IO多路复用

select的TCP服务器

主函数代码

  1 #include <stdio.h>
  2 #include <myhead.h>
  3 #include "select.h"
  4 #define PORT 9999     //1024~49151
  5 #define IP "192.168.124.17"//ifconfig查找本机的IP地址
  6 
  7 int main(int argc, const char *argv[])
  8 {
  9 
 10     //创建流式套接字文件
 11 
 12     int sfd = socket(AF_INET,SOCK_STREAM,0);
 13     if(sfd <0)
 14     {
 15         fprintf(stderr,"line:%d",__LINE__);
 16         perror("socket");
 17         return -1;
 18     }
 19     printf("创建流式套接字文件成功 sfd=%d __%d__\n",sfd,__LINE__);
 20 
 21     //允许端口号被快速重复使用
 22     int reuse = 1;
 23     if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))<0)
 24     {
 25         fprintf(stderr,"line:%d",__LINE__);
 26         perror("setsockopt");
 27         return -1;
 28 
 29     }
 30 
 31     //填充服务器的地址信息结构体,真实的地址信息结构体根据地址族制定
 32     //AF_INET --->man 7 ip
 33     struct sockaddr_in sin;
 34     sin.sin_family = AF_INET;//必须填AF_INET;
 35     sin.sin_port = htons(PORT);//端口号的网络字节序
 36     sin.sin_addr.s_addr = inet_addr(IP);
 37     //绑定服务器自身的地址信息--》必须绑定
 38     if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
 39     {
 40         fprintf(stderr,"line:%d",__LINE__);
 41         perror("bind");
 42         return -1;
 43     }
 44     printf("bind success __%d__\n",__LINE__);
 45     //将套接字设置为被动监听状态
 46     if(listen(sfd,128)<0)
 47     {
 48         fprintf(stderr,"line:%d",__LINE__);
 49         perror("listen");
 50         return -1;
 51     }
 52     printf("listen success __%d__\n",__LINE__);
 53 
 54     //创建一个读集合
 55     //由于读集合中的成员是一个+整形数组,若不初始化则集合中为随机值
 56     //必须清空
 57     fd_set readfds,tempfds;
 58     FD_ZERO(&readfds);
 59 
 60     //要监测的文件描述符加入到读集合中
 61     FD_SET(0,&readfds);
 62     FD_SET(sfd,&readfds);
 63     int maxfd = sfd;
 64     int s_res;
 65     char buf[128];
 66     ssize_t res;
 67     int newfd;
 68     struct sockaddr_in saveCin[1024-3];//将连接成功的客户端信息存储到newfd-3的下标位置
 69 
 70     while(1)
 71     {
 72         tempfds = readfds;
 73         //监测集合中的文件描述符是否准备就绪
 74         s_res = select(maxfd+1,&tempfds,NULL,NULL,NULL);
 75         if(s_res <0)
 76         {
 77             fprintf(stderr,"line:%d",__LINE__);
 78             perror("select");
 79             return -1;
 80         }
 81         else if(0 == s_res)
 82         {
 83             printf("time out...\n");
 84             break;
 85         }
 86         //判断集合中剩下的文件描述符是谁
 87         for(int i =0 ;i<=maxfd;i++)
 88         {
 89 
 90             if(FD_ISSET(i,&tempfds)==0)
 91             {
 92                 continue;
 93             }
 94 
 95             if(0==i)
 96             {
 97                 printf("触发键盘输入事件\n");
 98                 deal_KeyboarEvent(readfds,saveCin);
 99             
100             }
101             else if(sfd == i)
102             {
103                 printf("触发客服端连接事件\n");
104                 deal_CliConnectEvent(sfd,saveCin,&readfds,&maxfd);
105                         }
106             else
107 
108             {
109                 printf("触发客服端交互事件\n");
110                 deal_CliTalkEvent(i,saveCin,&readfds,&maxfd);
111                         }
112         }
113     }
114 
115     //关闭文件描述符
116     close(sfd);
117     return 0;
118 }                                                                                                                                        
~                                                                                                                                            
~                                                                                                                                            
~                                                                                                                                            
~                                                                                                                                            
~                                                                                                                                            

