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 }
在unix和Linux主要有4中IO模型
最常用、最简单、效率最低
套接字建立后处于阻塞IO模式
read、recv、wirte、send、accept、connect。。。。
可以防止阻塞在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 }
异步通讯模型
信号驱动IO是指进程提前告诉内核,当某个文件描述符上发生了事件,内核以信号的方式通知进程。总的来说,信号驱动IO对TCP套接字几乎是无用,因为这个信号产生的过于频繁,不能区分是哪种事件。
允许同时对多个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小时内删除。
留言与评论(共有 0 条评论) |