欢迎来到别爱的CSDN
文章目录前言一、服务器端代码二、客户端代码总结参考资料
前言
具体内容看上一篇,这篇主要是代码的改进。
链接地址: 实现TCP服务器
#include二、客户端代码#include #include #include #include #include #include #include #include #define BUFFER_LENGTH 1024 #define EPOLL_SIZE 1024 #define MAX_PORT 100 void *client_routine(void *arg) { int clientfd = *(int *)arg; while (1) { char buffer[BUFFER_LENGTH] = {0}; int len = recv(clientfd, buffer, BUFFER_LENGTH, 0); if (len < 0) { close(clientfd); break; } else if (len == 0) { // disconnect close(clientfd); break; } else { printf("Recv: %s, %d byte(s)n", buffer, len); } } } int islistenfd(int fd, int *fds) { int i = 0; for (i = 0;i < MAX_PORT;i ++) { if (fd == *(fds+i)) return fd; } return 0; } // ./tcp_server int main(int argc, char *argv[]) { if (argc < 2) { printf("Param Errorn"); return -1; } int port = atoi(argv[1]); // start int sockfds[MAX_PORT] = {0}; // listen fd int epfd = epoll_create(1); int i = 0; for (i = 0;i < MAX_PORT;i ++) { int sockfd = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in addr; memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_family = AF_INET; addr.sin_port = htons(port+i); // 8888 8889 8890 8891 .... 8987 addr.sin_addr.s_addr = INADDR_ANY; if (bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) < 0) { perror("bind"); return 2; } if (listen(sockfd, 5) < 0) { perror("listen"); return 3; } printf("tcp server listen on port : %dn", port + i); struct epoll_event ev; ev.events = EPOLLIN; ev.data.fd = sockfd; epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev); sockfds[i] = sockfd; } // #if 0 while (1) { struct sockaddr_in client_addr; memset(&client_addr, 0, sizeof(struct sockaddr_in)); socklen_t client_len = sizeof(client_addr); int clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len); pthread_t thread_id; pthread_create(&thread_id, NULL, client_routine, &clientfd); } #else struct epoll_event events[EPOLL_SIZE] = {0}; while (1) { int nready = epoll_wait(epfd, events, EPOLL_SIZE, 5); // -1, 0, 5 if (nready == -1) continue; int i = 0; for (i = 0;i < nready;i ++) { int sockfd = islistenfd(events[i].data.fd, sockfds); if (sockfd) { // listen 2 struct sockaddr_in client_addr; memset(&client_addr, 0, sizeof(struct sockaddr_in)); socklen_t client_len = sizeof(client_addr); int clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len); fcntl(clientfd, F_SETFL, O_NONBLOCK); int reuse = 1; setsockopt(clientfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)); struct epoll_event ev; ev.events = EPOLLIN | EPOLLET; ev.data.fd = clientfd; epoll_ctl(epfd, EPOLL_CTL_ADD, clientfd, &ev); } else { int clientfd = events[i].data.fd; char buffer[BUFFER_LENGTH] = {0}; int len = recv(clientfd, buffer, BUFFER_LENGTH, 0); if (len < 0) { close(clientfd); struct epoll_event ev; ev.events = EPOLLIN; ev.data.fd = clientfd; epoll_ctl(epfd, EPOLL_CTL_DEL, clientfd, &ev); } else if (len == 0) { // disconnect close(clientfd); struct epoll_event ev; ev.events = EPOLLIN; ev.data.fd = clientfd; epoll_ctl(epfd, EPOLL_CTL_DEL, clientfd, &ev); } else { printf("Recv: %s, %d byte(s), clientfd: %dn", buffer, len, clientfd); } } } } #endif return 0; }
代码如下(示例):
#include#include #include #include #include #include #include #include #include #include #include #define MAX_BUFFER 128 #define MAX_EPOLLSIZE (384*1024) #define MAX_PORT 100 #define TIME_SUB_MS(tv1, tv2) ((tv1.tv_sec - tv2.tv_sec) * 1000 + (tv1.tv_usec - tv2.tv_usec) / 1000) int isContinue = 0; static int ntySetNonblock(int fd) { int flags; flags = fcntl(fd, F_GETFL, 0); if (flags < 0) return flags; flags |= O_NONBLOCK; if (fcntl(fd, F_SETFL, flags) < 0) return -1; return 0; } static int ntySetReUseAddr(int fd) { int reuse = 1; return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)); } int main(int argc, char **argv) { if (argc <= 2) { printf("Usage: %s ip portn", argv[0]); exit(0); } const char *ip = argv[1]; int port = atoi(argv[2]); int connections = 0; char buffer[128] = {0}; int i = 0, index = 0; struct epoll_event events[MAX_EPOLLSIZE]; int epoll_fd = epoll_create(MAX_EPOLLSIZE); strcpy(buffer, " Data From MulClientn"); struct sockaddr_in addr; memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr(ip); struct timeval tv_begin; gettimeofday(&tv_begin, NULL); while (1) { if (++index >= MAX_PORT) index = 0; struct epoll_event ev; int sockfd = 0; if (connections < 340000 && !isContinue) { sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd == -1) { perror("socket"); goto err; } //ntySetReUseAddr(sockfd); addr.sin_port = htons(port+index); if (connect(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) < 0) { perror("connect"); goto err; } ntySetNonblock(sockfd); ntySetReUseAddr(sockfd); sprintf(buffer, "Hello Server: client --> %dn", connections); send(sockfd, buffer, strlen(buffer), 0); ev.data.fd = sockfd; ev.events = EPOLLIN | EPOLLOUT; epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sockfd, &ev); connections ++; } //connections ++; if (connections % 1000 == 999 || connections >= 340000) { struct timeval tv_cur; memcpy(&tv_cur, &tv_begin, sizeof(struct timeval)); gettimeofday(&tv_begin, NULL); int time_used = TIME_SUB_MS(tv_begin, tv_cur); printf("connections: %d, sockfd:%d, time_used:%dn", connections, sockfd, time_used); int nfds = epoll_wait(epoll_fd, events, connections, 100); for (i = 0;i < nfds;i ++) { int clientfd = events[i].data.fd; if (events[i].events & EPOLLOUT) { sprintf(buffer, "data from %dn", clientfd); send(sockfd, buffer, strlen(buffer), 0); } else if (events[i].events & EPOLLIN) { char rBuffer[MAX_BUFFER] = {0}; ssize_t length = recv(sockfd, rBuffer, MAX_BUFFER, 0); if (length > 0) { printf(" RecvBuffer:%sn", rBuffer); if (!strcmp(rBuffer, "quit")) { isContinue = 0; } } else if (length == 0) { printf(" Disconnect clientfd:%dn", clientfd); connections --; close(clientfd); } else { if (errno == EINTR) continue; printf(" Error clientfd:%d, errno:%dn", clientfd, errno); close(clientfd); } } else { printf(" clientfd:%d, errno:%dn", clientfd, errno); close(clientfd); } } } usleep(1 * 1000); } return 0; err: printf("error : %sn", strerror(errno)); return 0; }
总结
今天主要就是实现这些功能了,可以让服务器的运行量更大。
参考资料C/C++ Linux高级开发课程



