io+day5

1,select服务端

1 #include
  2 
  3 #define PORT 8888              //端口号
  4 #define IP "192.168.228.165"       //IP地址
  5 
  6 
  7 int main(int argc, const char *argv[])
  8 {
  9     //1、创建用于接受连接的套接字
 10     int sfd = socket(AF_INET, SOCK_STREAM, 0);
 11     if(sfd == -1)
 12     {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
 13         perror("socket error");
 14         return -1;
 15     }
 16 
 17     printf("socket success sfd = %d\n", sfd);    //4
 18 
 19 
 20     //设置端口号快速重用
 21     int reuse = 1;
 22     if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1)
 23     {
 24         perror("setsockopt error");
 25         return -1;
 26     }
 27     printf("设置端口快速重用成功 _%d_ %s_ %s_\n", __LINE__, __FILE__, __func__);
 28 
 29 
 30 
 31 
 32 
 33     //2、绑定IP地址和端口号
 34     //2.1、填充要绑定的地址信息结构体
 35     struct sockaddr_in sin;
 36     sin.sin_family     = AF_INET;         //表明是ipv4
 37     sin.sin_port     = htons(PORT);        //端口号
 38     sin.sin_addr.s_addr = inet_addr(IP);     //IP地址
 39 
 40     //2.2、绑定
 41     if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin))==-1)
 42     {
 43         perror("bind error");
 44         return -1;
 45     }
 46     printf("bind success _%d_ %s_ %s_\n", __LINE__, __FILE__, __func__);
 47 
 48     //3、将套接字设置成被动监听状态
 49     if(listen(sfd, 128) == -1)
 50     {
 51         perror("listen error");
 52         return -1;
 53     }
 54 
 55     printf("listen success _%d_ %s_ %s_\n", __LINE__, __FILE__, __func__);
 56 
 57     //4、阻塞等待客户端连接请求,如果有新的客户端连接,则创建一个新的用于通信的套接字
 58     //4.1、定义客户端地址信息结构体
 59     struct sockaddr_in cin;             //客户端地址信息结构体
 60     cin.sin_family     = AF_INET;
 61     socklen_t socklen = sizeof(cin);          //客户端地址信息的大小
 62 
 63 
 64     定义一个用于检测文件描述符的集合
 65     fd_set readfds, tempfds;                          //在栈区定义
 66 
 67     清空容器中的内容
 68     FD_ZERO(&readfds);
 69     将要检测的文件描述符放入集合中
 70     FD_SET(sfd, &readfds);           //将sfd文件描述符放入
 71     FD_SET(0, &readfds);             //将0号文件描述符放入
 72 
 73 
 74 
 75     //定义一个容器
 76     char buf[128] = "";
 77     int res = 0;             //接收select的返回值
 78     int newfd = -1;          //存放用于最新连接客户端的套接字
 79     int maxfd = sfd;          //定义控制select函数中最大文件描述符
 80 
 81     struct sockaddr_in saveCin[1024];       //用于存放客户端地址信息结构体
 82 
 83 
 84     while(1)
 85     {
 86         将集合内容复制一份
 87         tempfds = readfds;
 88 
 89         使用select阻塞等待集合中的文件描述符有事件产生
 90         res = select(maxfd+1, &tempfds, NULL, NULL, NULL);
 91         if(res == -1)
 92         {
 93             perror("select error");
 94             return -1;
 95         }else if(res == 0)
 96         {
 97             printf("time out\n");
 98             return -1;
 99         }
100 
101 
102         //遍历所有集合中文件描述符
103         for(int i=0; i<=maxfd; i++)
104         {
105             //判断当前i是否在集合中,如果不在,直接判断下一个
106             if(!FD_ISSET(i, &tempfds))
107             {
108                 continue;
109             }
110 
111             判断sfd是否还在集合中
112             if( i == sfd)
113             {
114                 //4.2、阻塞接收客户端的链接请求,并且获取客户端的地址信息
115                 newfd = accept(sfd, (struct sockaddr*)&cin, &socklen);
116                 if(newfd == -1)
117                 {
118                     perror("accept error");
119                     return -1;
120                 }
121                 printf("accept success _%d_ %s_ %s_\n", __LINE__, __FILE__, __func__);
122 
123                 将newfd放入readfds中
124                 FD_SET(newfd , &readfds);
125 
126                 //更新maxfd
127                 if(newfd > maxfd)
128                 {
129                     maxfd = newfd;
130                 }
131 
132                 //将最新的客户端套接字放入数组的下标为new的位置
133                 saveCin[newfd] = cin;
134                 printf("newfd = %d\n", newfd);
135 
136             }else if(i == 0 )    //判断是否是终端输入
137 
138             {
139                 char buf1[1000] = "";
140 
141                 bzero(buf, sizeof(buf));
142                 //从终端获取数据
143                 fgets(buf, sizeof(buf), stdin);       //从终端获取数据
144                 buf[strlen(buf)-1]='\0';
145                 printf("触发终端输入事件:%s\n", buf);
146 
147                sprintf(buf1, "%s%s", "系统消息:", buf);
148 
149                 //将数据发送给所有客户端
150                 for(int j=4; j<=maxfd; j++)
151                 {
152                     send(j, buf1,sizeof(buf1), 0);
153                 }
154 
155 
156             }else
157             {
158                 //5、收发数据使用newfd完成通信
159                 char buf[128] = "";
160                 //清空字符串
161                 bzero(buf, sizeof(buf));
162                 int ret = recv(i, buf, sizeof(buf), 0);        //从套接字中读取客户端发来的消息
163 
164                 //判断收到的结果
165                 if(ret == 0)
166                 {
167                     printf("客户端已经下线\n");
168                     close(i);             //关闭通信的套接字
169 
170                     将当前的文件描述符从集合中删除
171                     FD_CLR(i, &readfds);
172 
173                     更新maxfd
174                     for(int j=maxfd; j>=0; j--)
175                     {
176                         //判断当前的j是否在集合中,如果在,则为maxfd
177                         if(FD_ISSET(j, &readfds))
178                         {
179                             maxfd = j;
180                             break;
181                         }
182                     }
183 
184                     continue;           //继续判断下一个
185                 }else if(ret < 0)
186                 {
187                     perror("recv error");
188                     return -1;
189                 }
190 
191                 printf("[%s:%d]:%s\n", inet_ntoa(saveCin[i].sin_addr), ntohs(saveCin[i].sin_port), buf);
192 
193                 //将读取的信息,加上一些字符发送回去
194                 strcat(buf, "*_*");
195                 send(i, buf, sizeof(buf), 0);
196 
197 
198             }
199         }
200 
201     }
202 
203 
204 
205     //6、关闭所有套接字
206     close(sfd);               //关闭监听
207 
208     return 0;
209 }
~                                                                                                                          
 #include 
  2 
  3 #define SERPORT 8888              //服务器端口号
  4 #define SERIP "192.168.228.165"       //服务器IP地址
  5 
  6 int main(int argc, const char *argv[])
  7 {
  8     //创建用于通信的套接字
  9     int cfd = socket(AF_INET,SOCK_STREAM,0);
 10     if(cfd == -1)
 11     {
 12         perror("socket error");
 13         return -1;
 14     }
 15 
 16     //连接服务器
 17     ///填充服务器地址信息结构体
 18     struct sockaddr_in sin;
 19     sin.sin_family = AF_INET;
 20     sin.sin_port = htons(SERPORT);
 21     sin.sin_addr.s_addr = inet_addr(SERIP);
 22 
 23     ///连接服务器
 24     if(connect(cfd,(struct sockaddr *)&sin,sizeof(sin)) == -1)
 25     {
 26         perror("connect error");
 27         return -1;
 28     }
 29 
 30     //创建用于检测文件描述符的集合
 31     fd_set readfds,tempfds;
 32 
 33     //清空集合
 34     FD_ZERO(&readfds);
 35 
 36     //将要检测的文件描述符放入集合中
 37     FD_SET(cfd,&readfds);
 38     FD_SET(0,&readfds);
 39 
 40     int res = 0;    //接收select的返回值
 41     int maxfd = cfd;  //集合中值最大的文件描述符
 42 
 43     //向服务器进行数据的收发
 44     char buf[128] = "";
 45     int ret = 0;    //接收recv的返回值
 46     while(1)
 47     {
 48         tempfds = readfds;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
 49 
 50         res = select(maxfd+1,&tempfds,NULL,NULL,NULL);
 51         if(res == -1)
 52         {
 53             perror("select error");
 54             return -1;
 55         }else if(res == 0)
 56         {
 57             printf("time out\n");
 58             return -1;
 59         }
 60 
 61         //遍历集合中所有的文件描述符
 62         for(int i = 0;i <= maxfd;i++)
 63         {
 64             //判断当前文件描述符是否在集合中
 65             if(!FD_ISSET(i,&readfds))
 66             {
 67                 continue;
 68             }
 69 
 70 
 71             //判断0号文件描述符是否还在集合中
 72             if(0 == i)
 73             {
 74                 //从标准输入中读取数据
 75                 fgets(buf,sizeof(buf),stdin);
 76                 buf[strlen(buf)-1] == 0;
 77 
 78                 //将数据发送到服务器
 79                 if(send(cfd,buf,sizeof(buf),0) == -1)
 80                 {
 81                     perror("send error");
 82                     return -1;
 83                 }
 84 
 85             }else if(cfd == i)     //判断cfd是否还在集合中
 86             {
 87                 //接收来自服务器的消息
 88                 ret = recv(cfd,buf,sizeof(buf),0);
 89                 if(ret == -1)
 90                 {
 91                     perror("recv error");
 92                     return -1;
 93                 }else if(ret == 0)
 94                 {
 95                     printf("服务器已关闭\n");
 96                     return -1;
 97                 }
 98 
 99                 printf("服务器消息:%s\n",buf);
100             }
101         }
102     }
103 
104     //关闭文件描述符
105     close(cfd);
106 
107     return 0;
108 }

