网络编程epoll遇到问题

Phoenix_FuliMa 2013-04-12 11:35:19
使用epoll模型,但是使用accept接受的文件描述符不停的增加,知道达到系统的是限制,就会出现too many open files, 我使用close函数关闭了打开的socket描述符,但是在进程目录中还是存在,所以打开的文件描述符数量一致增加。
请问是什么原因,有没有什么解决办法?

网络后台模型
使用epoll监听端口,如果有新的链接,那么就监听这个新链接上的。
一般这个链接需要保持大概20秒钟,可能同时保持有5-6链接,
处理完毕之后客户端关闭链接,服务器端检测到关闭之后也调用close关闭链接。

但是遇到的问题就是accept接收的文件描述符不停的增加,有很多。

查看进程打开的文件描述符结果都是如下图所示


查看进程目录下面的内容如下, 这些链接都是丢失的,
...全文
268 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
qq120848369 2013-04-12
  • 打赏
  • 举报
回复
说错, 是看下不是FD泄漏的话,就优化一下TCP参数(百度就知道),对短连接优化效果明显,4倍的效果。 fd泄漏直接打印fd的数值就知道了,如果一直涨不降就是泄露。
Phoenix_FuliMa 2013-04-12
  • 打赏
  • 举报
回复
引用 2 楼 qq120848369 的回复:
不是内存泄漏的话优化一下TCP参数把。
如何优化,我看下不是内存泄露,就是打开的文件描述符没有关闭啊
qq120848369 2013-04-12
  • 打赏
  • 举报
回复
不是内存泄漏的话优化一下TCP参数把。
Phoenix_FuliMa 2013-04-12
  • 打赏
  • 举报
回复
部分代码:


