- 论坛徽章:
- 0
|
本帖最后由 xtchina 于 2013-03-26 11:18 编辑
问题已解决,自己粗心造成
1.为什么用EPOLL_CTL_ADD加入到epoll中的socket会无声无息的消失了?
2.为什么用EPOLL_CTL_DEL删除从epoll_wait中返回的句柄会出现bad file descriptor错误?
3.为什么已经加入到epoll中的sock连接中断,却没有从epoll中得到任何提示?
4.为什么我的socket句柄还没有调用close,系统就把它分配给别的连接用了?
撇开效率不谈,我的代码**问题?网上找了好几周了,实在解决不了,还望高手能够帮忙看看,不胜感激!
- #include <sys/types.h>
- #include <sys/mman.h>
- #include <sys/resource.h>
- #include <stdio.h>
- #include <errno.h>
- #include <unistd.h>
- #include <string.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <assert.h>
- #include <pthread.h>
- #include <netinet/tcp.h>
- #include <sys/epoll.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- bool woking = true;
- unsigned short server_port = 9001;
- const char* server_ip = "127.0.0.1";
- int wait_epevent_num = 4096;
- int ep_client = -1;
- int ep_server = -1;
- int buffer_size = 4096;
- double server_recv_size = 0.0d;
- double server_send_size = 0.0d;
- double client_recv_size = 0.0d;
- double client_send_size = 0.0d;
- unsigned int server_inepoll_sock = 0;
- unsigned int server_outepoll_sock = 0;
- unsigned int client_inepoll_sock = 0;
- unsigned int client_outepoll_sock = 0;
- struct epitem
- {
- int sock;
- unsigned short local_port;
- unsigned short remote_port;
- unsigned int send_data_size;
- unsigned int recv_data_size;
- };
- // 获取本端端口
- unsigned short get_sock_local_port(int sock)
- {
- unsigned short local_port = 0;
- sockaddr_in addr;
- socklen_t nl = sizeof(addr);
- if (0 == getsockname(sock, (sockaddr*)&addr, &nl))
- {
- local_port = ntohs(addr.sin_port);
- }
- return local_port;
- }
- // 获取远端端口
- unsigned short get_sock_remote_port(int sock)
- {
- unsigned short remote_port = 0;
- sockaddr_in addr;
- socklen_t nl = sizeof(addr);
- if (0 == getpeername(sock, (sockaddr*)&addr, &nl))
- {
- remote_port = ntohs(addr.sin_port);
- }
- return remote_port;
- }
- // 投入到epoll中
- bool putinto_epoll(int epoll, int sock)
- {
- if (0 != fcntl(sock, F_SETFL
- , fcntl(sock, F_GETFL, 0)|O_NONBLOCK))
- {
- return false;
- }
- epitem* newitem = new epitem;
- if (0 == newitem)
- {
- return false;
- }
- newitem->sock = sock;
- newitem->local_port = get_sock_local_port(sock);
- newitem->remote_port = get_sock_remote_port(sock);
- newitem->send_data_size = 0;
- newitem->recv_data_size = 0;
- epoll_event eevent;
- eevent.data.ptr = newitem;
- eevent.events = EPOLLIN | EPOLLOUT;
- if (0 != epoll_ctl(epoll, EPOLL_CTL_ADD, sock, &eevent))
- {
- printf("epoll_ctl call failed [%d:%s]...\r\n", errno, strerror(errno));
- delete newitem;
- return false;
- }
- // 33%的概率关掉一些刚刚投入到epoll中的sock,仅仅是测试需要
- if (rand() % 3 == 0)
- {
- close(sock);
- }
- return true;
- }
- // 连接线程,不停地进行连接
- void* thread_connect(void* param)
- {
- printf("begin thread connect...\r\n");
- sockaddr_in server_addr;
- memset(&server_addr, 0, sizeof(sockaddr_in));
- server_addr.sin_family = AF_INET;
- server_addr.sin_addr.s_addr = inet_addr(server_ip);
- server_addr.sin_port = htons(server_port);
- while(woking)
- {
- int new_client_sock = -1;
- new_client_sock = socket(PF_INET, SOCK_STREAM, 0);
- if (-1 == new_client_sock)
- {
- sleep(1);
- continue;
- }
- if (0 != connect(new_client_sock, (sockaddr*)&server_addr
- , sizeof(sockaddr_in)))
- {
- goto fail;
- }
- // 放入epoll队列中
- if (!putinto_epoll(ep_client, new_client_sock))
- {
- goto fail;
- }
- client_inepoll_sock++;
- goto ok;
- fail:
- close(new_client_sock);
- //sleep(1);
- ok:
- ;
- }
- printf("end thread connect...\r\n");
- return 0;
- }
- // 接收线程,不停地接收客户端的连接
- void* thread_accept(void* param)
- {
- printf("begin thread accept...\r\n");
- int listen_sock;
- sockaddr_in server_addr;
- listen_sock = socket(PF_INET, SOCK_STREAM, 0);
- if (-1 == listen_sock)
- {
- printf("end thread accept[%d:%s]...\r\n", errno, strerror(errno));
- return 0;
- }
- int reuseaddr = 1;
- if (0 != setsockopt(listen_sock, SOL_SOCKET
- , SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr) ))
- {
- printf("end thread accept[%d:%s]...\r\n", errno, strerror(errno));
- return 0;
- }
- memset(&server_addr, 0, sizeof(sockaddr_in));
- server_addr.sin_family = AF_INET;
- server_addr.sin_addr.s_addr = inet_addr(server_ip);
- server_addr.sin_port = htons(server_port);
- if (0 != bind(listen_sock, (sockaddr*)&server_addr, sizeof(server_addr)))
- {
- printf("end thread accept[%d:%s]...\r\n", errno, strerror(errno));
- return 0;
- }
- if (0 != fcntl(listen_sock, F_SETFL
- , fcntl(listen_sock, F_GETFL, 0) & ~O_NONBLOCK))
- {
- printf("end thread accept[%d:%s]...\r\n", errno, strerror(errno));
- return 0;
- }
- if (0 != listen(listen_sock, 32))
- {
- printf("end thread accept[%d:%s]...\r\n", errno, strerror(errno));
- return 0;
- }
- while(woking)
- {
- int new_accept_sock = -1;
- new_accept_sock = accept(listen_sock, 0, 0);
- if (-1 == new_accept_sock)
- {
- goto fail;
- }
- // 放入epoll队列中
- if (!putinto_epoll(ep_server, new_accept_sock))
- {
- goto fail;
- }
- server_inepoll_sock++;
- goto ok;
- fail:
- close(new_accept_sock);
- //sleep(1);
- ok:
- ;
- }
- printf("end thread accept...\r\n");
- return 0;
- }
- // epoll中的输入处理
- bool do_input(int sock, char* buffer, int buf_size, double& recv_size)
- {
- assert(buf_size > 0);
- assert(buffer != 0);
- for (int i=0; i<8; i++)
- {
- int recvlen = recv(sock, buffer, buf_size, 0);
- // return false; 如果这里返回为什么会有double free错误?
- recv_size += recvlen>0?recvlen:0;
- if (recvlen == 0)
- {
- return false;
- }
- else if (recvlen == -1)
- {
- if (errno == EAGAIN)
- {
- return true;
- }
- if (errno == EINTR)
- {
- continue;
- }
-
- return false;
- }
- else if (recvlen == buf_size)
- {
- continue;
- }
- else if (recvlen < buf_size)
- {
- assert(recvlen > 0);
- return true;
- }
- }
- // 有太多的数据时,返回false关闭连接
- return false;
- }
- // epoll中的输出处理
- bool do_output(int sock, char* buffer, int buf_size, double& send_size)
- {
- for (int i=0; i<4; i++)
- {
- int sendlen = send(sock, buffer, buf_size, 0);
- // return false; 如果这里返回为什么会有double free错误?
- send_size += sendlen>0?sendlen:0;
- if (sendlen == -1)
- {
- if (errno == EAGAIN)
- {
- return true;
- }
- if (errno == EINTR)
- {
- continue;
- }
- // 为什么有SIGPIPE信号,出错的连接我都关掉了
- return false;
- }
- else if (sendlen == buf_size)
- {
- continue;
- }
- else if (sendlen < buf_size)
- {
- assert(sendlen > 0);
- return true;
- }
- }
- return true;
- }
- void do_epoll(int epoll, epoll_event* wait_epevent, int wait_epevent_num
- , int wait_time, char* buffer, int buf_size
- , double& recv_size, double& send_size, unsigned int& out_sock_num)
- {
- int wait_num = epoll_wait(epoll, wait_epevent, wait_epevent_num, wait_time);
- for (int i=0; i<wait_num; i++)
- {
- epitem* sockitem = (epitem*)wait_epevent[i].data.ptr;
- if ( 0 != (wait_epevent[i].events & ~(EPOLLIN|EPOLLOUT)) )
- {
- // 非输入输出事件,全部关闭
- goto fail;
- }
- if ((wait_epevent[i].events & EPOLLIN)
- && !do_input(sockitem->sock, buffer, buf_size, recv_size))
- {
- // 输入事件处理失败
- goto fail;
- }
- {
- // 这里sock是有效的,为什么端口号会改变??
- unsigned short local_port = get_sock_local_port(sockitem->sock);
- assert((0 == local_port) || (local_port == sockitem->local_port));
- unsigned short remote_port = get_sock_remote_port(sockitem->sock);
- assert((0 == remote_port) || (remote_port == sockitem->remote_port));
- }
- if ((wait_epevent[i].events & EPOLLOUT)
- && !do_output(sockitem->sock, buffer, buf_size, send_size))
- {
- // 输出事件处理失败
- goto fail;
- }
-
- {
- // 这里sock是有效的,为什么端口号会改变??
- unsigned short local_port = get_sock_local_port(sockitem->sock);
- assert((0 == local_port) || (local_port == sockitem->local_port));
- unsigned short remote_port = get_sock_remote_port(sockitem->sock);
- assert((0 == remote_port) || (remote_port == sockitem->remote_port));
- }
- // 事件过多时,随机关闭一些连接,仅仅是测试需要
- if (rand()%5000 < (wait_num-1000))
- {
- goto fail;
- }
- goto ok;
- fail:
- if (0 != epoll_ctl(epoll, EPOLL_CTL_DEL, sockitem->sock, 0))
- {
- // 为什么会出现bad file descriptor?
- //pirntf("epoll_ctl failed.[%d:%s]\r\n", errno, strerror(errno));
- }
- close(sockitem->sock);
- delete sockitem;
- out_sock_num++;
- ok:
- ;
- }
- }
- // 服务器端epoll数据处理
- void* thread_server(void* param)
- {
- printf("begin thread server...\r\n");
- // 创建接收和发送数据的缓冲区,所有sock公用,数据随机
- char* buffer = new char[buffer_size];
- assert(0 != buffer);
- // epoll中等待事件
- epoll_event* wait_epevent = new epoll_event[wait_epevent_num];
- assert (wait_epevent != 0);
- while(woking)
- {
- do_epoll(ep_server, wait_epevent, wait_epevent_num, 1, buffer, buffer_size
- , server_recv_size, server_send_size, server_outepoll_sock);
- }
- printf("end thread server...\r\n");
- return 0;
- }
- // 客户端epoll数据处理
- void* thread_client(void* param)
- {
- printf("begin thread client...\r\n");
- // 创建接收和发送数据的缓冲区,所有sock公用,数据随机
- char* buffer = new char[buffer_size];
- assert(0 != buffer);
- // epoll中等待事件
- epoll_event* wait_epevent = new epoll_event[wait_epevent_num];
- assert (wait_epevent != 0);
- while(woking)
- {
- do_epoll(ep_client, wait_epevent, wait_epevent_num, 1, buffer, buffer_size
- , client_recv_size, client_send_size, client_outepoll_sock);
- }
- delete[] buffer;
- delete[] wait_epevent;
- printf("end thread client...\r\n");
- return 0;
- }
- int main()
- {
- rlimit rlim;
- if (0 == getrlimit(RLIMIT_NOFILE, &rlim))
- {
- rlim.rlim_cur = rlim.rlim_max;
- setrlimit(RLIMIT_NOFILE , &rlim);
- }
- // 创建服务器端epoll
- ep_server = epoll_create(4096);
- assert(ep_server != -1);
- // 创建客户端端epoll
- ep_client = epoll_create(4096);
- assert (ep_client != -1);
- pthread_t thread_id_connect;
- pthread_t thread_id_accept;
- pthread_t thread_id_client;
- pthread_t thread_id_server;
- woking = true;
- // 服务器处理线程
- if (0 != pthread_create(&thread_id_server, 0, thread_server, 0))
- {
- return 0;
- }
- // 客户端处理线程
- if (0 != pthread_create(&thread_id_client, 0, thread_client, 0))
- {
- return 0;
- }
- // 连接监听线程
- if (0 != pthread_create(&thread_id_accept, 0, thread_accept, 0))
- {
- return 0;
- }
- // 建立连接线程
- if (0 != pthread_create(&thread_id_connect, 0, thread_connect, 0))
- {
- return 0;
- }
- printf("begin epoll test...\r\n");
- while (1)
- {
- // 打印一些统计信息,连接数和收发数据速度
- // 连接数为什么不对?
- printf("s[%d:%f:%f] c[%d:%f:%f]\r\n"
- ,(server_inepoll_sock-server_outepoll_sock)
- , server_recv_size/1024/1024, server_send_size/1024/1024
- ,(client_inepoll_sock-client_outepoll_sock)
- , client_recv_size/1024/1024, client_send_size/1024/1024);
- server_recv_size = 0.0d;
- server_send_size = 0.0d;
- client_recv_size = 0.0d;
- client_send_size = 0.0d;
- sleep(1);
- }
- sleep(-1);
- woking = false;
- close(ep_server);
- close(ep_client);
- pthread_join(thread_id_connect, 0);
- pthread_join(thread_id_accept, 0);
- pthread_join(thread_id_client, 0);
- pthread_join(thread_id_server, 0);
- printf("end epoll test...\r\n");
- return 0;
- }
复制代码 |
|