多路复用poll
#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
参数
fds:要监控文件描述符集合
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events */
short revents; /* returned events */
};
events和revents:
POLLIN 有数据可读
POLLOUT写数据
POLLER指定文件描述符发生错误
POLLRDHUP判断tcp的socket关闭了连接
加上一个宏 _GNU_SOURCE
#define _GNU_SOURCE 1
#include <poll.h>
nfds:监控多少个文件描述符
timeout:超时(毫秒)
> 0等待的时间
==0非阻塞
< 0阻塞 INFTIM
返回值:
成功,返回结构体revents域不为0的文件描述符个数
失败,-1
如果超时返回0
1 /*================================================================
2 * Copyright (C) 2020 hqyj Ltd. All rights reserved.
3 *
4 * 文件名称:02_多路复用01.c
5 * 创 建 者:Chens
6 * 创建日期:2020年04月24日
7 * 描 述:执行的时候需要加sudo
8 *
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 #include <poll.h>
21
22 int main(int argc, char *argv[])
23 {
24 //打开鼠标驱动文件
25 int fd =-1;
26 fd = open("/dev/input/mouse0",O_RDONLY);
27 if(fd < 0){
28 perror("open");
29 exit(1);
30 }
31
32 //1,创建文件描述符集合
33 struct pollfd fds[2];
34 //2,把关心的文件描述符填入
35 fds[0].fd = 0;//监控键盘
36 fds[0].events = POLLIN;//监控键盘的输入
37
38 fds[1].fd = fd;//监控鼠标
39 fds[1].events = POLLIN;//监控鼠标输入
40
41
42 int val =-1;
43
44 while(1){
45
46 val = poll(fds,2,1000);
47 if(val <0){
48 perror("poll");
49 exit(1);
50 }
51 else if(0 == val){
52 puts("-------超时了");
53 continue;
54 }
55 else{
56 if(fds[0].revents == POLLIN){
57 puts("键盘输入++++++++");
58 }
59 if(fds[1].revents == POLLIN){
60 puts("****鼠标动了***");
61 }
62 }
63 }
64 close(fd);
65 return 0;
66 }
2、域套接字
用于本地间通讯,域套接字 易用性、效率还可以不错
#include <sys/socket.h>
#include <sys/un.h>
unix_socket = socket(AF_UNIX, type, 0);
socket(AF_LOCAL,SOCK_STREAM,0);
socket(AF_LOCAL,SOCK_DGRAM ,0);
struct sockaddr_un {
sa_family_t sun_family; 填写AF_UNIX
char sun_path[108]; 套接字文件绝对路径
这个套接字必须事先不存在
};
填充结构体
struct sockaddr_un myaddr;
bzero(&myaddr.sizeof(myaddr));
myaddr.sun_family = AF_UNIX;
strcpy(myaddr.sun_path,"/tmp/mysocket");
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LIUgZ7MG-1587912699172)(.\1.png)]
#include <unistd.h>
int access(const char *pathname, int mode);
参数:
pathname路径文件名
mode:
F_OK判断存在
X_OK判断权限执行权限
W_OK判断权限写权限
R_OK判断权限读权限
返回值:
成功0失败-1
#include <unistd.h>
int unlink(const char *pathname);
返回值,成功0,失败-1
1 /*================================================================
2 * Copyright (C) 2020 hqyj Ltd. All rights reserved.
3 *
4 * 文件名称:01_域套接字服务器.c
5 * 创 建 者:Chens
6 * 创建日期:2020年04月26日
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/socket.h>
22 #include <sys/types.h>
23 #include <sys/wait.h>
24 #include <sys/un.h>
25
26 #define QUIT "quit"
27 #define BACKLOG 10
28 #define PATH "/tmp/20021/unix_sock"
29
30
31 int main(int argc, char *argv[])
32 {
33 int sockfd = -1;
34 sockfd = socket(AF_LOCAL,SOCK_STREAM,0);
35
36 int b_reuse = 1;
37 setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&b_reuse,sizeof(int));
38
39 struct sockaddr_un sun;
40 bzero(&sun,sizeof(sun));
41 sun.sun_family = AF_LOCAL;
42 strncpy(sun.sun_path,PATH,strlen(PATH));
43
44 if(!access(PATH,F_OK))unlink(PATH);
45
46 if(bind(sockfd,(struct sockaddr*)&sun,sizeof(sun))<0){
47 perror("bind");
48 exit(1);
49 }
50
51 if(listen(sockfd,BACKLOG)<0){
52 perror("listen");
53 exit(1);
54 }
55
56
57 char buf[BUFSIZ]={};
58
59 //创建集合
60 fd_set readfds,temp;
61 //初始化集合(清空集合)
62 FD_ZERO(&readfds);
63 FD_ZERO(&temp);
64 //把关心的文件描述符加入集合
65 FD_SET(0,&readfds);
66 FD_SET(sockfd,&readfds);
67
68 puts("IO多路复用服务器就绪");
69 int maxfd = sockfd;
70 int val = -1;
71 int i = -1;
72 ssize_t recv_t = -1;
73
74 int setfd = -1;
75 int input_t = -1;
76 int ret = -1;
77 int acceptfd = -1;
78 puts("输入方式:“客户端对应的文件描述符 内容");
79 while(1){
80 temp = readfds;
81 val = select(maxfd+1,&temp,NULL,NULL,NULL);
82 if(val<0){
83 perror("select");
84 exit(1);
85 }
86 //轮训判断那个文件描述符产生事件
87 for(i=0;i<maxfd+1;i++){
88 if(FD_ISSET(i,&temp)){
89 if(0==i){//是键盘输入产生事件
90 bzero(buf,sizeof(buf));
91 input_t = scanf("%d %s",&setfd,buf);
92 while(getchar()!='\n');
93 if(input_t !=2){
94 puts("输入错误!请按格式输入:fd+空格+消息内容");
95 continue;
96 }
97 if(!FD_ISSET(setfd,&readfds)){
98 puts("输入fd号错误,没有这个链接!");
99 continue;
100 }
101 //发出信息
102 do{
103 ret = send(setfd,buf,strlen(buf),0);
104 }while(ret<0 && EINTR==errno);
105 }
106 //如果是socket产生的套接字文件描述符
107 //那就说明是要建立连接
108 else if(sockfd == i){
109 acceptfd = accept(sockfd,NULL,NULL);
110 if(acceptfd < 0){
111 perror("accept");
112 exit(1);
113 }
114 //newfd加入集合
115 FD_SET(acceptfd,&readfds);
116 //更新maxfd(判断那个最大的文件描述符是那个)
117 maxfd = (maxfd > acceptfd) ? maxfd : acceptfd;
118 }
119 else//剩下的情况就是所有的客户端对应的newfd了
120 {
121 bzero(buf,sizeof(buf));
122 //i就是产生事件的客户端对应的fd
123 //接收消息
124 do{
125 recv_t = recv(i,buf,sizeof(buf),0);
126 }while(recv_t < 0 && EINTR==errno);
127 if(recv_t <= 0){
128 perror("客户端错误或关闭");
129 FD_CLR(i,&readfds);
130 close(i);
131 maxfd = (( i == maxfd) ? (--maxfd) : maxfd);
132 }
133 else{
134 printf("收到%d 消息:%s\n",i,buf);
135 }
136 }
137 }
138 }
139 }
140
141 close(sockfd);
142
143 return 0;
144 }
1 /*================================================================
2 * Copyright (C) 2020 hqyj Ltd. All rights reserved.
3 *
4 * 文件名称:02_域套接字客户端.c
5 * 创 建 者:Chens
6 * 创建日期:2020年04月26日
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/socket.h>
22 #include <sys/types.h>
23 #include <sys/wait.h>
24 #include <sys/un.h>
25
26 #define QUIT "quit"
27 #define BACKLOG 10
28 #define PATH "/tmp/20021/unix_sock"
29
30
31 int main(int argc, char *argv[])
32 {
33 int fd = -1;
34 fd = socket(AF_LOCAL,SOCK_STREAM,0);
35
36 struct sockaddr_un sun;
37 bzero(&sun,sizeof(sun));
38 sun.sun_family = AF_LOCAL;
39 strncpy(sun.sun_path,PATH,strlen(PATH));
40
41 if(access(PATH,F_OK|W_OK) <0){
42 puts("路径文件不存在或没有权限");
43 exit(1);
44 }
45
46 if( connect(fd,(struct sockaddr*)&sun,sizeof(sun))<0){
47 perror("connect");
48 exit(1);
49 }
50
51 puts("域套接字客户端OK!");
52
53
54 int ret =-1;
55 int fh =-1;
56 fd_set readfds;
57 int maxfd =-1;
58 struct timeval tv={1,0};
59 char buf[BUFSIZ]={};
60
61 puts("准备就绪-----------");
62 while(1){
63 FD_ZERO(&readfds);
64 FD_SET(0,&readfds);
65 FD_SET(fd,&readfds);
66 tv.tv_sec = 5;
67 tv.tv_usec= 0;
68 maxfd = fd;
69 fh = select(maxfd+1,&readfds,NULL,NULL,&tv);
70 if(fh<0){
71 perror("select");
72 exit(1);
73 }
74 if(FD_ISSET(0,&readfds)){//键盘输入了
75 bzero(buf,BUFSIZ);
76 do{
77 ret = read(0,buf,BUFSIZ-1);
78 }while(ret<0&&EINTR==errno);
79 if(ret <0){
80 perror("read");
81 continue;
82 }
83 if(!ret)continue;
84 if(write(fd,buf,strlen(buf))<0){
85 perror("write");
86 exit(1);
87 }
88 if(!strncasecmp(buf,QUIT,strlen(QUIT))){
89 printf("***客户端退出***\n");
90 break;
91 }
92 }
93 if(FD_ISSET(fd,&readfds)){//接收数据
94 bzero(buf,BUFSIZ);
95 do{
96 ret = read(fd,buf,BUFSIZ-1);
97 }while(ret<0 && EINTR==errno);
98 if(ret<0){
99 perror("接收");
100 continue;
101 }
102 if(!ret)break;
103 printf("已收到:%s \n",buf);
104 }
105 }
106 close(fd);
107
108 return 0;
109 }