linux下多进程并发服务器

阅读: 评论:0

linux下多进程并发服务器

linux下多进程并发服务器

多进程并发服务器

  1 /*================================================================2  *   Copyright (C) 2020 hqyj Ltd. All rights reserved.3  *                               4  *   文件名称:01_多进程server.c5  *   创 建 者:Chens             6  *   创建日期:2020年04月24日    7  *   描    述:多进程并发服务器  8  *                               9  ================================================================*/10                                  11                                  12 #include <stdio.h>               13 #include <stdint.h>              14 #include <sys/types.h>           15 #include <sys/socket.h>          16 #include <stdlib.h>              17 #include <unistd.h>              18 #include <arpa/inet.h>           19 #include <string.h>              20 #include <errno.h>               21 #include <sys/types.h>           22 #include <sys/socket.h>          23 #include <sys/types.h>           24 #include <sys/wait.h>            25                                  26 #define  SERV_PORT    6666       27 #define  SERV_IP_ADDR "192.168.1.104"28 #define  QUIT         "quit"     29                                  30 #define BACKLOG       10         31                                  32 void sig_child_handle(int signo);33 void cli_info(struct sockaddr_in cin);34 void cli_data_handle(void* arg); 35                                  36                                  37 int main(int argc, char *argv[]) 38 {                                39     signal(SIGCHLD,sig_child_handle);40     //子进程结束后,会给父进程发送这个信号41     //捕捉,并执行处理           42                                  43     //创建socket                 44     int fd =-1;                  45     if( (fd = socket(AF_INET,SOCK_STREAM,0))<0){46         perror("socket");        47         exit(1);                 48     }                            49                                  50     //允许地址快速重用           51     int b_reuse = 1;             52     setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&b_reuse,sizeof(int));53                                  54     //绑定                       55     struct sockaddr_in sin;      56     bzero(&sin,sizeof(sin));     57     sin.sin_family          = AF_INET;58     sin.sin_port            = htons(SERV_PORT);59     sin.sin_addr.s_addr     = htonl(INADDR_ANY);60                                  61     if(bind(fd,(struct sockaddr*)&sin,sizeof(sin))<0){62         perror("bind");          63         exit(1);                 64     }                            65                                  66     //监听                       67     if(listen(fd,BACKLOG) <0){   68         perror("listen");        69         exit(1);                 70     }                            71                                  72     struct sockaddr_in cin;      73     socklen_t addrlen = sizeof(cin);74     int newfd = -1;              75     pid_t pid = -1;              76     while(1){                    77         bzero(&cin,sizeof(cin)); 78         newfd = accept(fd,(struct sockaddr *)&cin,&addrlen);79         if(newfd <0){            80             perror("accept");    81             continue;            82         }                        83                                  84         /*创建子进程用来处理已建立链接的客户端数据收发*/85         if((pid=fork())<0){      86             perror("fork");      87             exit(1);             88         }                        89         if(0 == pid)//子进程     90         {                        91             close(fd);           92             //已连接客户端信息   93             cli_info(cin);       94             //调用收发函数       95             cli_data_handle(&newfd);96             return 0;            97         }                        98         else{                    99             close(newfd);        
100         }                        
101     }                            
102                                  
103     close(fd);                   
104     return 0;                    
105 }                                
106                                  
107 void sig_child_handle(int signo){
108     if(SIGCHLD == signo){        
109         while(waitpid(-1,NULL,WNOHANG)>0);
110     }                            
111 }                                
112                                  
113                                  
114 void cli_info(struct sockaddr_in cin)
115 {                                
116     //显示客户端信息             
117     char ipv4_addr[16];          
118     bzero(ipv4_addr,sizeof(ipv4_addr));
119     if(NULL == inet_ntop(AF_INET,(void*)&cin.sin_addr.s_addr,ipv4_addr,sizeof(ipv4_addr))){
120         perror("inet_ntop");     
121         exit(1);                 
122     }                            
123     printf("客户端(%s:%d):已连接n",ipv4_addr,ntohs(cin.sin_port));
124 }                                
125                                  
126                                  
127                                  
128 void cli_data_handle(void* arg)  
129 {                                
130     int newfd = *((int*)arg);    
131     printf("子进程连接newfd=%dn",newfd);
132                                  
133     int ret = -1;                
134     char buf[BUFSIZ]={};         
135     while(1){                    
136         bzero(buf,BUFSIZ);       
137         do{                      
138             ret=read(newfd,buf,BUFSIZ-1);
139         }while(ret<0&&EINTR==errno);
140         if(ret<0){               
141             perror("recv");      
142             exit(1);             
143         }                        
144         if(!ret)break;           
145                                  
146         printf("收到:%sn",buf);
147                                  
148         if(!strncasecmp(buf,QUIT,strlen(QUIT))){
149             puts("++++客户端退出了");
150             break;               
151         }                        
152     }                            
153     close(newfd);                
154 }                                
155                                  
156                                  