效果图

io+day5_第1张图片

poll客户端

  1 #include 
  2 
  3 #define IP "192.168.228.165"
  4 #define PORT 8888
  5 
  6 int main(int argc, const char *argv[])
  7 {
  8     //创建用于连接的套接字
  9     int sfd = socket(AF_INET,SOCK_STREAM,0);
 10     if(sfd == -1)
 11     {
 12         perror("socket error");
 13         return -1;
 14     }
 15 
 16     //绑定服务器IP和端口号
 17     ///填充服务器地址信息结构体
 18     struct sockaddr_in sin;
 19     sin.sin_family = AF_INET;
 20     sin.sin_port = htons(PORT);
 21     sin.sin_addr.s_addr = inet_addr(IP);
 22 
 23     ///绑定
 24     if(bind(sfd,(struct sockaddr *)&sin,sizeof(sin)) == -1)
 25     {
 26         perror("bind error");
 27         return -1;
 28     }
 29     printf("bind success\n");
 30 
 31     //将连接用套接字设置为被动监听状态
 32     if(listen(sfd,128) == -1)
 33     {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
 34         perror("listen error");
 35         return -1;
 36     }
 37     printf("listen success\n");
 38 
 39     //定义一个集合管理sfd和打开的通信用文件描述符
 40     struct pollfd fds[1024];
 41     int maxfd = 0;
 42 
 43 
 44     //手动放入sfd
 45     fds[0].fd = sfd;
 46     fds[0].events = POLLIN;     //表明为读事件
 47 
 48     //将fds中其余元素初始化为-1
 49     for(int i = 4;i <= 1024;i++)
 50     {
 51         fds[i].fd = -1;
 52     }
 53 
 54     //填充客户端地址信息结构体
 55     struct sockaddr_in cin;
 56     cin.sin_family = AF_INET;
 57     socklen_t socklen = sizeof(cin);
 58 
 59 
 60     char cbuf[128] = "";  //给客户端用的容器
 61     int nfd;
 62     int res = 0;  //接收poll返回的结果
 63     while(1)
 64     {
 65         res = poll(fds,maxfd+1,-1);
 66         if(res == -1)
 67         {
 68             perror("select");
 69             return -1;
 70         }
 71         else if(res == 0)
 72         {
 73             continue;;
 74         }
 75         else if(res > 0)                //说明检测到了有文件描述符对应的缓冲区的数据发生了改变
 76         {
 77             if(fds[0].revents ==  POLLIN)    //表明有新的客户连接进来了
 78             {
 79                 int nfd = accept(sfd,(struct sockaddr*)&cin,&socklen);  //阻塞在此处,直到有客户端连接上来
 80                 if(nfd == -1)   //增加这些错误的判断非常重要,可以帮助找到出现问题的地方
 81                 {
 82                     perror("accept");
 83                     return -1;
 84                 }
 85 
 86                 //将新的文件描述符加入到集合中
 87                 for(int i = 1;i < 1024;i++)
 88                 {
 89                     if( fds[i].fd == -1)
 90                     {
 91                         fds[i].fd = nfd;
 92                         fds[i].events = POLLIN;
 93                         break;
 94                     }
 95                 }
 96 
 97                 //更新最大的文件描述符
 98                 if(nfd > maxfd)
 99                 {
100                     maxfd = nfd;
101                 }
102             }
103 
104             for(int i = 1;i <= maxfd;i++)     //轮询客户端对应的文件描述符
105             {
106                 if(fds[i].revents == POLLIN)  //说明此文件描述符对应的客户端发送来了数据
107                 {
108                     int ret = read(fds[i].fd,cbuf,sizeof(cbuf));
109                     if(ret == -1)
110                     {
111                         perror("read");
112                         exit(-1);
113                     }
114                     else if(ret == 0)
115                     {
116                         printf("client closed\n");
117                         close(fds[i].fd);   //关闭对应的文件描述符
118                         fds[i].fd = -1;   //在fds中清空对应的文件描述符
119                     }
120                     else if(ret > 0)
121                     {
122                         printf("read buf = %s\n",cbuf);
123                         write(fds[i].fd,cbuf,strlen(cbuf)+1);
124                     }
125 
126 
127                 }
128             }
129         }
130     }
131     //关闭所有套接字
132     close(sfd);
133 
134     return 0;
135 
1 #include
  2 #define SERIP "192.168.228.165"
  3 #define SERPORT 8888
  4 #define CLIIP "192.168.228.165"
  5 #define CLIPORT 6666
  6 
  7 int main(int argc, const char *argv[])
  8 {
  9     //1、创建客户端用于通信的套接字
 10     int cfd = socket(AF_INET, SOCK_STREAM, 0);
 11     if(cfd == -1)
 12     {
 13         perror("socket error");
 14         return -1;
 15     }
 16     printf("cfd = %d\n", cfd);                //3
 17 
 18 
 19     //2、绑定(可选)
 20     //2.1、填充地址信息结构体
 21     struct sockaddr_in cin;
 22     cin.sin_family     = AF_INET;            //使用的是ipv4通信
 23     cin.sin_port     = htons(CLIPORT);       //服务器端口号
 24     cin.sin_addr.s_addr     = inet_addr(CLIIP);       //服务器IP地址
 25     //2.2、绑定工作
 26     if(bind(cfd, (struct sockaddr*)&cin, sizeof(cin)) == -1)
 27     {
 28         perror("bind error");
 29         return -1;
 30     }
 31     printf("bind success\n");
 32 
 33 
 34     //3、连接服务器
 35     //3.1、填充服务器地址信息结构体
 36     struct sockaddr_in sin;
 37     sin.sin_family     = AF_INET;            //使用的是ipv4通信
 38     sin.sin_port     = htons(SERPORT);       //服务器端口号
 39     sin.sin_addr.s_addr     = inet_addr(SERIP);       //服务器IP地址                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
 40 
 41     //3.2、连接服务器
 42     if(connect(cfd, (struct sockaddr*)&sin, sizeof(sin)) ==-1)
 43     {
 44         perror("connect error");
 45         return -1;
 46     }
 47     printf("connect success\n");
 48 
 49     //4、收发数据(send、recv、read、write)
 50     char buf[128] = "";
 51     char rbuf[128] = "";
 52 
 53     定义一个集合管理0号文件描述符和cfd
 54     struct pollfd fds[2];
 55 
 56     //将0号文件描述符放入
 57     fds[0].fd = 0;
 58     fds[0].events = POLLIN;          //表明要进行读事件
 59 
 60     //将cfd放入集合
 61     fds[1].fd = cfd;
 62     fds[1].events = POLLIN;
 63 
 64     int res = 0;     //接收poll返回的结果
 65 
 66 
 67     while(1)
 68     {
 69         res = poll(fds, 2, -1);          //第三个参数如果是负数,表明一直等待
 70         if(res == -1)
 71         {
 72             perror("poll error");
 73             return -1;
 74         }else if(res == 0)
 75         {
 76             printf("time out\n");
 77             return -1;
 78         }
 79 
 80 
 81         bzero(buf, sizeof(buf));
 82         bzero(rbuf, sizeof(rbuf));
 83 
 84 
 85 
 86         //判断是否是发送数据满足条件
 87         if(fds[0].revents == POLLIN)
 88         {
 89             fgets(buf, sizeof(buf), stdin);       //从标准输入中读取数据
 90             buf[strlen(buf)-1] = '\0';
 91 
 92             //将数据发送给服务器
 93             send(cfd, buf, sizeof(buf), 0);
 94 
 95             //如果输入的是quit则退出
 96             if(strcmp(buf,"quit") == 0)
 97             {
 98                 break;
 99             }
100         }
101 
102 
103 
104         //判断是否为接收数据满足条件
105         if(fds[1].revents == POLLIN)
106         {
107 
108             //接收服务器发送来的消息
109             int res = recv(cfd, rbuf, sizeof(rbuf), 0);
110             if(res == 0)
111             {
112                 printf("服务器已经关闭\n");
113                 break;
114             }
115             printf("rbuf = %s\n", rbuf);
116         }
117 
118     }
119 
120     //5、关闭客户端套接字
121     close(cfd);
122 
123 
124     return 0;
125 }
126 
~                                                                                

io+day5_第2张图片

你可能感兴趣的:(c语言)