[Linux网络编程]04-多进程/多线程并发服务器思路分析及实现(进程,信号,socket,线程...)

一.思路

实现一个服务器可以连接多个客户端,每当accept函数等待到客户端进行连接时 就创建一个子进程;
核心思路:让accept循环阻塞等待客户端,每当有客户端连接时就fork子进程,让子进程去和客户端进行通信,父进程用于监听并使用信号捕捉回收子进程;(子进程关闭用于监听的套接字lfd,父进程关闭用于通信的cfd)

二.多进程并发服务器代码实现:

1.利用while 和 accept 阻塞等待客户端连接,一旦有一个客户端连接上,就创建一个新的子进程执行服务逻辑。

2.子进程结束时,利用信号捕捉函数sigaction回收子进程

3.注意,当主进程阻塞在accept时,若子进程发出信号,accept会被打断(一系列慢速系统调用的特点)从而直接执行接下来的fork函数,这就会导致一个子进程刚好被回收后,又会产生一个新的子进程,为了防止这种情况,使用again和goto维护accept,防止被信号打断后产生错误。

cpp 复制代码
  1 #include<iostream>                                                                                        
  2 #include<unistd.h>
  3 #include<sys/socket.h>
  4 #include<arpa/inet.h>
  5 #include<signal.h>
  6 #include<sys/wait.h>
  7 using namespace std;
  8 
  9 void huidiao(int signo)
 10 {
 11  pid_t pid;
 12  while((pid = waitpid(-1,NULL,WNOHANG))>0)
 13  {
 14    cout<<pid<<endl;
 15  }
 16  return ;
 17 }
 18 
 19 int main()
 20 { 
 21      struct sigaction act;
 22      act.sa_handler = huidiao; sigemptyset(&act.sa_mask);
 24      act.sa_flags = 0;
 25      sigaction(SIGCHLD,&act,NULL);
 26   //socket bind listen accept
 27   int fd = socket(AF_INET,SOCK_STREAM,0);
 28   struct sockaddr_in serveraddr,clientaddr;
 29   serveraddr.sin_family = AF_INET;
 30   serveraddr.sin_port = htons(9876);
 31   serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
 32   bind(fd,(struct sockaddr*)&serveraddr,sizeof(serveraddr));
 33 
 34   listen(fd,128);
 35 
 36   socklen_t clientaddr_len = sizeof(clientaddr);
 37   int sfd,flag;
 38   while(true)
 39   {
 40     sfd = accept(fd,(struct sockaddr*)&clientaddr,&clientaddr_len);
 41     flag = fork();
 42    
 43     if(flag == 0)
 44     {                                      close(fd);
 46       break;
 47     }
 48     else if(flag <0)
 49     {
 50       exit(1);
 51     }
 52     else if(flag>0) 
 53     {
 54       close(sfd);
 55       continue;
 56     }
 57   } 
 58 
 59     if(flag == 0)
 60 {                                                                           
 61       for(;;)
 62     {
 63        char buf[1024];
 64        int n = read(sfd,buf,sizeof(buf));
 65        if(n==0)
 66        {                              close(sfd);
 68           cout<<"jieshu"<<endl;
 69           exit(0);
 70        }
 71           for(int i = 0;i<n;i++)
 72           {
 73             buf[i] = toupper(buf[i]);
 74           }
 75           write(STDOUT_FILENO,buf,n);
 76           write(sfd,buf,n);
 77     }
 78 }
 79  return 0;
 80 }

三. 多线程并发服务器代码实现:

cpp 复制代码
1.#include <stdio.h>  
2.#include <string.h>  
3.#include <arpa/inet.h>  
4.#include <pthread.h>  
5.#include <ctype.h>  
6.#include <unistd.h>  
7.#include <fcntl.h>  
8.  
9.#include "wrap.h"  
10.  
11.#define MAXLINE 8192  
12.#define SERV_PORT 8000  
13.  
14.struct s_info {                     //定义一个结构体, 将地址结构跟cfd捆绑  
15.    struct sockaddr_in cliaddr;  
16.    int connfd;  
17.};  
18.  
19.void *do_work(void *arg)  
20.{  
21.    int n,i;  
22.    struct s_info *ts = (struct s_info*)arg;  
23.    char buf[MAXLINE];  
24.    char str[INET_ADDRSTRLEN];      //#define INET_ADDRSTRLEN 16  可用"[+d"查看  
25.  
26.    while (1) {  
27.        n = Read(ts->connfd, buf, MAXLINE);                     //读客户端  
28.        if (n == 0) {  
29.            printf("the client %d closed...\n", ts->connfd);  
30.            break;                                              //跳出循环,关闭cfd  
31.        }  
32.        printf("received from %s at PORT %d\n",  
33.                inet_ntop(AF_INET, &(*ts).cliaddr.sin_addr, str, sizeof(str)),  
34.                ntohs((*ts).cliaddr.sin_port));                 //打印客户端信息(IP/PORT)  
35.  
36.        for (i = 0; i < n; i++)   
37.            buf[i] = toupper(buf[i]);                           //小写-->大写  
38.  
39.        Write(STDOUT_FILENO, buf, n);                           //写出至屏幕  
40.        Write(ts->connfd, buf, n);                              //回写给客户端  
41.    }  
42.    Close(ts->connfd);  
43.  
44.    return (void *)0;  
45.}  
46.  
47.int main(void)  
48.{  
49.    struct sockaddr_in servaddr, cliaddr;  
50.    socklen_t cliaddr_len;  
51.    int listenfd, connfd;  
52.    pthread_t tid;  
53.  
54.    struct s_info ts[256];      //创建结构体数组.  
55.    int i = 0;  
56.  
57.    listenfd = Socket(AF_INET, SOCK_STREAM, 0);                     //创建一个socket, 得到lfd  
58.  
59.    bzero(&servaddr, sizeof(servaddr));                             //地址结构清零  
60.    servaddr.sin_family = AF_INET;  
61.    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);                               //指定本地任意IP  
62.    servaddr.sin_port = htons(SERV_PORT);                                       //指定端口号   
63.  
64.    Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));             //绑定  
65.  
66.    Listen(listenfd, 128);                                                      //设置同一时刻链接服务器上限数  
67.  
68.    printf("Accepting client connect ...\n");  
69.  
70.    while (1) {  
71.        cliaddr_len = sizeof(cliaddr);  
72.        connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);   //阻塞监听客户端链接请求  
73.        ts[i].cliaddr = cliaddr;  
74.        ts[i].connfd = connfd;  
75.  
76.        pthread_create(&tid, NULL, do_work, (void*)&ts[i]);  
77.        pthread_detach(tid);                                                    //子线程分离,防止僵线程产生.  
78.        i++;  
79.    }  
80.  
81.    return 0;  
82.}  
相关推荐
大树8820 分钟前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠23 分钟前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
bush41 小时前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5201 小时前
Linux 11 动态监控指令top
linux
小宇宙Zz1 小时前
Maven依赖冲突
java·服务器·maven
网络研究院2 小时前
2026年网络安全
网络·安全·法律·法规·趋势·发展
酣大智2 小时前
ARP代理--工作原理
运维·网络·arp·arp代理
treesforest2 小时前
AI安全系统如何识别异常访问?IP风险识别正在成为关键能力
网络·人工智能·tcp/ip·安全·web安全
不会C语言的男孩2 小时前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言
shushangyun_2 小时前
2026年快消品B2B系统推荐:支持终端门店订货、促销政策自动化的工具?
java·运维·网络·数据库·人工智能·spring·自动化