解密C高并发TCP服务器实现方法
概述
在当今数字化时代,构建高效、可靠的服务器是网络通信领域的核心任务之一,C语言作为一种功能强大的编程语言,广泛应用于系统编程和网络编程中,本文将详细介绍如何使用C语言实现高并发的TCP服务器,包括多进程、多线程及IO多路复用等技术的应用,通过这些技术,可以显著提升服务器的性能和稳定性,满足大规模用户访问的需求。
多进程实现高并发TCP服务器
1、基本原理:多进程模型通过父进程监听客户端连接请求,每当有新的连接时,父进程会创建一个子进程来处理该连接,这种方式能够有效利用多核CPU的优势,提高系统的并发处理能力。
2、代码示例
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <unistd.h> #include <signal.h> #include <wait.h> #include <errno.h> void recycleChild(int argc) { while (1) { int ret = waitpid(1, NULL, WNOHANG); if (ret > 0) { printf("Process %d recycled ", ret); } else if (ret == 0) { break; } else { break; } } } int main() { struct sigaction act; act.sa_handler = recycleChild; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGCHLD, &act, NULL); int lfd = socket(AF_INET, SOCK_STREAM, 0); if (lfd == 1) { perror("socket"); exit(1); } struct sockaddr_in serv_addr; memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(9999); serv_addr.sin_addr.s_addr = INADDR_ANY; int ret = bind(lfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); if (ret == 1) { perror("bind"); exit(1); } ret = listen(lfd, 128); if (ret == 1) { perror("listen"); exit(1); } while (1) { struct sockaddr_in cli_addr; socklen_t len = sizeof(cli_addr); int cfd = accept(lfd, (struct sockaddr *)&cli_addr, &len); if (cfd == 1) { perror("accept"); continue; } pid_t pid = fork(); if (pid == 0) { // 子进程 close(lfd); // 关闭不必要的文件描述符 char buf[1024]; while (recv(cfd, buf, sizeof(buf), 0) > 0) { // Echo back to the client send(cfd, buf, sizeof(buf), 0); } close(cfd); exit(0); // 结束子进程 } else if (pid > 0) { // 父进程 close(cfd); // 关闭不必要的文件描述符 } else { perror("fork"); exit(1); } } close(lfd); return 0; }
3、注意事项:使用多进程模型时,需要注意资源的有效管理,如及时回收僵尸进程,避免资源泄漏,由于进程间内存不共享,需要通过IPC(InterProcess Communication)机制进行数据交换。
多线程实现高并发TCP服务器
1、基本原理:多线程模型通过在单个进程中创建多个线程来处理并发连接,每个线程负责一个客户端连接的处理,线程之间共享进程的内存空间,减少了进程间通信的开销。
2、代码示例
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> #include <unistd.h> #include <errno.h> typedef struct { int sockfd; } thread_data; void *handle_client(void *arg) { thread_data *data = (thread_data *)arg; char buf[1024]; while (recv(data>sockfd, buf, sizeof(buf), 0) > 0) { send(data>sockfd, buf, sizeof(buf), 0); } close(data>sockfd); free(data); return NULL; } int main() { int lfd = socket(AF_INET, SOCK_STREAM, 0); if (lfd == 1) { perror("socket"); exit(1); } struct sockaddr_in serv_addr; memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(9999); serv_addr.sin_addr.s_addr = INADDR_ANY; int ret = bind(lfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); if (ret == 1) { perror("bind"); exit(1); } ret = listen(lfd, 128); if (ret == 1) { perror("listen"); exit(1); } while (1) { struct sockaddr_in cli_addr; socklen_t len = sizeof(cli_addr); int cfd = accept(lfd, (struct sockaddr *)&cli_addr, &len); if (cfd == 1) { perror("accept"); continue; } thread_data *data = (thread_data *)malloc(sizeof(thread_data)); data>sockfd = cfd; pthread_t tid; pthread_create(&tid, NULL, handle_client, data); pthread_detach(tid); // 设置为分离状态,线程结束时自动释放资源 } close(lfd); return 0; }
3、注意事项:使用多线程模型时,需要注意线程安全问题,尤其是在访问共享资源时需要加锁,以防止竞态条件的发生,合理设置线程的数目和优先级,以充分利用系统资源。
IO多路复用实现高并发TCP服务器
1、基本原理:IO多路复用技术(如select、poll、epoll)允许单个线程监视多个文件描述符,当某个文件描述符就绪时,线程对其进行处理,这种方式避免了为每个连接创建线程或进程的开销,提高了系统的并发处理能力。
2、代码示例(以epoll为例):
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <sys/epoll.h> #include <unistd.h> #include <errno.h> #define MAX_EVENTS 1024 #define BUF_SIZE 1024 int setNonBlocking(int sockfd) { int flags = fcntl(sockfd, F_GETFL, 0); if (flags == 1) { perror("fcntl get"); return 1; } flags |= O_NONBLOCK; if (fcntl(sockfd, F_SETFL, flags) == 1) { perror("fcntl set"); return 1; } return 0; } int main() { int lfd = socket(AF_INET, SOCK_STREAM, 0); if (lfd == 1) { perror("socket"); exit(1); } setNonBlocking(lfd); // 设置为非阻塞模式 struct sockaddr_in serv_addr; memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(9999); serv_addr.sin_addr.s_addr = INADDR_ANY; int ret = bind(lfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); if (ret == 1) { perror("bind"); exit(1); } ret = listen(lfd, 128); if (ret == 1) { perror("listen"); exit(1); } struct epoll_event ev, events[MAX_EVENTS]; int epfd = epoll_create1(0); // 创建epoll实例 if (epfd == 1) { perror("epoll create"); exit(1); } ev.events = EPOLLIN; // 注册感兴趣的事件类型:有数据可读 ev.data.fd = lfd; // 指定要监听的文件描述符 if (epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &ev) == 1) { // 添加文件描述符到epoll实例中进行监听 perror("epoll ctl"); exit(1); } // 事件循环 for (;;) { int nfds = epoll_wait(epfd, events, MAX_EVENTS, 1); // 等待事件发生,超时时间为1表示无限等待 if (nfds == 1) { perror("epoll wait"); exit(1); } for (int i = 0; i < nfds; ++i) { // 遍历所有就绪的事件 if (events[i].data.fd == lfd) { // 如果就绪的文件描述符是监听套接字,说明有新的连接到来 struct sockaddr_in cli_addr; socklen_t len = sizeof(cli_addr); int cfd = accept(lfd, (struct sockaddr*)&cli_addr, &len); // 接受新的连接 setNonBlocking(cfd); // 设置为非阻塞模式 epoll_event new_ev; new_ev.events = EPOLLIN | EPOLLET; // 注册感兴趣的事件类型:有数据可读或发生EOF(这里ET模式用于水平触发) new_ev.data.fd = cfd; // 指定要监听的文件描述符 if (epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &new_ev) == 1) { // 添加新的文件描述符到epoll实例中进行监听 perror("epoll ctl"); exit(1); } } else { // 如果就绪的文件描述符是客户套接字,说明有数据传输或关闭事件发生 int cfd = events[i].data.fd; // 获取就绪的客户套接字文件描述符 char buf[BUF_SIZE]; // 读取数据缓冲区大小为BUF_SIZE字节 int bytesRead = read(cfd, buf, BUF_SIZE); // 从套接字读取数据到缓冲区中,返回实际读取的字节数(可能小于BUF_SIZE)如果返回值为1,则表示对端关闭了连接或者出现了错误;否则表示成功读取了bytesRead个字节的数据,根据具体需求处理数据...(此处省略数据处理部分)... } } } } } return 0; }```3.注意事项:使用IO多路复用技术时,需要注意正确处理各种I/O事件,尤其是异常情况,合理设置文件描述符的数量和事件的类型,以平衡性能和资源消耗,不同的IO多路复用函数(如select、poll、epoll)有不同的特点和适用场景,需要根据实际情况选择合适的函数,表1:多进程、多线程与IO多路复用技术比较| 技术 | 优点 | 缺点 | 适用场景 |||||||多进程 | 实现简单,可以利用多核CPU | 进程间通信复杂,资源消耗大 | 适用于需要隔离不同任务的场景 ||多线程 | 线程间共享内存,减少通信开销 | 线程安全和同步问题 | 适用于I/O密集型任务 ||IO多路复用 | 高效的I/O处理能力,适合高并发 | 编程复杂,需要处理多种事件 | 适用于大规模并发连接的场景 |通过以上分析和比较,可以看出,不同的并发处理技术各有优缺点,适用于不同的场景,在实际应用中,可以根据具体需求选择合适的技术或组合使用多种技术,以实现高效、稳定的服务器性能。
各位小伙伴们,我刚刚为大家分享了有关“「解密」C 高并发 TCP 服务器实现方法 (c 高并发tcp服务器)”的知识,希望对你们有所帮助。如果您还有其他相关问题需要解决,欢迎随时提出哦!
原创文章,作者:未希,如若转载,请注明出处:https://www.kdun.com/ask/1224389.html
本网站发布或转载的文章及图片均来自网络,其原创性以及文中表达的观点和判断不代表本网站。如有问题,请联系客服处理。
发表回复