多线程并发服务器

  1 /*================================================================2 *   Copyright (C) 2020 hqyj Ltd. All rights reserved.3 *   4 *   文件名称:01_多线程并发server.c5 *   创 建 者:Chens6 *   创建日期:2020年04月24日7 *   描    述:8 *9 ================================================================*/10  11  12 #include <stdio.h>13 #include <stdint.h>14 #include <sys/types.h>    15 #include <sys/socket.h>   16 #include <stdlib.h>17 #include <unistd.h>18 #include <arpa/inet.h>    19 #include <string.h>20 #include <errno.h>21 #include <sys/types.h>    22 #include <sys/socket.h>   23 #include <sys/types.h>    24 #include <sys/wait.h>     25 #include <pthread.h>      26  27 #define  SERV_PORT    666628 #define  SERV_IP_ADDR "192.168.1.104"29 #define  QUIT         "quit"30  31 #define BACKLOG       10  32  33 void cli_info(struct sockaddr_in cin);34 void cli_data_handle(void *arg);35  36 int main(int argc, char *argv[])37 {38     //创建socket39     int fd =-1;40     if( (fd = socket(AF_INET,SOCK_STREAM,0))<0){41         perror("socket"); 42         exit(1);43     }44     puts("------创建套接字-----");45  46     //允许地址快速重用    47     int b_reuse = 1;      48     setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&b_reuse,sizeof(int));49     puts("------允许地址快速重用-----");50     //绑定51     struct sockaddr_in sin;52     bzero(&sin,sizeof(sin));53     sin.sin_family          = AF_INET;54     sin.sin_port            = htons(SERV_PORT);55     sin.sin_addr.s_addr     = htonl(INADDR_ANY);56  57     if(bind(fd,(struct sockaddr*)&sin,sizeof(sin))<0){58         perror("bind");   59         exit(1);60     }61  62     puts("-------绑定ip端口-----");63     //监听64     if(listen(fd,BACKLOG) <0){65         perror("listen"); 66         exit(1);67     }68  69     puts("-------服务器开启监听------");70  71     struct sockaddr_in cin;72     socklen_t addrlen = sizeof(cin);73     int newfd =-1;74     pthread_t tid;75     while(1){76         newfd = accept(fd,(void*)&cin,&addrlen);77         if(newfd <0){     78             perror("accept");79             break;80         }81         //显示已连接信息  82         cli_info(cin);    83         84         //调用子线程      85         pthread_create(&tid,NULL,(void*)cli_data_handle,(void*)&newfd);86  87     }88     close(fd);89  90  91     return 0;92 }93  94 void cli_info(struct sockaddr_in cin)95 {96     //显示客户端信息      97     char ipv4_addr[16];   98     bzero(ipv4_addr,sizeof(ipv4_addr));99     if(NULL == inet_ntop(AF_INET,(void*)&cin.sin_addr.s_addr,ipv4_addr,sizeof(ipv4_addr))){
100         perror("inet_ntop");
101         exit(1);
102     }
103     printf("客户端(%s:%d):已连接n",ipv4_addr,ntohs(cin.sin_port));
104 }
105  
106 void cli_data_handle(void *arg)
107 {
108     pthread_detach(pthread_self());
109     int newfd = *((int *)arg);
110     printf("线程连接到newfd=%dn",newfd);
111     int ret =-1;
112     char buf[BUFSIZ];     
113         while(1){
114         bzero(buf,BUFSIZ);
115         do{
116             ret=read(newfd,buf,BUFSIZ-1);
117         }while(ret<0&&EINTR==errno);
118         if(ret<0){
119             perror("recv");
120             exit(1);      
121         }
122         if(!ret)break;    
123                                                                                                      
124         printf("收到:%sn",buf);
125  
126         if(!strncasecmp(buf,QUIT,strlen(QUIT))){
127             puts("++++客户端退出了");
128             break;
129         }
130     }
131     close(newfd);
132     pthread_exit(0);      
133 }

IO模型

在unix和Linux主要有4中IO模型

1、阻塞IO

​ 最常用、最简单、效率最低

​ 套接字建立后处于阻塞IO模式

​ read、recv、wirte、send、accept、connect。。。。

2、非阻塞IO

​ 可以防止阻塞在IO操作上,需要轮询。

​ 需要使用一个循环不停的测试是否资源文件有数据可以读取。

​ fcntl函数设置非阻塞状态

