【项目 计网10】4.28 poll API介绍及代码编写

文章目录

    • 4.28 poll API介绍及代码编写
        • 代码实现


4.28 poll API介绍及代码编写

#include 
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个文件描述符发生变化

【项目 计网10】4.28 poll API介绍及代码编写_第1张图片
当检测两个事件时,使用或操作:

struct pollfd myfd;
myfd.fd=5;
myfd.events=PLLIN|POLLOUT;//同时检测读事件和写事件

代码实现

client.c

#include 
#include 
#include 
#include 
#include 

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 
#include 
#include 
#include 
#include 
#include 

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;
}

你可能感兴趣的:(tcp/ip)