大家好,欢迎来到IT知识分享网。
2、多线程并发服务器的步骤 1 #include <stdio.h> 2 #include <sys/socket.h>//socket 3 #include <netinet/in.h>//struct sockaddr_in 4 #include <arpa/inet.h>//inet_pton inet_addr 5 #include <string.h>//bzero 6 #include <stdlib.h>//_exit 7 #include <pthread.h>//线程相关函数 8 #include <unistd.h> 9 typedef struct { 10 int cfd;//存放已连接套接字 11 struct sockaddr_in addr;//存放客户端的信息 12 }CLIENT_MSG; 13 void *deal_client_fun(void *arg) 14 { 15 CLIENT_MSG *p = (CLIENT_MSG *)arg; 16 17 //打印客户端的信息 18 char ip[16]=""; 19 unsigned short port = 0; 20 inet_ntop(AF_INET, &p‐>addr.sin_addr.s_addr, ip, 16); 21 port = ntohs(p‐>addr.sin_port); 22 printf("%s %hu connected\n", ip, port); 23 24 //while获取客户端的请求 并回应 25 while(1) 26 { 27 unsigned char buf[1500]=""; 28 int len = recv(p‐>cfd, buf, sizeof(buf), 0); 29 if(len <= 0) 30 { 31 printf("%s %hu 退出了\n", ip, port); 32 close(p‐>cfd); 33 break; 34 } 35 else 36 { 37 printf("%s %d:%s\n", ip, port, buf); 38 send(p‐>cfd, buf, len, 0); 39 } 40 } 41 42 //释放堆区空间 43 if(p != NULL) 44 { 45 free(p); 46 p=NULL; 47 } 48 49 //线程结束 50 pthread_exit(NULL); 51 52 return NULL; 53 } 54 int main(int argc, char const *argv[]) 55 { 56 if(argc != 2) 57 { 58 printf("./a.out 8000\n"); 59 _exit(‐1); 60 } 61 62 //1、创建tcp监听套接字 63 int lfd = socket(AF_INET, SOCK_STREAM, 0); 64 if(lfd < 0) 65 { 66 perror("socket"); 67 _exit(‐1); 68 } 69 70 //设置端口复用 71 int opt = 1; 72 setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); 73 74 //2、bind给服务器的监听套接字 绑定固定的IP、port 75 struct sockaddr_in my_addr; 76 bzero(&my_addr, sizeof(my_addr)); 77 my_addr.sin_family = AF_INET; 78 my_addr.sin_port = htons(atoi(argv[1])); 79 my_addr.sin_addr.s_addr = htonl(INADDR_ANY); 80 int ret = bind(lfd, (struct sockaddr *)&my_addr, sizeof(my_addr)); 81 if(ret < 0) 82 { 83 perror("bind"); 84 _exit(‐1); 85 } 86 87 //3、listen将服务器的套接字主动变被动 创建连接队列 进行监听 88 ret = listen(lfd, 128); 89 if(ret < 0) 90 { 91 perror("listen"); 92 _exit(‐1); 93 } 94 95 //4、while‐‐>accept提取客户端 96 while(1) 97 { 98 struct sockaddr_in cli_addr; 99 socklen_t cli_len = sizeof(cli_addr); 100 int cfd = accept(lfd, (struct sockaddr *)&cli_addr, &cli_len); 101 102 CLIENT_MSG *p = (CLIENT_MSG *)calloc(1,sizeof(CLIENT_MSG)); 103 p‐>cfd = cfd; 104 p‐>addr = cli_addr; 105 106 //5、一个客户端 创建一个线程 107 pthread_t tid; 108 pthread_create(&tid, NULL, deal_client_fun, (void *)p); 109 //线程分离 110 pthread_detach(tid); 111 } 112 113 //关闭监听套接字 114 close(lfd); 115 return 0; 116 }
在这段代码中,通过设置端口复用,实际上是在告诉操作系统允许重新使用被占用的端口。在网络编程中,端口复用是一个常见的技术手段,其作用和优势如下:
1. 允许快速重启服务器:当服务器进程异常退出或者被关闭后,如果不设置端口复用,操作系统会在一段时间内保持该端口处于TIME_WAIT状态,这样会导致在该端口上无法立即启动新的服务器进程。设置了端口复用后,新的服务器进程可以立即重用之前被占用的端口,快速恢复服务。
2. 提高服务器的健壮性和可用性:在高并发环境下,服务器可能会频繁启动和关闭,如果不设置端口复用,会导致端口资源被长时间占用,从而影响服务器的健壮性和可用性。通过设置端口复用,可以避免端口资源被长时间占用,提高服务器的稳定性。
3. 解决TIME_WAIT状态资源耗尽问题:如果不设置端口复用,在高并发情况下,大量的TIME_WAIT状态连接会消耗系统资源,甚至导致资源耗尽。设置端口复用可以有效减少TIME_WAIT状态连接的数量,避免资源耗尽问题的发生。
总之,设置端口复用可以提高服务器的稳定性、健壮性和可用性,是网络编程中常用的一项技术手段。
端口复用是什么意思,可以详细讲解吗
当一个套接字(Socket)在关闭之后,操作系统会保持一段时间的状态,称为TIME_WAIT状态。在这段时间内,该套接字的端口会被标记为不可用,以防止新的连接使用相同的端口。这个状态持续的时间通常是几分钟,具体取决于操作系统的设置。
端口复用就是一种机制,允许一个端口在短时间内被多个套接字共享或者重新使用。通常情况下,一个套接字关闭后,操作系统会将其端口保留一段时间以处理可能存在的延迟数据包或者断开连接后的数据包。但在某些情况下,如果需要快速重新启动服务器或者处理大量的连接请求,这种行为就会成为一个问题,因为端口会被占用一段时间,导致无法立即重新使用。
通过设置端口复用选项,可以告诉操作系统允许其他套接字在当前套接字关闭后立即绑定到同一端口上,而不必等待TIME_WAIT状态结束。这样可以有效地提高服务器的可用性和响应速度,特别是在高并发的网络环境中。
在实际编程中,可以通过调用`setsockopt`函数来设置端口复用选项,具体是通过设置`SO_REUSEADDR`选项来实现的。当这个选项被设置为1时,表示允许端口复用,操作系统将允许重新绑定到同一端口上。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/122643.html