static void RecvJsonMessage(int epfd, ServerType ServerSocket, ClientSetType &ClientSet,
	int nfds, struct epoll_event* events)
{
	int Ret = 0;
	char RecvBuffer[256] = {0};

	int connfd;	//客户端网络文件描述符.
	int sockfd;

	struct sockaddr_in clientaddr;
	socklen_t clilen;
	struct epoll_event ev;

	for(int i = 0; i < nfds; ++i)
	{
		if(events[i].data.fd == ServerSocket.ServerSocket)//如果新监测到一个SOCKET用户连接到了绑定的SOCKET端口,建立新的连接。
		{
			clilen = sizeof(clientaddr);
			connfd = accept(ServerSocket.ServerSocket,(struct sockaddr *)&clientaddr, &clilen);
			if(connfd<0)
			{
				if(errno == EINTR)
				{
					continue;
				}
				else
				{
					perror("Accept errno: connfd<0");
				}
				exit(-1);
			}

			/* Avoid TIME_WAIT */
			struct linger linger;
			linger.l_onoff = 1;
			linger.l_linger = 0;
			setsockopt(connfd, SOL_SOCKET, SO_LINGER, (const char *) &linger, sizeof(linger));

			char *str = inet_ntoa(clientaddr.sin_addr);
			cout<<"Accept a Connect form "<<str<<", Sockfd is "<<connfd<<endl;
			//设置用于读操作的文件描述符

			ev.data.fd=connfd;
			//设置用于注测的读操作事件

			//ev.events=EPOLLIN|EPOLLET;
			ev.events= EPOLLIN | EPOLLET |  EPOLLERR | EPOLLHUP | EPOLLPRI;

			//注册ev
			epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev);

			/* 初始化每个套接字描述符对应的结构体 */
			ClientSet[connfd] = new ClientSocketInfo;
			ClientSet[connfd]->sockfd = connfd;
			ClientSet[connfd]->brace_num = 0;
			ClientSet[connfd]->jsonbuffer = (char*) malloc( 1024*1024);
			ClientSet[connfd]->buffersize = 1024 *1024;
			memset(ClientSet[connfd]->jsonbuffer,0, 1024*1024);

		}
		else if(events[i].events & EPOLLIN)//如果是已经连接的用户,并且收到数据,那么进行读入。
		{
			if ( (sockfd = events[i].data.fd) < 0)
				continue;
			memset(RecvBuffer, 0, sizeof(RecvBuffer));
			Ret = recv(sockfd, RecvBuffer, sizeof(RecvBuffer) - 1, 0);

			if(Ret > 0)
			{
				/* 首先判断客户端缓冲区的大小,
				如果缓冲区不够,则重新分配 */
				if( ClientSet[sockfd]->buffersize 
					<((int)strlen(ClientSet[sockfd]->jsonbuffer) + Ret))
				{
					ClientSet[sockfd]->jsonbuffer = 
						(char*) realloc(ClientSet[sockfd]->jsonbuffer,
						ClientSet[sockfd]->buffersize + 1024 *1024);
					ClientSet[sockfd]->buffersize += 1024*1024;
				}

				strcat(ClientSet[sockfd]->jsonbuffer, RecvBuffer);

				/* 检测json数据包的合法性 */
				IsJsonFormatIllegal(ClientSet[sockfd]);

				if(ClientSet[sockfd]->brace_num == 0)
				{
					/* 将接受的json数据包放入到接受队列中 */
					InsertIntoJsonObj(ClientSet[sockfd], recvque);
				}
				else if(ClientSet[sockfd]->brace_num < 0)
				{
					/*出错,将将缓冲区清空 */
					memset(ClientSet[sockfd]->jsonbuffer, 0,
						ClientSet[sockfd]->buffersize);
				}
				else 
				{
					/* 继续等待一下个数据包 */
				}
			}
			//else if ( Ret < 0) 
			//{
			//	if (errno == ECONNRESET) {
			//		close(sockfd);
			//		events[i].data.fd = -1;
			//	} else
			//	{
			//		std::cout<<"readline error"<<std::endl;
			//	}
			//} 
			else if (Ret <= 0) 
			{
				cout<<"One Client Is Closed! Sockfd is "<<sockfd<<endl;

				ev.data.fd=sockfd;
				ev.events= EPOLLIN | EPOLLET |  EPOLLERR | EPOLLHUP | EPOLLPRI;
				epoll_ctl(epfd,EPOLL_CTL_DEL,sockfd,&ev);
				
				if(close(sockfd)== -1)
				{
					cout<<"close error, errno: "<<errno<<endl;
				}
				shutdown(connfd, 2);
				events[i].data.fd = -1;

				free(ClientSet[sockfd]->jsonbuffer);
				delete ClientSet[sockfd];
				ClientSet.erase(sockfd);
			}
		}
		else if(events[i].events & EPOLLOUT) 
		{

		}
		else
		{
			if ( (sockfd = events[i].data.fd) < 0)
				continue;
			ev.data.fd = sockfd;  
			epoll_ctl(epfd, EPOLL_CTL_DEL, sockfd, &ev);  
			close(sockfd);  
		}
	}
}

static void SendJsonMessage()
{
	if(sendque.empty())
	{
		return;
	}

	/* 从发送队列中寻找对应的描述符 */
	pthread_mutex_lock(&g_sendqueue_lock);
	for(list<Value>::iterator iter = sendque.begin(); iter != sendque.end(); iter++)
	{
		int sockfd = (*iter)["sockfd"].asInt();
		if(sockfd < 0)
		{
			continue;
		}
		string msg = (*iter)["sendcontent"].asString();

		int num = send(sockfd, msg.c_str(), (int)msg.length(), 0);

		if(num == (int)msg.length())
		{
			list<Value>::iterator tempiter = iter;
			iter++;
			sendque.erase(tempiter);
		}
		else if(num < 0)
		{
			DebugPrintf("Send Error: %s\n", msg.c_str());
			list<Value>::iterator tempiter = iter;
			iter++;
			sendque.erase(tempiter);
		}
	}		
	pthread_mutex_unlock(&g_sendqueue_lock);
}

SocketCon::SocketCon()
{

}

