静态网页模板免费下载的网站,网站没备案可以做商城吗,濮阳市网站建设,东莞加工厂外发网一请求一线程
问题
当客户端数量较多时#xff0c;使用单独线程为每个客户端处理请求可能导致系统资源的消耗过大和性能瓶颈。
资源消耗#xff1a;
线程创建和管理开销#xff1a;每个线程都有其创建和销毁的开销#xff0c;特别是在高并发环境中#xff0c;这种开销…一请求一线程
问题
当客户端数量较多时使用单独线程为每个客户端处理请求可能导致系统资源的消耗过大和性能瓶颈。
资源消耗
线程创建和管理开销每个线程都有其创建和销毁的开销特别是在高并发环境中这种开销会显著增加。内存消耗每个线程通常需要分配一定的栈空间这会增加内存使用量。上下文切换操作系统需要频繁地切换线程上下文这会消耗CPU资源。
性能瓶颈
线程竞争大量线程会导致线程之间竞争共享资源如内存和CPU时间降低整体性能。调度开销操作系统调度大量线程时的开销可能会影响应用程序的响应时间和吞吐量。
#include stdio.h
#include string.h
#include stdlib.h
#include libgen.h
#include sys/socket.h
#include sys/types.h
#include netinet/in.h
#include arpa/inet.h
#include pthread.h
#include errno.h
#include unistd.h#define BUFFER_LENGTH 1024// 客户端处理线程的例程
void *client_routine(void* arg) {int clientfd *(int*)arg; // 获取传入的客户端套接字描述符while (1) {char buffer[BUFFER_LENGTH]; // 定义接收缓冲区int len recv(clientfd, buffer, BUFFER_LENGTH, 0); // 接收数据if (len 0) {// 接收数据出错perror(recv error);close(clientfd); // 关闭客户端套接字break;} else if (len 0) {// 客户端关闭连接close(clientfd); // 关闭客户端套接字break;} else {// 打印接收到的数据printf(Recv: %s, %d byte(s)\n, buffer, len);}}return NULL;
}int main(int argc, char* argv[]) {if (argc 2) {// 参数错误未提供端口号printf(usage: %s port\n, basename(argv[0]));return -1;}int port atoi(argv[1]); // 从命令行参数获取端口号// 创建监听用的套接字int sockfd socket(AF_INET, SOCK_STREAM, 0);if (sockfd 0) {perror(socket creation failed);return 1;}// 配置套接字地址struct sockaddr_in addr;memset(addr, 0, sizeof(struct sockaddr_in)); // 清空地址结构addr.sin_family AF_INET;addr.sin_port htons(port); // 转换端口号为网络字节序addr.sin_addr.s_addr INADDR_ANY; // 绑定到所有可用的接口if (bind(sockfd, (struct sockaddr*)addr, sizeof(struct sockaddr_in))) {perror(bind failed);return 2;}if (listen(sockfd, 5) 0) {perror(listen failed);return 3;}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);if (clientfd 0) {perror(accept failed);continue;}// 为每个客户端创建一个线程pthread_t thread_id;if (pthread_create(thread_id, NULL, client_routine, clientfd) ! 0) {perror(pthread_create failed);close(clientfd); // 创建线程失败时关闭客户端套接字}// 可选分离线程以避免线程资源泄漏pthread_detach(thread_id);}// 关闭监听套接字实际上这部分代码永远不会到达close(sockfd);return 0;
}使用ifconfig查看服务器程序所在主机的IP地址。 首先启动所写的tcp服务器即确保tcp_server_test.cpp已经编译并运行在虚拟机上监听指定的端口8888。
打开三个网络调试助手NetAssist在每个助手中配置远端主机地址为你的tcp服务器地址在虚拟机用ifconfig查看端口设置为 8888点击连接。可以分别向tcp服务器写数据。 利用epoll
优点
高效
epoll采用事件驱动的方式仅在有事件发生时通知应用程序避免了轮询带来的性能开销。
可扩展性
能够处理大量的文件描述符适合高并发应用。
边缘触发
支持边缘触发EPOLLET在数据到达时通知一次适合需要高效处理大量事件的场景。
缺点
复杂性
编程模型较为复杂需要正确处理事件并维持数据流动性可能导致代码较难维护。
资源消耗
虽然epoll高效但在高负载情况下资源使用仍然会增加如内存和系统调用次数。
边缘触发处理
需要确保处理所有数据否则可能错过事件增加了编程的复杂性。
#include stdio.h
#include string.h
#include stdlib.h
#include libgen.h
#include sys/socket.h
#include sys/types.h
#include netinet/in.h
#include arpa/inet.h
#include errno.h
#include unistd.h
#include sys/epoll.h#define BUFFER_LENGTH 1024
#define EPOLL_SIZE 1024int main(int argc, char* argv[]) {if (argc 2) {// 参数错误未提供端口号printf(usage: %s port\n, basename(argv[0]));return -1;}int port atoi(argv[1]); // 从命令行参数获取端口号// 创建监听用的套接字int sockfd socket(AF_INET, SOCK_STREAM, 0);if (sockfd 0) {perror(socket creation failed);return 1;}// 配置套接字地址struct sockaddr_in addr;memset(addr, 0, sizeof(struct sockaddr_in)); // 清空地址结构addr.sin_family AF_INET;addr.sin_port htons(port); // 转换端口号为网络字节序addr.sin_addr.s_addr INADDR_ANY; // 绑定到所有可用的接口if (bind(sockfd, (struct sockaddr*)addr, sizeof(struct sockaddr_in))) {perror(bind failed);close(sockfd);return 2;}if (listen(sockfd, 5) 0) {perror(listen failed);close(sockfd);return 3;}// 创建 epoll 实例int epfd epoll_create1(0); // 使用 epoll_create1(0) 代替 epoll_create(0)if (epfd 0) {perror(epoll_create failed);close(sockfd);return 4;}struct epoll_event events[EPOLL_SIZE] {0};// 添加监听套接字到 epoll 实例struct epoll_event ev;ev.events EPOLLIN | EPOLLET; // 设置为边缘触发模式ev.data.fd sockfd;if (epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, ev) 0) {perror(epoll_ctl failed);close(sockfd);close(epfd);return 5;}while (1) {// 等待事件发生int nready epoll_wait(epfd, events, EPOLL_SIZE, -1);if (nready 0) {perror(epoll_wait failed);break; // 退出循环}for (int i 0; i nready; i) {if (events[i].data.fd sockfd) {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);if (clientfd 0) {perror(accept failed);continue;}// 将新的客户端套接字添加到 epoll 实例中并设置为边缘触发模式ev.events EPOLLIN | EPOLLET;ev.data.fd clientfd;if (epoll_ctl(epfd, EPOLL_CTL_ADD, clientfd, ev) 0) {perror(epoll_ctl failed);close(clientfd);}} else {// 处理客户端套接字的事件int clientfd events[i].data.fd;char buffer[BUFFER_LENGTH]; // 定义接收缓冲区int len;// 处理所有可用的数据while ((len recv(clientfd, buffer, BUFFER_LENGTH, 0)) 0) {buffer[len] \0; // 添加字符串结束标志printf(Recv: %s, %d byte(s)\n, buffer, len);}if (len 0) {perror(recv error);}// 客户端关闭连接或出错close(clientfd); // 关闭客户端套接字epoll_ctl(epfd, EPOLL_CTL_DEL, clientfd, NULL);}}}// 关闭监听套接字和 epoll 实例close(sockfd);close(epfd);return 0;
} 推荐一下
0voice · GitHub