文章目录
- 4.28 poll API介绍及代码编写
- 代码实现
4.28 poll API介绍及代码编写
#include <poll.h>
struct pollfd{
int fd;//委托内核检测的文件描述符
short events;//委托内核检测文件描述符的什么事件
short revents;//文件描述符实际发生的事件
};
int poll(struct pollfd *fds,nfds_t nfds,int timeout);
-参数:
-fds:是一个struct pollfd结构体数组,这是一个需要检测的文件描述符的集合
-nfds:这是第一个参数数组中最后一个有效元素的下标+1
-timeout:阻塞时长
0:不阻塞
-1:阻塞,当检测到需要检测的文件描述符有变化,解除阻塞
>0:阻塞的时长,单位毫秒
-返回值:
-1:失败
>0:成功,返回n表示检测到集合中有n个文件描述符发生变化
当检测两个事件时,使用或操作:
struct pollfd myfd;
myfd.fd=5;
myfd.events=PLLIN|POLLOUT;//同时检测读事件和写事件
代码实现
client.c
#include <stdio.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(){
//1.创建一个用于通信的socket
int fd=socket(PF_INET,SOCK_STREAM,0);
if(fd==-1){
perror("socket");
return -1;
}
//指定连接的服务器的IP和端口
struct sockaddr_in seraddr;
inet_pton(AF_INET,"127.0.0.1",&seraddr.sin_addr.s_addr);
seraddr.sin_family=AF_INET;
seraddr.sin_port=htons(9999);
//2.连接服务器
int ret=connect(fd,(struct sockaddr *)&seraddr,sizeof(seraddr));
if(ret==-1){
perror("connect");
return -1;
}
//3.连接成功了,客户端可以直接和服务端通信(接收数据,发送数据)
int num=0;
while(1){
char sendBuf[1024]={0};
sprintf(sendBuf,"send data %d",num++);
//发送数据
write(fd,sendBuf,strlen(sendBuf)+1);
//接收数据
int len=read(fd,sendBuf,sizeof(sendBuf));
if(len==-1){
perror("read");
return -1;
}else if(len>0){
printf("read buf=%s\n",sendBuf);
}else{
printf("服务器已经断开连接...\n");
break;
}
usleep(1000);
}
//4.通信结束,断开连接
close(fd);
return 0;
}
poll.c
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <poll.h>
int main(){
//1、创建一个用于监听的套接字
int lfd=socket(PF_INET,SOCK_STREAM,0);
//本地服务器的地址信息(IP和端口)
struct sockaddr_in saddr;
saddr.sin_port=htons(9999);
saddr.sin_family=AF_INET;
saddr.sin_addr.s_addr=INADDR_ANY;
//2、将监听文件描述符和本地IP和端口绑定
bind(lfd,(struct sockaddr *)&saddr,sizeof(saddr));
//3、设置监听,监听的fd开始工作
listen(lfd,8);
//初始化检测的文件描述符数组
struct pollfd fds[1024];
for(int i=0;i<1024;++i){
fds[i].fd=-1;
fds[i].events=POLLIN;//检测读事件
}
fds[0].fd=lfd;//下标0表示监听描述符
int nfds=0;
while(1){
//调用poll系统函数,让内核帮忙检测哪些文件描述符有数据
int ret=poll(fds,nfds+1,-1);
if(ret==-1){
perror("poll");
exit(-1);
}else if(ret==0){
continue;
}else if(ret>0){
//说明检测到了有文件描述符的对应缓冲区数据发生改变
if(fds[0].revents&POLLIN){
//表示有新客户端连接进来
struct sockaddr_in cliaddr;
int len=sizeof(cliaddr);
int cfd=accept(lfd,(struct sockaddr *)&cliaddr,&len);
//将新的文件描述符加入到集合中
for(int i=1;i<1024;++i){
if(fds[i].fd==-1){
fds[i].fd=cfd;
fds[i].events=POLLIN;
break;
}
}
//更新最大的文件描述符索引
nfds=nfds>cfd?nfds:cfd;
}
for(int i=1;i<=nfds;++i){
if(fds[i].revents&POLLIN){
//说明这个文件描述符对应的客户端发来了数据
char buf[1024]={0};
//接收数据
int len=read(fds[i].fd,buf,sizeof(buf));
if(len==-1){
perror("read");
exit(-1);
}else if(len==0){
printf("client closed...\n");
close(fds[i].fd);//通信结束,断开连接
fds[i].fd=-1;
}else if(len>0){
printf("read buf=%s\n",buf);
//发送数据
write(fds[i].fd,buf,strlen(buf)+1);
}
}
}
}
}
close(lfd);
return 0;
}