eturn; } else if(buflen == 0) { // 这里表示对端的 socket 已正常关闭 . } if(buflen == sizeof(buf) rs = 1; // 需要再次读取 else rs = 0; } 还有,假如发送端流量大于接收端的流量 ( 意思是 epoll 所在的程序读比转发的 socket 要快 ), 由于是非阻塞的 socket, 那么 send() 函数虽然返回 , 但实际缓冲区的数据并未真正发给接收端 , 这样不断的读和发,当缓冲区满后会产生 EAGAIN 错误 ( 参考 man send), 同时 , 不理会这次请求发送的数据 . 所以 , 需要封装 socket_send()的函数用来处理这种情况 , 该函数会尽量将数据写完再返回,返回 -1 表示出错。在 socket_send() 内部 , 当写缓冲已满 (send() 返回 -1, 且 errno 为 EAGAIN), 那么会等待后再重试 . 这种方式并不很完美 , 在理论上可能会长时间的阻塞在 socket_send() 内部 , 但暂没有更好的办法 . ssize_t socket_send(int sockfd, const char* buffer, size_t buflen) { ssize_t tmp; size_t total = buflen; const char *p = buffer; while(1) { tmp = send(sockfd, p, total, 0); if(tmp < 0) { // 当 send 收到信号时 , 可以继续写 , 但这里返回 -1. if(errno == EINTR) return -1; // 当 socket 是非阻塞时 , 如返回此错误 , 表示写缓冲队列已满 , // 在这里做延时后再重试 . if(errno == EAGAIN) { usleep(1000); continue; } return -1; } if((size_t)tmp == total) return buflen; total -= tmp; p += tmp; } return tmp; } 代码: #include <iostream> #include <sys/socket.h> #include <sys/epoll.h> #include <netinet/in.h> #include <arpa/inet.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> #include <pthread.h> #include <errno.h> #define MAXLINE 10 #define OPEN_MAX 100 #define LISTENQ 20 #define SERV_PORT 5555 #define INFTIM 1000 // 线程池任务队列结构体 struct task { int fd; // 需要读写的文件描述符 struct task *next; // 下一个任务 }; // 用于读写两个的两个方面传递参数 struct user_data { int fd; unsigned int n_size;   |