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

文章目录

    • [4.28 poll API介绍及代码编写](#4.28 poll API介绍及代码编写)

4.28 poll API介绍及代码编写

cpp 复制代码
#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个文件描述符发生变化

当检测两个事件时,使用或操作:

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

代码实现

client.c

cpp 复制代码
#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

cpp 复制代码
#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;
}
相关推荐
编程小风筝1 小时前
MAC物理地址和IP网络地址有什么区别?
网络协议·tcp/ip·macos
ipooipoo118818 小时前
动态住宅IP的定义、核心优势与技术场景应用
网络·网络协议·tcp/ip
pythonchashaoyou21 小时前
静态住宅ip是什么,静态住宅IP选型全解
网络·网络协议·tcp/ip
REDcker21 小时前
HTTP请求数据包流转详解:localhost、127.0.0.1、公网 IP、公网域名访问时的数据流转
网络·tcp/ip·http
会开花的二叉树1 天前
吃透Reactor多线程:EventLoop_Channel_ThreadPool协作原理
开发语言·c++·tcp/ip·servlet
科技块儿1 天前
如何定期向监管部门报送IP属地统计报表?
网络·网络协议·tcp/ip
云中飞鸿1 天前
虚拟机需要连外网,同时笔记本连接wlan,IP经常变,该怎么配置网络?
服务器·网络·tcp/ip
李白你好1 天前
基于腾讯云函数 (SCF) 的分布式 IP 代理池.
分布式·tcp/ip·腾讯云
树℡独1 天前
ns-3仿真之应用层(五)
服务器·网络·tcp/ip·ns3
酣大智2 天前
接口模式参数
运维·网络·网络协议·tcp/ip