
(六)多进程实现TCP服务端
发布日期:2021-05-07 04:38:51
浏览次数:14
分类:精选文章
本文共 3094 字,大约阅读时间需要 10 分钟。
首先,为什么要用多进程处理,多进程的好处是可靠性高,而且在处理大量数据的时候,多进程的速度会比多线程快,所有多进程还是要掌握的。
在一些实际项目中,进程和线程要根据实际场景用。
但是多进程是不能共享进程空间的,所以有很多变量都不能共享。除了fork()之前的变量是可以共享的。
下面的代码基本逻辑就是,用父进程来 accept,检测有没有新的客户端要连入,用子进程来接受客户端发来的信息
下面给出服务端的代码:(有详细注释)
#include"myhead.h"char rbuf[50];char wbuf[50];char ipbuf[50];int main(){ signal(SIGCHLD,SIG_IGN);//把子进程的僵尸进程给init进程处理 struct sockaddr_in saddr; struct sockaddr_in caddr; int size,len,opt = 1; int sockfd,newfd; pid_t pid; int err; size = sizeof(struct sockaddr_in); len = sizeof(struct sockaddr); //初始化本地ip,地址信息 bzero(&saddr,size); saddr.sin_family = AF_INET; saddr.sin_port = htons(8888); saddr.sin_addr.s_addr = htonl(INADDR_ANY); //创建一个监听套接字 sockfd = socket(AF_INET,SOCK_STREAM,0); if(sockfd<0) { perror("failed socket"); return -1; } //设置端口复用 err = setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof opt); if(err<0) { perror("setsockopt failed"); return -1; } //绑定套接字和IP,地址信息 err = bind(sockfd,(struct sockaddr*)&saddr,len); if(err<0) { perror("failed bind"); return -1; } //开始监听 listen(sockfd,10); //循环接收 客户端的连入 while(1) { //监测有没有新的客户端连入,有的话,返回新的套接字 newfd = accept(sockfd,(struct sockaddr*)&caddr,&len); if(newfd<0) { perror("accept failed"); continue; } //有新的客户端连入,则打印他的IP和端口 inet_ntop(AF_INET,(void*)&caddr.sin_addr.s_addr, ipbuf,50); printf("the client:%s is in\n", ipbuf); //创建一个子进程来接受新客户端的信息 pid = fork(); if(pid<0) //fork失败 { perror("failed fork()"); return -1; } else if(pid == 0) //子进程 { close(sockfd);//关闭从父进程进程来的监听套接字 //因为在子进程用不到 /*关闭不需要的套接字可节省系统资源, 同时可避免父子进程共享这些套接字 可能带来的不可预计的后果 */ //这个子进程循环接收客户端信息 while(1) { err = recv(newfd,rbuf,50,0); if(err<0) { perror("failed recv"); } //若recv的返回=0,表示客户端已经断开 else if(err == 0) { bzero(ipbuf,50); inet_ntop(AF_INET,(void*)&caddr.sin_addr.s_addr, ipbuf,50); printf("the client:%s is out\n", ipbuf); exit(0); close(newfd); } //读取客户端的信息 else { inet_ntop(AF_INET,(void*)&caddr.sin_addr.s_addr, ipbuf,50); printf("ip:%s,port:%d\n",ipbuf,ntohs(caddr.sin_port)); printf("%s\n",rbuf); bzero(rbuf,50); } } } else if(pid>0) //父进程,用于继续监测有没有新的客户端连入 { close(newfd);//关闭新客户端返回的套接字,因为在 //父进程中用不到 continue; } }}
再给出客户端的代码:
客户端的没啥好说的,通用的客户端代码就可以
#include "myhead.h"char wbuf[50];int main(){ struct sockaddr_in saddr; struct sockaddr_in caddr; int size,len,opt = 1; int sockfd,newfd; pid_t pid; int err; size = sizeof(struct sockaddr_in); len = sizeof(struct sockaddr); bzero(&saddr,size); saddr.sin_family = AF_INET; saddr.sin_port = htons(8888); saddr.sin_addr.s_addr = inet_addr("192.168.106.128"); sockfd = socket(AF_INET,SOCK_STREAM,0); if(sockfd<0) { perror("failed socket"); return -1; } err = setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof opt); if(err<0) { perror("setsockopt failed"); return -1; } err = connect(sockfd,(struct sockaddr*)&saddr, sizeof(struct sockaddr)); if(err<0) { perror("failed connect"); return -1; } while(1) { scanf("%s",wbuf); write(sockfd,wbuf,50); bzero(wbuf,50); }}
发表评论
最新留言
感谢大佬
[***.8.128.20]2025年03月18日 18时42分55秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
L2-031 深入虎穴 (25 分)
2021-05-08
Unity之PlayerPrefs
2021-05-08
简单的xml读取存储方法(未优化)
2021-05-08
Flower
2021-05-08
Nginx---惊群
2021-05-08
供应ASTM D3475认证丨ASTM D3475防儿童包装测试费用
2021-05-08
2种解法 - 获取一条直线上最多的点数
2021-05-08
项目中常用的审计类型概述
2021-05-08
新生儿不建议吃鱼肝油,这些你知道吗
2021-05-08
新生儿哭是因为什么
2021-05-08
nodeName与tagName的区别
2021-05-08
(九)实现页面底部购物车的样式
2021-05-08
在vue中给对象扩展属性的方法
2021-05-08
Neo4j : 通过节点的 id属性 对节点进行查,改,删操作
2021-05-08
Linux标准错误和标准输出重定向到同一个文件
2021-05-08
【2021年新书推荐】ASP.NET Core 5 and Angular
2021-05-08
python-day3 for语句完整使用
2021-05-08