4.28、poll API介绍及代码编写

4.28、pollAPI介绍及代码编写

  • 1.poll使用介绍
  • 2.poll的服务端代码编写
    • ①服务端
    • ②客户端(跟其他的一样,没变)

1.poll使用介绍

#include 
struct pollfd {
	int fd; /* 委托内核检测的文件描述符 */
	short events; /* 委托内核检测文件描述符的什么事件 */
	short revents; /* 文件描述符实际发生的事件 */
};

struct pollfd myfd;
myfd.fd = 5;
myfd.events = POLLIN | POLLOUT;

int poll(struct pollfd *fds, nfds_t nfds, int timeout);
	- 参数:
		- fds : 是一个struct pollfd 结构体数组,这是一个需要检测的文件描述符的集合
		- nfds : 这个是第一个参数数组中最后一个有效元素的下标 + 1
		- timeout : 阻塞时长
			0 : 不阻塞
			-1 : 阻塞,当检测到需要检测的文件描述符有变化,解除阻塞
			>0 : 阻塞的时长
	- 返回值:
		-1 : 失败
		>0(n) : 成功,n表示检测到集合中有n个文件描述符发生变化

4.28、poll API介绍及代码编写_第1张图片

2.poll的服务端代码编写

①服务端

#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

int main() {


    // 创建监听描述符
    int server_listen_fd = socket(PF_INET, SOCK_STREAM, 0);

    sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(9999);
    server_addr.sin_addr.s_addr = INADDR_ANY;

    // 绑定 ip 和端口
    bind(server_listen_fd, (sockaddr *)&server_addr, sizeof(server_addr));


    // 设置监听
    listen(server_listen_fd, 8);


    // 设置poll的来帮我们管理
    pollfd client_fds[1024];
    int client_fd_len = 0;
    for (int i = 0; i < 1024; i ++ ) {
        client_fds[i].fd = -1;
        client_fds[i].events = POLLIN;
    }
    client_fds[0].fd = server_listen_fd;



    while (1) {

        int poll_ret = poll(client_fds, client_fd_len + 1, -1);
        if (poll_ret == -1) {
            perror("poll");
            exit(-1);
        } else if (poll_ret == 0) {
            // 只有设置poll非阻塞的时候才会出现
            continue;
        } else if (poll_ret > 0) {
            
            // 发现监听描述符发生了变化,有新连接的客户端
            if ((client_fds[0].revents & POLLIN) == POLLIN) {
                
                // 获取与客户端进行通信的文件描述符
                sockaddr_in client_addr;
                socklen_t client_addr_len = sizeof(client_addr);
                int client_fd = accept(server_listen_fd, (sockaddr *)&client_addr, &client_addr_len);

                // 找到一个未使用或者关闭的文件描述符位置
                for (int i = 1; i < 1024; i ++ ) {
                    if (client_fds[i].fd == -1) {
                        client_fds[i].fd = client_fd;
                        client_fds[i].events = POLLIN;
                        // 更新数组有效长度
                        client_fd_len = max(client_fd_len, i);
                        break;
                    }
                }

            }

            // 循环判断哪一个客户端的文件描述符发生了改变
            char buf[1024];
            for (int i = 1; i <= client_fd_len; i ++ ) {

                if ((client_fds[i].revents & POLLIN) == POLLIN) {
                    
                    // 读取客户端数据
                    int recv_ret = recv(client_fds[i].fd, buf, sizeof(buf), 0);
                    if (recv_ret == -1) {
                        perror("recv");
                        exit(-1);
                    } else if (recv_ret == 0) {
                        cout << "client closed..." << endl;
                        // 关闭文件描述符
                        close(client_fds[i].fd);
                        client_fds[i].fd = -1;
                        continue;
                    } else if (recv_ret > 0) {
                        printf("I am server, data: %s\n", buf);
                        // 向客户端返回数据
                        send(client_fds[i].fd, buf, strlen(buf) + 1, 0);
                    }


                }

            }

        }

    }


    return 0;
}

②客户端(跟其他的一样,没变)

#include 
#include 
#include 
#include 

using namespace std;

int main()
{
    // 1.创建客户端socket
    int client_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (client_fd == -1) {
        perror("socket");
        exit(-1);
    }

    // 2.连接服务端
    // 设置需要连接的服务器的 ip 和端口
    sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;   // 设置为ipv4协议
    // 将点分十进制ip转换为newwork字节序
    int pton_ret = inet_pton(AF_INET, "xxx.xxx.xxx.xxx", &server_addr.sin_addr.s_addr);
    // 将主机序端口转换为newwork字节序端口
    server_addr.sin_port = htons(9999);

    int cone_ret = connect(client_fd, (sockaddr *)&server_addr, sizeof(server_addr));
    if (cone_ret == -1) {
        perror("connect");
        exit(-1);
    }

    // 3.读写服务端数据
    int num = 0;
    char recvBuf[1024] = {0};
    while (1) {
        
        // 往服务端写数据
        sprintf(recvBuf, "hello, I am client: %d\n", num ++ );
        write(client_fd, recvBuf, strlen(recvBuf) + 1);


        // 接手服务端数据
        int read_ret = read(client_fd, recvBuf, sizeof(recvBuf));
        if (read_ret == -1) {
            perror("read");
            exit(-1);
        } else if (read_ret > 0) {
            printf("recv client data is %s\n", recvBuf);
        } else if (read_ret == 0){
            cout << "server closed..." << endl;
            break;
        }
        sleep(1);

    }

    // 关闭文件描述符
    close(client_fd);

    return 0;
}

你可能感兴趣的:(c++,c语言,开发语言)