SocketCon::~SocketCon()
{

#ifdef WIN32
	closesocket(ServerSocket.ServerSocket);
	WSACleanup();
#else
	close((int)ServerSocket.ServerSocket);
#endif

}

int SocketCon::InitialSocketCon()
{
	int opt = 1;
#ifdef WIN32
	WSADATA  Ws;
	if(WSAStartup(MAKEWORD(2,2), &Ws) != 0)
	{
		cout<<"Init windows socket failed"<<GetLastError()<<endl;
	}
#endif 

	ServerSocket.ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if(ServerSocket.ServerSocket < 0)
	{
		cout<<"Create socket failed"<<endl;
	}
	setsockopt(ServerSocket.ServerSocket , SOL_SOCKET, SO_REUSEADDR, (const void*)&opt, sizeof(opt));  

	MakeSocketNonblocking(ServerSocket);

	this->epfd=epoll_create(256);

	struct epoll_event ev;
	ev.data.fd = ServerSocket.ServerSocket;
	ev.events = EPOLLIN;

	epoll_ctl(epfd,EPOLL_CTL_ADD,ServerSocket.ServerSocket,&ev);

	/************************************************************/
	int   Ret = 0;
	maxm = -1;

	/* 将客户端套接字描述符集合设置为负数 */
	for(int m = 0; m < FD_SETSIZE; m++)
	{
		client[m] = -1;
	}

	/* 设置非阻塞模式 */
	tv.tv_usec = 0;
	tv.tv_usec = 0;

	/* 清除接收缓冲区 */
	memset(RecvBuffer, 0, 256);

	LocalAddr.sin_family			= AF_INET;
#ifdef WIN32
	LocalAddr.sin_addr.S_un.S_addr	= inet_addr(IP_ADDRESS);
#else
	LocalAddr.sin_addr.s_addr       = inet_addr(IP_ADDRESS);
#endif
	LocalAddr.sin_port				= htons(PORT);
	memset(LocalAddr.sin_zero, 0x00, 8);

	Ret = bind(ServerSocket.ServerSocket, 
		(struct sockaddr*)&LocalAddr, sizeof(LocalAddr));
	if(Ret != 0)
	{
		cout<<"Bind socket failed"<<endl;
		return -1;
	}

	Ret = listen(ServerSocket.ServerSocket, ListenNq);
	if(Ret != 0)
	{
		cout<<"listen socket failed"<<endl;
		return -1;
	}

	cout<<"server start...."<<endl;

	return 0;
}

void SocketCon::RecvAndSend()
{
	int nfds = 0;
	//等待epoll事件的发生
	nfds=epoll_wait(epfd,events,20,500);
	if(nfds > 0)
	{
		/* 接受消息, 将json数据包放入到recvque中 */
		RecvJsonMessage(this->epfd, ServerSocket, ClientSet, nfds,events);

		/* 将信息发送出去 */
		/*SendJsonMessage(*this, fdwrite, client, &maxm);*/
	}
	SendJsonMessage();

}

Phoenix_FuliMa 2013-04-12
  • 打赏
  • 举报
回复
Phoenix_FuliMa 2013-04-12
  • 打赏
  • 举报
回复
Phoenix_FuliMa 2013-04-12
  • 打赏
  • 举报
回复
引用 6 楼 qq120848369 的回复:
你不close能不泄露吗... 找bug呗
呜呜。。。我肯定是close了啊。。。但是close木有用啊。。。代码里面不是写了close函数了啊。。呜呜呜。。
qq120848369 2013-04-12
  • 打赏
  • 举报
回复
你不close能不泄露吗... 找bug呗
Phoenix_FuliMa 2013-04-12
  • 打赏
  • 举报
回复
引用 4 楼 qq120848369 的回复:
说错, 是看下不是FD泄漏的话,就优化一下TCP参数(百度就知道),对短连接优化效果明显,4倍的效果。 fd泄漏直接打印fd的数值就知道了,如果一直涨不降就是泄露。
我现在也是确认是fd泄露了,但是找不到原因呢?您看代码有问题吗?一些参数例如so_linger我都设置了啊

64,683

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