参考书籍:linux高性能服务器编程,是个人对看书的总结,上文一致
poll系统调用和select类似,(个人认为poll和select掌握一个就好了)也是在指定时间内轮询一定数量的文件描述符,以测试其中是否有就绪者。
关于poll的原型
#include <poll.h>
int poll(struct pollfd* fds,nfds_t nfds,int timeout);
(1)fds参数是一个pollfd结构类型的数组,它指定我们所有的感兴趣的文件描述符上发生的可读可写和异常等事件。pollfd结构体的定义如下:
struct pollfd
{
int fd;//文件描述符
short events;//注册的事件,在这里声明我们要关心的事件是什么
short revents;//实际发生的事件,由内核填充,这个我们是不用去管的
}
poll有许多的事件类型,我目前接触或者说用到的是
POLLIN,数据可读(包括普通数据和优先数据)
POLLRDHUP,TCP连接被对方关闭,或者对方关闭了写操作,他由GUN引入
POLLHUP,挂起,比如管道的写端被关闭后,读端描述符上将收到POLLHUP事件。
通常,应用程序需要recv调用的返回值来区分socket上面接收到的是有效数据还是对方关闭连接的请求,并做相应的处理。但是poll可以通过POLLRDHUP事件来进行判断。
(2)对于nfds,他制定的是被监听事件集合fds的大小。
(3)对于timeout他的单位是毫秒制定的是poll的超时值,当timeout是-1,poll调用将一直阻塞,直到某个事件发生;当timeout为0,那么poll调用将立即返回。
poll返回值的含义和selec相同,,如果超时且没有任何描述符就绪,那么返回0,如果失败则返回-1,如果成功那么就返回就绪文件描述符的总数,如果在等待期间接收到了信
号那就返回-1。
用poll监听其他进程发来信息的代码
#include <stdio.h>
#include <assert.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <poll.h>
int main()
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
assert(sockfd!=-1);
struct sockaddr_in saddr,caddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(6500);
saddr.sin_addr.s_addr = inet_addr("192.168.1.11");
int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
assert(res!=-1);
int ret = listen(sockfd,5);
assert(ret!=-1);
int len = sizeof(caddr);
int c = accept(sockfd,(struct sockaddr*)&caddr,&len);
struct pollfd rdset;//read
//init
rdset.fd = c;//choose
rdset.events = POLLIN;
rdset.revents = 0;
while(1)
{
int n = poll(&rdset,1,0);
if(n<0)
{
break;
}
if(n>0)
{
char buff[128] = {0};
int ret = recv(c,buff,127,0);
if(ret<=0)
{
printf("over!");
break;
}
printf("%s",buff);
}
}
return 0;
}
相应的客户端代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc,char *argv[])
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
assert(sockfd!=-1);
struct sockaddr_in saddr;//虽然操作一样,但是客户端是为了去链接服务端
memset(&saddr,0,sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(6500);//转换成大端
saddr.sin_addr.s_addr = inet_addr("192.168.1.11");
//要用就必须先运行起来
int res = connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//链接到服务端上面
assert(res!=-1);
//执行到这个地方说明三次握手完成
while(1)
{
printf("input:\n");
char buff[128] = {0};
fgets(buff,128,stdin);//fgets会用到空格回车
if(strncmp(buff,"end",3)==0)
{
break;
}
send(sockfd,buff,strlen(buff),0);//把收到的讯息再发送出去
memset(buff,0,128);
}
close(sockfd);//关闭
return 0;
}