功能函数

 1 #include <stdio.h>
 2 #include <myhead.h>
 3 
 4 /*
 5  *function:处理客服端交互事件
 6  *@param[in]
 7  *@parm[out]
 8  *@return
 9  *
10  */
11 int deal_CliTalkEvent(int talkfd,struct sockaddr_in saveCin[],fd_set *preadfds,int *pmaxfd  )
12 {
13     char buf[128]="";
14     bzero(buf,sizeof(buf));
15 
16     //接收
17     ssize_t res = recv(talkfd ,buf,sizeof(buf),0);
18     if(res<0)
19     {
20         fprintf(stderr,"line:%d",__LINE__);
21         perror("recv");
22         return -1;
23     }
24     else if(0==res)
25     {
26         printf("[%s:%d] 客服端下线 newfd=%d  __%d__\n",\
27                 inet_ntoa(saveCin[talkfd-3].sin_addr),ntohs(saveCin[talkfd-3].sin_port),talkfd,__LINE__);
28         close(talkfd);
29         FD_CLR(talkfd,preadfds); //将newfd从readfds集合中剔除
30 
31         for(;*pmaxfd>0;*pmaxfd--)
32         {
33             if(FD_ISSET(*pmaxfd,preadfds))
34             {
35                 break;
36             }
37         }
38         return -1;
39     }
40     printf("[%s:%d] 客服端连接成功 newfd=%d %s __%d__\n",\
41             inet_ntoa(saveCin[talkfd-3].sin_addr),ntohs(saveCin[talkfd-3].sin_port),talkfd,buf,__LINE__);
42 
43     //发送
44     strcat(buf,"*~*");
45     if( send(talkfd,buf,sizeof(buf),0)<0)
46     {
47         fprintf(stderr,"line:%d",__LINE__);
48         perror("send");
49         return -1;
50 
51     }
52     printf("send success __%d__\n",__LINE__);
53 
54     return 0;
55 
56 }
57 /*
58  *function:处理客服端连接事件
59  *@param[in]
60  *@parm[out]
61  *@return
62  *
63  */
64 int deal_CliConnectEvent(int psfd,struct sockaddr_in* saveCin,fd_set* preadfds,int *pmaxfd)
65 {
66     struct sockaddr_in cin;
67     socklen_t addrlen = sizeof(cin);
68 
69     //会从已完成连接队列的对头获取一个客户端的信息,生成一个新的文件描述符
70     //accept(sfd,NULL,NULL);
71     int newfd = accept(psfd,(struct sockaddr*)&cin,&addrlen);
72     if(newfd <0)
73     {
74         fprintf(stderr,"line:%d",__LINE__);
75         perror("accept");
76         return -1;
77     }
78 
79     printf("[%s:%d] 客服端连接成功 newfd=%d __%d__\n",\
80             inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd,__LINE__);
81 
82     saveCin[newfd - 3] =cin;
83     FD_SET (newfd ,preadfds);  //将生成的newfd添加到集合中
84     *pmaxfd = newfd>*pmaxfd?newfd:*pmaxfd;//更新maxfd
85 
86     return 0;
87 }
88 /*
89  *function:键盘输入事件
90  *@param[in]
91  *@parm[out]
92  *@return
93  *
94  */
95 int deal_KeyboarEvent(fd_set preadfds,struct sockaddr_in psaveCin[])
96 
97 {
98 
99     int sndfd;
00     char buf[128];
01     int res = scanf("%d %s",&sndfd,buf);//从终端输入一个客户端对应的文件描述符
02     while (getchar()!='\n' );
03     if(res != 2)
04     {
05 
06         printf("请输入正确的格式:fd string\n");
07         return -1;
08 
09     }
10     if(sndfd<0||sndfd>1023||FD_ISSET(sndfd,&preadfds)== 0)
11     {
12         printf("请输入正确的文件描述符\n");
13         return -1;
14 
15     }
16     if(send(sndfd,buf,sizeof(buf),0)<0)
17     {
18         perror("send");
19         return -1;
20 
21     }
22     printf("发送给[%s:%d] fd=%d客服端成功  __%d__\n",\
23             inet_ntoa(psaveCin[sndfd-3].sin_addr),ntohs(psaveCin[sndfd-3].sin_port),sndfd,__LINE__);
24     return 0;
25 }                                                                                                                        
                                                                                                                            
                                                                                                                            
                                                                                                                            
                                                                                                                            

