0基础学会 TCP通信多进程高并发(内附C语言源码)

一、分析

要实现TCP通信服务器处理并发的任务,使用多线程或者多进程来解决。

思路:

        1、一个父进程,多个子进程;

        2、父进程负责等待并接受客户端的连接;

        3、子进程:完成通信,接受一个客户端连接,就创建一个子进程用于通信。

二、代码实现

设计意图

1)服务器阻塞接收若干个客户端的连接请求,一旦有一个客户端connect,则服务器端fork一个子进程与之连接。
2)在服务器端,子进程的任务是接收并处理客户端的数据,而父进程的任务是监听新的客户端请求(accept),创建子进程,并负责回收子进程(可通过处理SIGCHLD信号的方式)。

server_process.c

  1 #include <stdio.h>
  2 #include <arpa/inet.h>
  3 #include <stdlib.h>
  4 #include <unistd.h>
  5 #include <string.h>
  6 #include <signal.h>
  7 #include <wait.h>
  8 #include <errno.h>
  9 void recyChild(int argc)
 10 {
 11         while(1)
 12         {
 13                 int ret=waitpid(-1,NULL,WNOHANG);
 14                 if(ret==-1)
 15                 {
 16                         //所有进程都运行完了
 17                         break;
 18                 }
 19                 else if(ret==0)
 20                 {
 21                         //还有子进程活着
 22                         break;
 23                 }
 24                 else if(ret>0)
 25                 {
 26                         //还有子进程没有回收
 27                         printf("%d 进程被回收了\n",ret);
 28 
 29                 }
 30         }
 31 }
 32 int main()
 33 {
 34         //注册捕捉函数
 35         struct sigaction act;
 36         act.sa_flags=0;
 37         sigemptyset(&act.sa_mask);
 38         act.sa_handler=recyChild;
 39         sigaction(SIGCHLD,&act,NULL);
 40         //1、socket
 41         int lfd=socket(AF_INET,SOCK_STREAM,0);
 42         if(lfd==-1)
 43         {
 44                 perror("socket");
 45                 exit(-1);
 46         }
 47         //2、绑定bind
 48         struct sockaddr_in saddr;
 49         saddr.sin_family=AF_INET;
 50         saddr.sin_port=htons(9999);
 51         saddr.sin_addr.s_addr=INADDR_ANY;
 52         int ret=bind(lfd,(struct sockaddr *)&saddr,sizeof(saddr));
 53         if(ret==-1)
 54         {
 55                 perror("bind");
 56                 exit(-1);
 57         }
 58         //3、监听listen
 59         ret=listen(lfd,128);
 60         if(ret==-1)
 61         {
 62                 perror("listen");
 63                 exit(-1);
 64         }
 65         //4、循环接收accept
 66         while(1)
 67         {
 68                 struct sockaddr_in cliaddr;
 69                 int len=sizeof(cliaddr);
 70                 int num=accept(lfd,(struct sockaddr*)&cliaddr,&len);
 71                 if(num==-1)
 72                 {
 73                         if(errno==EINTR)
 74                         {
 75                                 continue;
 76                         }
 77                         perror("accept");
 78                         exit(-1);
 79                 }
 80 
 81                 //创建子进程
 82                 pid_t pid=fork();
 83                 if(pid==0)
 84                 {
 85                         char cliIP[16];
 86                            
                        inet_ntop(AF_INET,&cliaddr.sin_addr.s_addr,cliIP,sizeof(cliIP));
 87                         unsigned short cliPort=ntohs(cliaddr.sin_port);
 88                         printf("client ip:%s,proc :%d\n",cliIP,cliPort);
 89 
 90                         //接收客户端发来的信息
 91                         char recvBuf[1024]={0};
 92                         while(1)
 93                         {
 94                                 int fd=read(num,&recvBuf,sizeof(recvBuf));
 95                                 if(fd==-1)
 96                                 {
 97                                         perror("read");
 98                                         exit(-1);
 99                                 }
100                                 else if(fd>0)
101                                 {
102                                         printf("recv data:%s\n",recvBuf);
103                                 }
104                                 else
105                                 {
106                                         printf("client closed...");
107                                 }
108                                 write(num,recvBuf,strlen(recvBuf));
109 //                              exit(0);
110                 //              close(fd);
111                         }
112                 }
113 //                              close(num);
114         }
115 //      close(ret);
116         return 0;
117 }

client_process.c

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <stdlib.h>
  4 #include <string.h>
  5 #include <arpa/inet.h>
  6 int main()
  7 {       //1、socket连接
  8         int cld=socket(AF_INET,SOCK_STREAM,0);
  9         if(cld==-1)
 10         {
 11                 perror("socket");
 12                 exit(-1);
 13         }
 14         //2、连接
 15         struct sockaddr_in caddr;
 16         caddr.sin_family=AF_INET;
 17         inet_pton(AF_INET,"192.168.17.136",&caddr.sin_addr.s_addr);
 18         caddr.sin_port=htons(9999);
 19         int ret=connect(cld,(struct sockaddr *)&caddr,sizeof(caddr));
 20         if(ret==-1)
 21         {
 22                 perror("connect");
 23                 exit(-1);
 24         }
 25         //3、通信  给客户端发送数据
 26         char recvBuf[1024]={0};
 27         int i=0;
 28         while(1)
 29         {
 30                 sprintf(recvBuf,"%d\n",i++);
 31                 write(cld,recvBuf,strlen(recvBuf)+1);
 32                 int fd=read(cld,recvBuf,sizeof(recvBuf));
 33                 sleep(1);
 34                 if(fd==-1)
 35                 {
 36                         perror("read");
 37                         exit(-1);
 38                 }
 39                 else if(fd>0)
 40                 {
 41                         printf("recv server data:%s\n",recvBuf);
 42                 }
 43                 else
 44                 {
 45                         printf("connect closed ...");
 46                 }
 47 //              close(fd);//如果不把这块删掉只能传送10个数据,删除后可以连续发送数据
 48         }
 49         close(cld);
 50         return 0;
 51 }

 运行:

一定要先运行服务器,再运行客户端,这样不会报错,首先客户端会先主动给服务器发送信号,这个时候就开始三次握手了(这个时间是非常快的),三次握手结束后就可以正常给服务器发送数据了,此时可以连续打开多个客户端用于实现多进程,此时观察服务器的状态,你会发现服务器不断接受不同的客户端发来的信号。当你关闭一个客户端后(此时会出现四次挥手,速度很快),服务器会显示“已经回收进程”后继续接受别的进程发来的信号,如果你重新运行刚才关闭的客户端,此时服务器会重新接受这个客户端发来的信号。如果全部关闭客户端的话,此时的服务器会出现阻塞等待,直到下一个客户端发来信号。

大家可以复制程序在自己的设备上运行。

 

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值