(四) 用poll实现TCP服务端

来源:互联网 发布:在vb中chr是什么意思 编辑:程序博客网 时间:2024/05/20 20:56

1.首先,大概说一下poll函数的工作大概:(包含在#include<poll.h>当中)

        poll 是通过监听一个结构体变量来对 文件描述符进行监听的(当然,socket也算是一个文件描述符)

        这个结构体的大概结构是:

       (!!如果不想了解poll工作原理的。可以直接拉下去看代码)

struct pollfd   //这个结构体一般会被定义为结构体数组{   int fd;        //要监听的文件描述符   short events;  //期待fd发生的事件   ,其中 events把他设置成 POLLIN就够用了,表示检测该fd有没有可读数据   short revents; //fd实际发生的事件};

而poll()是通过监听上述结构体数组 来监听一堆文件描述符的
2.再来了解poll()函数详细信息:
    (一)首先是他的输入参数:
            int poll(struct pollfd *name,int num,int timeout);
              一共有三个,分别是监听的结构体数组的数组名,实际监听着多少个结构体数组成员,阻塞时间控制参数。
             其中timeout参数 ==0,是非阻塞,== -1 是阻塞,>0是阻塞 xx毫秒
   (二)然后是他的返回值
          poll()函数的返回值   ,表示同时有响应的文件描述符个数。
接下来看看 poll()的大致使用例子:

3.给出代码:(在这之前先看看代码的大致实现逻辑)
首先把 监听套接字sock 和 标准输入 先放到 监听的结构体数组中
while(1)循环是必须的,在循环中,用poll()进行监听,然后判断是sock是否响应,是的话,就调用accept来获取连接进来的客户端的信息,并把接收到的socket放到结构体数组中。否则就继续往下(判断是否标准输入响应,是就读信息),再往下,判断是哪些客户端socket发生可读响应,有的话,就读。

//服务端#include"myhead.h"#define CLI_NUM 10char rbuf[50];char wbuf[50];char ipbuf[50];int recv_num;struct pollfd pollfd[CLI_NUM];void write_all(char *wbuf,int max){int i = 2;for(i;i<(max+2);i++){write(pollfd[i].fd,wbuf,50);}}int main(){int sockfd;int size,port;int new_sock;int on = 1;int i;int max = 0;int ret;struct sockaddr_in saddr;struct sockaddr_in caddr;size = sizeof(struct sockaddr_in);saddr.sin_family = AF_INET;saddr.sin_port = htons(8888);saddr.sin_addr.s_addr = htonl(INADDR_ANY);sockfd = socket(AF_INET,SOCK_STREAM,0);setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));bind(sockfd,(struct sockaddr*)&saddr,sizeof(struct sockaddr));listen(sockfd,10);//init pollfdfor(i=0;i<10;i++)    //把pollfd置 -1,当然不一定是-1,只是文件描述符不可能为负,所以就置成一个负数{pollfd[i].fd = -1;}pollfd[0].fd = sockfd;pollfd[0].events = POLLIN;pollfd[1].fd = STDIN_FILENO;pollfd[1].events = POLLIN;int len = sizeof(struct sockaddr);while(1){puts("waiting poll");ret = poll(pollfd,max+2,-1);            //ret表示发生响应的文件描述符个数,接下来就要对这些响应的文件描述符都处理一次if(ret ==0){perror("timeout");exit(-1);}if((pollfd[0].revents& POLLIN) == POLLIN){puts("waiting accept");new_sock = accept(sockfd,(struct sockaddr*)&caddr,&len);write(new_sock,"get",4);if(new_sock>0){//fcntl(new_sock,F_SETFL,fcntl(new_sock,F_GETFL)|O_NONBLOCK);printf("newfd =%d\n",new_sock);i = 2;for(i;i<CLI_NUM;i++){if(pollfd[i].fd != -1)continue;else if(pollfd[i].fd == -1){pollfd[i].fd = new_sock;pollfd[i].events = POLLIN;max +=1;printf("max=%d\n",max);ret-=1;                    //每处理一个就 -1if(ret <= 0 )              //要是响应的文件描述符都处理完了,就退出循环。{break;}}}}}if((pollfd[1].revents & POLLIN) == POLLIN)  //是否从键盘有信息读入{bzero(wbuf,50);scanf("%s",wbuf);write_all(wbuf,max);   ret-=1;                      //每处理一个就 -1if(ret<=0)continue;}for(i=2;i<CLI_NUM && pollfd[i].fd!=-1;i++)  //接收来自其他客户端的信息{if((pollfd[i].revents & POLLIN)==POLLIN){puts("enter read");bzero(rbuf,50);recv_num = recv(pollfd[i].fd,rbuf,50,0);if(recv_num == 0)                          //当recv_num 为0,表示客户端已经退出了{printf("client close\n");close(pollfd[i].fd);pollfd[i].fd = -1;                 //既然客户端退出了,那原本该客户端占着的位置就重新置 -1continue;}printf("%s,from:%d\n",rbuf,pollfd[i].fd);write_all(rbuf,max);ret -=1;               if(ret<=0)break;}}}}

接下来是客户端:
//客户端相对而言就比较简单
#include"myhead.h"char rbuf[50];char wbuf[50];char ipbuf[50];int main(){int sockfd;int ret,port;struct pollfd pollfd[2];struct sockaddr_in saddr;int size = sizeof(struct sockaddr_in);bzero(&saddr,size);saddr.sin_family = AF_INET;saddr.sin_port = htons(8888);saddr.sin_addr.s_addr = inet_addr("192.168.152.128");sockfd = socket(AF_INET,SOCK_STREAM,0);ret=connect(sockfd,(struct sockaddr*)&saddr,sizeof(struct sockaddr));if(ret == 0){inet_ntop(AF_INET,(void*)&saddr.sin_addr.s_addr,ipbuf,50);port = ntohs(saddr.sin_port);printf("%s,%d\n",ipbuf,port);}pollfd[0].fd = STDIN_FILENO;pollfd[0].events = POLLIN;pollfd[1].fd = sockfd;pollfd[1].events = POLLIN;while(1){poll(pollfd,2,-1);if((pollfd[0].revents & POLLIN)==POLLIN){puts("message from keyboard");bzero(wbuf,50);scanf("%s",wbuf);write(sockfd,wbuf,50);}if((pollfd[1].revents & POLLIN)==POLLIN){bzero(rbuf,50);read(sockfd,rbuf,50);printf("%s\n",rbuf);}}return 0;}














0 0