现象


poll的客户端
 1 #include <stdio.h>
 2 #include <myhead.h>
 3 
 4 #define CLI_PORT 7777  //1024~49151
 5 #define CLI_IP "192.168.124.17"//ifconfig查找本机的IP地址
 6 
 7 
 8 
 9 int main(int argc, const char *argv[])
10 {
11     if(argc <3)
12     {
13         printf("请在命令行传入服务器的port和ip\n");
14         return -1;
15     }
16 
17     //创建流式套接字
18 
19     int cfd = socket(AF_INET,SOCK_STREAM,0);
20     if(cfd <0)
21     {
22         fprintf(stderr,"line:%d",__LINE__);
23         perror("socket");
24         return -1;
25     }
26     printf("创建流式套接字文件成功 cfd=%d __%d__\n",cfd,__LINE__);
27     //绑定客服端自身的地址信息结构体--->非必须绑定
28     //若不绑定,则操作系统会自动给客服端绑定客服端所运行主机的IP及随机端口:
29     //49152~65535
30 
31     //填充服务器的地址信息,给connect函数连接服务器的时候使用
32     struct sockaddr_in sin;
33     sin.sin_family = AF_INET;//必须填AF_INET;
34     sin.sin_port = htons(atoi(argv[1]));//服务器要绑定的端口号
35     sin.sin_addr.s_addr = inet_addr(argv[2]);//服务器绑定的IP地址
36     //连接指定的服务器
37     if(connect(cfd,(struct sockaddr*)&sin,sizeof(sin))<0)
38     {
39         fprintf(stderr,"line:%d",__LINE__);
40         perror("connect");
41         return -1;
42     }
43     printf("connect server[%s:%s] 成功 __%d__\n",argv[2],argv[1],__LINE__);
44 
45 
46     //创建集合
47     struct pollfd fds[2];
48     fds[0].fd = 0;      //指定监测0号文件描述符
49 
50     fds[0].events = POLLIN;  //指定监测读事件
51 
52     fds[1].fd = cfd;
53     fds[1].events = POLLIN;
54 
55 
56     char buf[128]= "";
57     ssize_t res;
58     int p_res;
59     while(1)
60     {
61 
62         //poll,让内核监测集合中是否有文件描述符准备就绪
63         p_res = poll(fds,2,-1);
64         if(p_res<0)
65         {
66             fprintf(stderr,"line:%d",__LINE__);
67             perror("poll");
68             return -1;
69         }
70         else if(0 == p_res)
71         {
72             printf("time out ...\n");
73             break;
74         }
75         //能运行到当前位置,则代表集合中有文件描述符产生事件了  
76         //需要遍历判断集合中文件描述符实际产生的事件中是否有POLLIN事件
77         //需要将revents & POLLIN判断结构是否为0
78         if((fds[0].revents&POLLIN))
79         {
80             fgets(buf,sizeof(buf),stdin);
81             buf[strlen(buf)-1]='\0';
82 
83 
84 
85             //发送
86             if( send(cfd,buf,sizeof(buf),0)<0)
87             {
88                 fprintf(stderr,"line:%d",__LINE__);
89                 perror("send");
90                 return -1;
91 
92             }
93             printf("send success __%d__",__LINE__);
94 
95         }
96         if(fds[1].revents &POLLIN)
97         {
98             //接收
99             bzero(buf,sizeof(buf));
00             res = recv(cfd,buf,sizeof(buf),0);
01             if(res<0)
02             {
03 
04 
05                 fprintf(stderr,"line:%d",__LINE__);
06                 perror("recv");
07                 return -1;
08             }
09             else if(0==res)
10             {
11                 printf("服务器下线 __%d__",__LINE__);
12                 break;
13             }
14             printf(":%s __%d__\n",buf,__LINE__);
15 
16         }
17 
18 
19     }
20     //关闭文件描述符
21     close(cfd);
22     return 0;
23 }                                                                                                  
                                                                                                      

现象

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值