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

devtools/2024/10/25 15:59:19/

一.思路

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

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

1.利用while 和 accept 阻塞等待客户端连接,一旦有一个客户端连接上,就创建一个新的子进程执行服务逻辑。
2.子进程结束时,利用信号捕捉函数sigaction回收子进程
3.注意,当主进程阻塞在accept时,若子进程发出信号,accept会被打断(一系列慢速系统调用的特点)从而直接执行接下来的fork函数,这就会导致一个子进程刚好被回收后,又会产生一个新的子进程,为了防止这种情况,使用again和goto维护accept,防止被信号打断后产生错误。

  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 accept27   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 }

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

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.}  

http://www.ppmy.cn/devtools/128716.html

相关文章

骨传导耳机哪个品牌好用质量好?2024年五款高性价比骨传导耳机推荐

骨传导耳机是我们日常生活中不可或缺的电子产品之一&#xff0c;无论是为了享受音乐还是运动健身使用都非常的合适&#xff0c;而选择一款好用且质量优秀的骨传导耳机却并不简单。因为市面上的骨传导耳机品牌琳琅满目&#xff0c;各种功能和设计让人眼花缭乱&#xff0c;经常让…

基于RK3588/算能BM1684 AI盒子:综合视频智能AI分析系统建设方案(五)边缘盒子与AI服务器

方案硬件介绍 智能AI分析服务器 机型:2U机架式服务器 处理器&#xff1a;CPU_Xeon_5318Y_2.1GHz_24C_48T_165W*2 内存&#xff1a;32GB DDR4 3200 RDIMM*4 240GB 2.5in&#xff08;SATA SSD&#xff09;*1 硬盘&#xff1a;6 TB, SATA 6Gb/s, 7.2K&am…

《近似线性可分支持向量机的原理推导》 目标函数 公式解析

本文是将文章《近似线性可分支持向量机的原理推导》中的公式单独拿出来做一个详细的解析&#xff0c;便于初学者更好的理解。 公式 9-38 解释&#xff1a; min ⁡ w , b , ξ 1 2 ∥ w ∥ 2 C ∑ i 1 N ξ i \min_{w, b, \xi} \quad \frac{1}{2} \|w\|^2 C \sum_{i1}^{N} \x…

Python爬虫:自动化获取商品评论数据

为什么选择Python爬虫API 高效的数据处理&#xff1a;Python的数据处理能力&#xff0c;结合Pandas等库&#xff0c;可以轻松处理和分析大量的评论数据。丰富的库支持&#xff1a;Python拥有丰富的库&#xff0c;如requests用于发送HTTP请求&#xff0c;BeautifulSoup用于解析…

Swift Macro 在业务开发中的探索与实践

简介 Swift Macro 在 Swift 5.9 版本中正式引入&#xff0c;且需配合 Xcode 15 使用。Swift Macro 作为一种新的设计方法&#xff0c;致力于帮开发者降低编写重复代码的繁琐&#xff0c;以更为简洁优雅的方式去实现。 在 OC 中&#xff0c;有大家熟知的宏 #define&#xff0c;…

HarmonyOS第一课——HarmonyOS介绍

HarmonyOS第一课 HarmonyOS介绍 HarmonyOS是新一代的智能终端操作系统&#xff08;泛终端服务的载体&#xff09;&#xff1b; 智慧互联协同&#xff0c;全场景交互体验&#xff1b; 核心技术理念&#xff1a; 一次开发 多次部署&#xff1a; 预览 可视化开发UI适配 事件交…

【Docker】在AlmaLinux 8.10系统中安装Docker-ce过程分享

随着2024年6月30日&#xff0c;官方停止了对CentOS 7的维护&#xff0c;属于CentOS 7的时代终于结束了。当然&#xff0c;对于CentOS 7的维护停止&#xff0c;大家也不用过度紧张&#xff0c;目前仍有部分Linux版本可以提供企业级的生产可用系统服务&#xff0c;比如&#xff1…

Unix信号处理

1.引言 信号是软件中断。很多比较重要的应用程序都需要处理信号。信号提供了一种处理异步事件的方法&#xff1a;终端用户键入中断键&#xff0c;则会通过信号机构停止一个程序。 2.信号的概念 首先&#xff0c;每个信号都有一个名字。这些名字都以三个字符SIG开头。例如&…