【项目 计网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;
}
相关推荐
Reggie_L2 小时前
网络原理——IP
网络·网络协议·tcp/ip
九州ip动态6 小时前
软路由 + 代理 IP 实现多手机不同公网 IP 分配教程
网络协议·tcp/ip·智能手机
lenkco13 小时前
WiFiMouseServer手机等作为远程输入
c语言·c++·tcp/ip
~央千澈~17 小时前
详细阐述 TCP、UDP、ICMPv4 和 ICMPv6 协议-以及防火墙端口原理优雅草卓伊凡
tcp/ip·udp·tcp
上海云盾-高防顾问20 小时前
高防IP能够防御CC攻击吗?它具备哪些显著优势?
网络·tcp/ip·安全
June`1 天前
计算机网络基础:从协议到通信全解析(大致框架)
网络·网络协议·tcp/ip·mac
kfepiza1 天前
`/etc/samba/smb.conf`笔记250720
linux·网络协议·tcp/ip
kfepiza1 天前
`/etc/samba/smb.conf` 的 `guest ok` 和 `map to guest` 和 `guest account`
linux·网络协议·tcp/ip
MediaTea1 天前
Python:简易的 TCP + SSL 服务端与客户端示例
开发语言·python·网络协议·tcp/ip·ssl
娅娅梨2 天前
HarmonyOS-ArkUI Web控件基础铺垫4--TCP协议- 断联-四次挥手解析
网络协议·tcp/ip·http·okhttp·harmonyos·arkui·arkweb