我用Epoll写的socket服务器,持续接受数据经常接收错误的数据,各位大神帮忙解决一下!有好用的实例给发一个yushadow@126.com

yushadow 发布于 2013/09/16 17:23
阅读 1K+
收藏 1
#include "test.h"


int iEpollfd = 0;
struct epoll_event Epoll_ev;
struct epoll_event Epoll_events[EPOLLMAXNUM];

int main()
{
	int iRetvalue = 0;


	while(TRUE)
	{
		iRetvalue = server_init(); 
		if(0 > iRetvalue)
		{
			sleep(3);
		}

		continue;
	}
	

	return 0;
}

static int server_init()
{
	int iRetvalue = 0;
	int iServerfd = 0;
	int iClientfd = 0;
	int iRetfds   = 0;
	int i;
	char recvbuf[1024] = "\0";

	struct sockaddr_in Clientaddr;
	socklen_t socklen = sizeof(struct sockaddr_in);
	memset(&Clientaddr, 0, sizeof(Clientaddr));

	iServerfd = socket_init();
	if(0 > iServerfd)
	{
		printf("socket init error\n");
		return -1;
	}

	int iCount = 0;

	while(TRUE)
	{
		iRetfds = epoll_wait(iEpollfd, Epoll_events, EPOLLMAXNUM, 0);
		for(i = 0; i < iRetfds; i++)
		{
			if(0 > (iClientfd == Epoll_events[i].data.fd)) continue;
			if(iServerfd == Epoll_events[i].data.fd)
			{
				iClientfd = accept(iServerfd, (struct sockaddr*)&Clientaddr, &socklen);
				if(0 > iClientfd)
				{
					iRetvalue = errno;
					printf("[%s][%s][%d]:accept error:%s\n", __FILE__, __func__, __LINE__, strerror(errno));
					break;
				}
				printf("客户端[ %d ]连接成功\n", iClientfd);

				socket_setnonblock(iClientfd);    

				Epoll_ev.data.fd = iClientfd;                            //设置与处理事件相关的描述符
				Epoll_ev.events  = EPOLLIN|EPOLLET;                              //设置要处理的事件类型
				epoll_ctl(iEpollfd, EPOLL_CTL_ADD, iClientfd, &Epoll_ev);  //注册epoll事件

				continue;
			}//end if

			if(Epoll_events[i].events&EPOLLIN)
			{
				iClientfd = Epoll_events[i].data.fd;
				//printf("iClientfd = %d\n", Epoll_events[i].data.fd);
				int iTotallen = 0;
				int iOnce = 0;
				do
				{
					/*
					iOnce = recv(iClientfd, &iTotallen, 4, 0);
					if(4 != iOnce)
					{
						printf("接收长度错误!\n");
						break;
					}
					printf("------------长度: %d\n", iTotallen);
*/
					memset(&recvbuf, 0, sizeof(recvbuf));
					//iOnce = recv(iClientfd, recvbuf, iTotallen, 0);
					iOnce = recv(iClientfd, recvbuf, 1024, 0);
					if(iOnce != 621)
					{
						printf("接收错误");
						break;
					}

					//printf("%s:socket:%d\n",recvbuf,iClientfd);
					iCount++;
					printf("iCount = %d\n", iCount);
				}
				while(0);

				Epoll_ev.data.fd = iClientfd;                            //设置与处理事件相关的描述符
				Epoll_ev.events  = EPOLLIN|EPOLLET;                       //设置要处理的事件类型
				epoll_ctl(iEpollfd, EPOLL_CTL_ADD, iClientfd, &Epoll_ev);  //注册epoll事件
			}// end if
		}//end for
	}//end while

	close(iServerfd);
	return 0;
}


