TCP协议是一种可靠的传输协议,用于数据在网络中的传输。在实现服务器端程序时,通常需要支持同时处理多个客户端的连接和请求,这就需要使用并发服务器。
一个并发服务器能够同时处理多个客户端的连接请求并相应客户端的请求。在UNIX网络编程中,使用了多进程和多线程技术来实现并发服务器程序。
一、多进程实现并发服务器
多进程并发实现服务器可以通过fork()系统调用实现。fork()函数能够复制出一个与父进程有相同变量值、代码段和文件描述符表的子进程。当处理一个客户端请求时,程序就可以创建一个子进程,并交给子进程处理,父进程继续等待其他客户端连接请求。这样就可以同时处理多个客户端连接请求。
具体实现时,可以使用select()系统调用来处理多个客户端的I/O事件,然后处理I/O事件的进程就可以通过读写文件描述符与客户端进行通信。
示例代码:一个基于多进程的并发服务器
```
#include #include #include #include #include #include #include #include #include #include #define PORT 8888 #define BACKLOG 5 void sig_chld(int signo) { pid_t pid; int stat; while( (pid = waitpid(-1, &stat, WNOHANG)) > 0) printf("child %d terminated\n", pid); return; } int main(int argc, char *argv[]) { int listener, connfd; struct sockaddr_in servaddr, cliaddr; pid_t childpid; if((listener = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); return -1; } memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(PORT); servaddr.sin_addr.s_addr = htonl(INADDR_ANY); if(bind(listener, (struct sockaddr *)&servaddr ,sizeof(servaddr)) == -1){ perror("bind"); return -1; } if(listen(listener, BACKLOG) == -1) { perror("listen"); return -1; } signal(SIGCHLD, sig_chld); while(1) { socklen_t clilen = sizeof(cliaddr); if((connfd = accept(listener, (struct sockaddr *)&cliaddr, &clilen)) == -1) { perror("accept"); continue; } if((childpid = fork()) == -1) { perror("fork"); return -1; } if(childpid == 0) { close(listener); char buf[1024]; int n; while(1) { if((n = recv(connfd, buf, 1024, 0)) == 0) { close(connfd); return 0; } else if(n < 0) { perror("recv"); return -1; } buf[n] = '\0'; printf("recv: %s", buf); if(send(connfd, buf, strlen(buf), 0) == -1) { perror("send"); return -1; } } } close(connfd); } return 0; } ``` 二、多线程实现并发服务器 多线程并发实现服务器可以使用pthread_create()函数创建多个线程,并让每个线程处理一个客户端连接请求。与多进程不同,多线程共享pid和资源,所以它比多进程更容易管理。 具体实现时,一个线程可以轮询多个客户端的I/O事件,并利用文件描述符与客户端进行通信。 示例代码:一个基于多线程的并发服务器 ``` #include #include #include #include #include #include #include #include #include #include #define PORT 8888 #define BACKLOG 5 void *client_handler(void *arg) { int connfd = *((int *)arg); char buf[1024]; int n; while(1) { if((n = recv(connfd, buf, 1024, 0)) == 0) { close(connfd); return NULL; } else if(n < 0) { perror("recv"); return NULL; } buf[n] = '\0'; printf("recv: %s", buf); if(send(connfd, buf, strlen(buf), 0) == -1) { perror("send"); return NULL; } } return NULL; } int main(int argc, char *argv[]) { int listener, connfd; struct sockaddr_in servaddr, cliaddr; pthread_t tid; if((listener = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); return -1; } memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(PORT); servaddr.sin_addr.s_addr = htonl(INADDR_ANY); if(bind(listener, (struct sockaddr *)&servaddr ,sizeof(servaddr)) == -1){ perror("bind"); return -1; } if(listen(listener, BACKLOG) == -1) { perror("listen"); return -1; } while(1) { socklen_t clilen = sizeof(cliaddr); if((connfd = accept(listener, (struct sockaddr *)&cliaddr, &clilen)) == -1) { perror("accept"); continue; } if(pthread_create(&tid, NULL, client_handler, &connfd) == -1) { perror("pthread_create"); return -1; } } return 0; } ``` 三、多进程与多线程并发的比较 多进程并发与多线程并发各有优缺点,具体使用时需要根据实际情况进行选择。 多进程的优点是可靠性高,各个进程相互独立,进程间不会互相影响;缺点是资源占用较多,进程间切换的开销大,并且需要使用IPC机制来进行进程间通信,实现较为复杂。 多线程的优点是资源开销较小,线程间的切换开销较小,易于管理;缺点是对于共享变量的访问需要进行同步,编程有一定难度,而且由于线程之间共享pid,导致不够稳定,容易出现死锁等问题。 如果你喜欢我们三七知识分享网站的文章,
欢迎您分享或收藏知识分享网站文章
欢迎您到我们的网站逛逛喔!https://www.37seo.cn/
发表评论 取消回复