当前位置:首页 > CN2资讯 > 正文内容

并发服务器 unity 并发服务器的优点

2天前CN2资讯


 并发服务器

 优点:1)可以同时处理多个客户端请求,创建子进程或者分支线程来处理客户端的请求

            2)父进程/主线程只负责连接,子进程/分支线程只负责与客户端进行交互;

1、多进程并发服务器

 父进程只负责连接,子进程只负责与客户端进行交互;

模型

void handler(int sig) { //回收僵尸进程 //回收成功则再回收一次,直到回收失败或者没有回收到为止 while(waitpid(-1, NULL, WNOHANG) > 0); } //捕获17号信号 SIGCHLD sighandler_t s = signal(17, handler); sfd = socket(); bind(); listen(); while(1) { newfd = accept(); pid = fork(); if(pid > 0) { close(newfd); } else if(0 == pid) { close(sfd); while(1) { recv(); send(); } close(newfd); exit(0); } } close(sfd);

捕捉子进程退出时发出的17号信号 SIGCHLD,并使用信号处理函数回收子进程的资源,防止僵尸进程的产生

//捕获17号信号 sighandler_t s = signal(17,handler); if(SIG_ERR == s) { ERR_MSG("signal"); return -1; } //信号处理函数 void handler(int sig) { //用非阻塞的形式回收僵尸进程, 如果成功回收,则再回收一次,直到回收子进程失败,或者没有收到为止 while(waitpid(-1,NULL,WNOHANG) > 0); }

 实现交互的函数

//负责与客户端的交互 int rcv_cli_mag(int newfd,struct sockaddr_in cin) { char buf[128] = ""; ssize_t res = 0; while(1) { bzero(buf, sizeof(buf)); //循环接收 res = recv(newfd, buf, sizeof(buf), 0); if(res < 0) { ERR_MSG("recv"); return -1; } else if(0 == res) { printf("[%s : %d] newfd = %d client off-line\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd); break; } printf("[%s : %d] newfd = %d : %s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd,buf); //发送数据 strcat(buf,"*_*"); if(send(newfd,buf,sizeof(buf),0) < 0) { ERR_MSG("send"); return -1; } printf("send message success\n"); } return 0; }

 宏函数与主函数

//打印错误信息的宏函数 #define ERR_MSG(msg) do{\ fprintf(stderr,"__%d__",__LINE__);\ perror(msg);\ }while(0) #define PORT 8888 //范围为1024~49151 #define IP "192.168.31.48" //本机IP,用ifconfig查看 typedef void (*sighandler_t)(int); int rcv_cli_mag(int newfd,struct sockaddr_in cin); int main(int argc, const char *argv[]) { //捕获17号信号 sighandler_t s = signal(17,handler); if(SIG_ERR == s) { ERR_MSG("signal"); return -1; } //创建流式套接字 int sfd = socket(AF_INET,SOCK_STREAM,0); if(sfd < 0) { ERR_MSG("socket"); return -1; } printf("create socket success\n"); //允许端口快速重用 int reuse = 1; if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))<0) { ERR_MSG("setsockopt"); return -1; } //填充地址信息结构体,真实的地址信息结构体与协议族相关 //AF_INET,所以详情请看man 7 ip struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(PORT); //网络字节序的端口号 sin.sin_addr.s_addr = inet_addr(IP); //网络字节序的IP地址 //将地址信息结构体绑定到套接字上 if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0) { ERR_MSG("bind"); return -1; } printf("bind success\n"); //将套接字转为监听状态,让内核监听是否有客户端连接 if(listen(sfd,8)<0) { ERR_MSG("listen"); return -1; } printf("listen success\n"); struct sockaddr_in cin; socklen_t addrlen = sizeof(cin); int newfd =0; pid_t pid =0; //从已完成连接的队列头中,取出一个客户端的信息,创建生成一个新的套接字文件描述符, //该文件描述符才是与客户端通信的文件描述符 while(1) { //父进程只负责连接 newfd = accept(sfd,(struct sockaddr*)&cin,&addrlen); if(newfd < 0) { perror("accept"); return -1; } //网络字节序的IP-->点分十进制 网络字节序的port-->本机字节序 printf("[%s : %d] newfd = %d\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd); //一旦连接成功,创建一个子进程用于交互 pid = fork(); if(pid >0) { close(newfd); } else if(0 == pid) { close(sfd); //子进程负责与客户端交互 rcv_cli_mag(newfd,cin); close(newfd); //交互结束后,不能让子进程继续执行后面的代码,需要直接退出 exit(0); } else { ERR_MSG("fork"); return -1; } } //关闭文件 close(sfd); return 0; }

2、多线程并发服务器

 主线程只负责连接,分支线程只负责与客户端进行交互

模型

sfd = socket(); bind(); listen(); struct msg cliInfo; while(1) { newfd = accept(); cliInfo.newfd = newfd; pthread_create(&tid, NULL, callback, &cliInfo); } void* callBack(void* arg) { pthread_detach(pthread_self()); while(1) { recv(); send(); } close(newfd); pthread_exit() }

 使用pthread_detach函数分离线程,线程退出后,自动回收线程资源

主线程传入分支线程的

 分支线程实现交互

void* rcv_cli_msg(void* arg) { //分离分支线程 pthread_detach(pthread_self()); int newfd = (*(struct msg*)arg).newfd; struct sockaddr_in cin = (*(struct msg*)arg).cin; char buf[128] = ""; ssize_t res = 0; while(1) { bzero(buf, sizeof(buf)); //循环接收 res = recv(newfd, buf, sizeof(buf), 0); if(res < 0) { ERR_MSG("recv"); return NULL; } else if(0 == res) //表明客户端已下线 { //打印下线提醒 printf("[%s : %d] newfd = %d client off-line\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd); break; //退出该分支线程 } printf("[%s : %d] newfd = %d : %s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd,buf); //发送数据 strcat(buf,"*_*"); if(send(newfd,buf,sizeof(buf),0) < 0) { ERR_MSG("send"); return NULL; } printf("send message success\n"); } close(newfd); pthread_exit(NULL); }

宏函数、宏定义与主函数

//打印错误信息的宏函数 #define ERR_MSG(msg) do{\ fprintf(stderr,"__%d__",__LINE__);\ perror(msg);\ }while(0) #define PORT 8888 //范围为1024~49151 #define IP "192.168.31.48" //本机IP,用ifconfig查看 struct msg { int newfd; struct sockaddr_in cin; }; void* rcv_cli_msg(void* arg); int main(int argc, const char *argv[]) { //创建流式套接字 int sfd = socket(AF_INET,SOCK_STREAM,0); if(sfd < 0) { ERR_MSG("socket"); return -1; } printf("create socket success\n"); //允许端口快速重用 int reuse = 1; if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))<0) { ERR_MSG("setsockopt"); return -1; } //填充地址信息结构体,真实的地址信息结构体与协议族相关 //AF_INET,所以详情请看man 7 ip struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(PORT); //网络字节序的端口号 sin.sin_addr.s_addr = inet_addr(IP); //网络字节序的IP地址 //将地址信息结构体绑定到套接字上 if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0) { ERR_MSG("bind"); return -1; } printf("bind success\n"); //将套接字转为监听状态,让内核监听是否有客户端连接 if(listen(sfd,10)<0) { ERR_MSG("listen"); return -1; } printf("listen success\n"); int newfd = 0; pthread_t tid; struct sockaddr_in cin; socklen_t addrlen = sizeof(cin); struct msg cliinfo; //从已完成连接的队列头中,取出一个客户端的信息,创建生成一个新的套接字文件描述符, //该文件描述符才是与客户端通信的文件描述符 while(1) { //主线程负责连接 newfd = accept(sfd, (struct sockaddr*)&cin, &addrlen); if(newfd <0) { ERR_MSG("accept"); return -1; } //网络字节序的IP-->点分十进制 网络字节序的port-->本机字节序 printf("[%s : %d] newfd = %d\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd); cliinfo.newfd = newfd; cliinfo.cin = cin; //一旦连接成功后,创建一个分支线程用于与客户端交互 if(pthread_create(&tid,NULL, rcv_cli_msg,(void*)&cliinfo) != 0) { ERR_MSG("pthread_create"); return -1; } } //关闭文件 close(sfd); return 0; }
    你可能想看:

    扫描二维码推送至手机访问。

    版权声明:本文由皇冠云发布,如需转载请注明出处。

    本文链接:https://www.idchg.com/info/23723.html

    分享给朋友:

    “并发服务器 unity 并发服务器的优点” 的相关文章

    搬瓦工VPS服务使用指南与优惠码获取技巧

    搬瓦工(BandwagonHost)是一家成立于2004年的网络服务公司,隶属于加拿大IT7。这家公司的崛起与它提供的超低价格VPS服务密不可分,尤其是在中国市场,搬瓦工已经积累了大量的用户和知名度。随着时间的推移,搬瓦工不仅没有止步于低价策略,而是逐渐向中高端VPS市场发展,推出了诸如CN2 GI...

    如何选择高性能、美西VPS服务商: 比较、评测及优化建议

    美西VPS概述 美西VPS,简单来说,就是那些位于美国西部地区的虚拟专用服务器,像在洛杉矶这样的城市里。这些服务器给用户提供了一种灵活而高效的托管解决方案,特别是对于需要快速访问和低延迟连接的用户群体。美西VPS的设计理念是为用户提供高性能和高可靠性的服务,同时确保在数据传输时的安全性。 美西VPS...

    BT下载机的使用技巧与软件下载推荐

    在数字时代,文件共享变得越来越普遍,BT下载机作为一种基于BitTorrent协议的P2P(Peer-to-Peer)文件共享工具,扮演着重要的角色。我记得第一次接触BT下载机时,发现它的操作不仅简单,还能快速下载大型文件,这让我对它产生了浓厚的兴趣。BT下载机允许用户通过种子文件(.torrent...

    IPv6 测速方法与工具:提升网络体验的技巧

    IPv6 测速的基本概念 IPv6,作为互联网协议的最新版本,让我们在网络世界中畅游无阻。它的推出旨在解决IPv4所面临的地址枯竭问题,推进更加广泛的设备连接。简单来说,IPv6提供了更大的地址空间,能够支持越来越多的设备上线。因为万物互联的时代已经来临,我们的手机、电脑、家居设备甚至汽车都需要连接...

    Linode新加坡服务器速度与性能评测

    Linode新加坡服务器概述 在当今互联网的快速发展中,选择一款合适的服务器至关重要。Linode是一个备受欢迎的云服务提供商,凭借其强大的全球服务网络而受到许多用户的信任。尤其是Linode的新加坡服务器,以其优越的速度和性能而显得尤为突出。 Linode在多个国家和地区设有数据中心,其中新加坡的...

    跑步的全面指南:基础知识、路线选择与心理技巧

    跑步的基础知识 跑步,这项简单又有效的运动,拥有着悠久的历史和丰富的文化背景。追溯到古代,跑步不仅是人类生存的必要技能,更是一项重要的竞技活动。历史上,古希腊的奥林匹克运动会中,长跑是最受欢迎的项目之一。而在中国,长跑也早在古代就已经成为士兵训练和民间竞技的一部分。随着时代发展,跑步逐渐演变为一种大...