static int socket_init()
{
	int iRetvalue = 0;

	int iSockfd = 0;
	struct sockaddr_in Serveraddr;
	socklen_t socklen = sizeof(struct sockaddr_in);

	memset(&Serveraddr, 0, sizeof(Serveraddr));
	Serveraddr.sin_family = AF_INET;
	Serveraddr.sin_port   = htons(SERVER_PORT);
	Serveraddr.sin_addr.s_addr = htonl(SERVER_ADDR); 

	iSockfd = socket(AF_INET, SOCK_STREAM, 0);
	if(0 > iSockfd)
	{
		printf("create socket error\n");
		return -1;
	}

	iEpollfd = epoll_create(EPOLLMAXNUM);
	if(0 > iEpollfd)
	{
		printf("create epoll error\n");
		close(iSockfd);
		return -1;
	}

	Epoll_ev.data.fd = iSockfd;                            //设置与处理事件相关的描述符
	Epoll_ev.events  = EPOLLIN|EPOLLET;                              //设置要处理的事件类型
	epoll_ctl(iEpollfd, EPOLL_CTL_ADD, iSockfd, &Epoll_ev);  //注册epoll事件


	iRetvalue = socket_setnonblock(iSockfd);       //把socket设置为非阻塞,epoll的边缘出发模式需要。
	if(iRetvalue)
	{
		printf("[%s][%s][%d]:设置非阻塞模式失败%s\n", __FILE__, __func__, __LINE__, strerror(errno));
		close(iSockfd);
		return -1;
	}

	iRetvalue = bind(iSockfd, (struct sockaddr *)&Serveraddr, socklen);
	if(iRetvalue)
	{
		printf("[%s][%s][%d]:bind error: %s\n", __FILE__, __func__, __LINE__, strerror(errno));
		close(iSockfd);
		return -1;
	}

	iRetvalue = listen(iSockfd, LISTENQ);
	if(iRetvalue)
	{
		printf("[%s][%s][%d]:listen error: %s\n", __FILE__, __func__, __LINE__, strerror(errno));
		close(iSockfd);
		return -1;
	}

	printf("监听socket成功 : %d\n", iSockfd);
	printf("请耐心等待连接.......\n");

	return iSockfd;
}

static int socket_setnonblock(int iSockfd)
{
	int iOpts = fcntl(iSockfd, F_GETFL);  //得到原有的句柄属性
	if(iOpts < 0)
	{
#ifdef PRINT
		printf("[%s][%s][%d]:fcntl error: %s\n", __FILE__, __func__, __LINE__, strerror(errno));
#endif
		return -1;
	}

	iOpts = iOpts|O_NONBLOCK;             //在原有属性的基础上添加非阻塞属性
	if(fcntl(iSockfd, F_SETFL, iOpts)<0)
	{
#ifdef PRINT
		printf("[%s][%s][%d]: fcntl error: %s\n", __FILE__, __func__, __LINE__, strerror(errno));
#endif
		return -1;
	}

	return 0;
}

以下是问题补充:

@yushadow:哪位大神有好用的实例给发一个呗,邮箱yushadow@126.com (2013/09/16 18:58)
加载中
0
星爷
星爷
目测没有TCP消息的编解码处理。
星爷
星爷
@yushadow 是tcp的数据包有大小的,你需要将数据包和起来或者拆分
yushadow
yushadow
编解码? 应该不用解码处理吧?我发送和接受的都是用统一utf8编码格式。
0
玛雅牛
玛雅牛
楼上说得对,TCP是流式协议,需要自己处理分片,一般要用ring(环形数组)来暂存已经收到的数据。
yushadow
yushadow
回复 @玛雅牛 : 这个我也做处理了,如果一次读不完,会循环读多次。问题是很多时候收取到的那4个字节用来表示长度的,跟实际发送的长度不一样。
玛雅牛
玛雅牛
没有实例。
玛雅牛
玛雅牛
你说的4个字节长度的头其实就是编解码处理。如果这个长度比较长的话,不一定一次就可以读完,可能需要多次才能读完。
yushadow
yushadow
请问有没有实例啊,给发一个呗?邮箱yushadow@126.com
yushadow
yushadow
这只是一个测试代码,真正用的时候回在每条数据前面加上4个字节的当前数据长度,我先接收4个字节,解析出长度,然后再接收那个长度的数据。结果还是一样的,
返回顶部
顶部