#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );fd:文件描述符cmd:F_GETFL和F_SETFL
返回值:F_GETFD返回文件描述符状态标记出错-1
int flag;
flag = fcntl(scokfd,F_GETFL,0);//获取文件状态标记
flag |= O_NONBLOCK;          //相当于flag = flag | O_NONBLOCK;
fcntl(sockfd,F_SETFL,flag);//设置文件标记
 1 /*================================================================2 *   Copyright (C) 2020 hqyj Ltd. All rights reserved.3 *   4 *   文件名称:01_非阻塞.c5 *   创 建 者:Chens6 *   创建日期:2020年04月24日7 *   描    述:8 *   9 ================================================================*/
10     
11     
12 #include <stdio.h>
13 #include <unistd.h>
14 #include <fcntl.h>
15 #include <strings.h>
16     
17 int main(int argc, char *argv[])
18 {   
19     int flag;
20     char buf[128]={};
21     //1获取文件描述符标记属性
22     flag = fcntl(0,F_GETFL);
23     //2设置                                                        
24     flag |= O_NONBLOCK;
25     //3写回去
26     fcntl(0,F_SETFL,flag);
27     
28     while(1){
29         bzero(buf,sizeof(buf));
30         fgets(buf,sizeof(buf),stdin);
31         sleep(1);
32         printf("------buf:%sn",buf);
33     }
34     
35     return 0;
36 }   

3、信号驱动

​ 异步通讯模型

​ 信号驱动IO是指进程提前告诉内核,当某个文件描述符上发生了事件,内核以信号的方式通知进程。总的来说,信号驱动IO对TCP套接字几乎是无用,因为这个信号产生的过于频繁,不能区分是哪种事件。

4、IO多路复用

​ 允许同时对多个IO进行监控

​ IO多路复用是只让内核一旦发现指定的一个或多个IO产生特定的事件,才通知这个进程。

​ 为什么要用多路复用

​ 相对于多进程、多线程、非阻塞系统开销小,而且不用维护进程和线程等

/* According to POSIX.1-2001, POSIX.1-2008 */
#include <sys/select.h>/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>int select(int maxfd, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
参数:maxfd:要监控的文件描述符值最大那个 +1readfds:指定要监控的读集合writefds:写集合exceptfds:异常集合关于集合:我们想添加fd到集合、从集合中删除fd、查询fd是不是在集合中、清空集合void FD_CLR(int fd, fd_set *set);从集合中删除fdint  FD_ISSET(int fd, fd_set *set);查询fd是不是在集合中void FD_SET(int fd, fd_set *set);添加fd到集合void FD_ZERO(fd_set *set);清空集合timeout:超时设置NULL:一直阻塞,直到有文件描述符产生特定事件函数返回返回值:-1出错,>0产生事件设置超时时间:0立即返回非阻塞时间不为零,等着,超时就返回返回值0时间到了-1出错>0产生事件struct timeval{long tv_sec;long tv_usec;}返回值:产生事件的文件描述符个数失败-1
 1 /*================================================================2  *   Copyright (C) 2020 hqyj Ltd. All rights reserved.3  *                          4  *   文件名称:02_多路复用01.c5  *   创 建 者:Chens        6  *   创建日期:2020年04月24日7  *   描    述:执行的时候需要加sudo8  *                          9  ================================================================*/
10                             
11                             
12 #include <stdio.h>          
13 #include <sys/time.h>       
14 #include <sys/types.h>      
15 #include <unistd.h>         
16 #include <sys/types.h>      
17 #include <sys/stat.h>       
18 #include <fcntl.h>          
19 #include <stdlib.h>         
20                             
21 int main(int argc, char *argv[])
22 {                           
23     //打开鼠标驱动文件      
24     int fd =-1;             
25     fd = open("/dev/input/mouse0",O_RDONLY);
26     if(fd < 0){             
27         perror("open");     
28         exit(1);            
29     }                       
30                             
31     //创建关心的读集合      
32     fd_set readfds,temp;    
33     //给集合清零初始化      
34     FD_ZERO(&readfds);      
35     //将关心的文件描述符添加到集合中
36     FD_SET(0,&readfds);     
37     FD_SET(fd,&readfds);    
38                             
39     struct timeval tv={1,0};                                       
40                             
41     int val =-1;            
42                             
43     while(1){               
44         tv.tv_sec  = 1;     
45         tv.tv_usec = 0;     
46         temp = readfds;     
47         val = select(fd+1,&temp,NULL,NULL,&tv);
48         if(val <0){         
49             perror("select");
50             exit(1);        
51         }                   
52         else if(0 == val){  
53             puts("-------超时了");
54             continue;       
55         }                   
56         else{               
57             if(FD_ISSET(0,&temp)){
58                 puts("键盘输入++++++++");
59             }               
60             if(FD_ISSET(fd,&temp)){
61                 puts("****鼠标动了***");
62             }               
63         }                   
64         sleep(1);           
65     }                       
66     close(fd);              
67     return 0;               
68 }                           

本文发布于:2024-02-04 05:58:57,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170700530952889.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:进程   服务器   linux
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23