Linux 非阻塞网络IO模式

非阻塞网络IO模式介绍

当用户线程发起一个 read 操作后,并不需要等待,而是马上就得到了一个结果。如果结果是一个 error 时,它就知道数据还没有准备好,于是它可以再次发送 read 操作。一旦内核中的数据准备好了,并且又再次收到了用户线程的请求,那么它马上就将数据拷贝到了用户线程,然后返回。

所以事实上,在非阻塞 IO 模型中,用户线程需要不断地询问内核数据是否就绪,也就 说非阻塞 IO 不会交出 CPU,而会一直占用 CPU。

在这里插入图片描述

设置非阻塞常用方式:

方式一: 创建 socket 时指定

int s = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);

方式二: 在使用前通过如下方式设定

fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) | O_NONBLOCK);

方式一 demo

#include <sys/un.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>

#define BUFF_SIZE 1024

int main(void)
{
        int server_sockfd;
        int client_sockfd;
        char ch;
        int ret;
        int recv_len;
        char buff[BUFF_SIZE];
        //用于 UNIX 系统内部通信的地址, struct sockaddr_un
        struct sockaddr_in server_addr;
        struct sockaddr_in client_addr;

        int client_addr_len =sizeof(struct sockaddr_in);
        server_sockfd = socket(AF_INET, SOCK_DGRAM|SOCK_NONBLOCK, 0);
        // 设置服务器地址
        server_addr.sin_family = AF_INET;               //地址的域,相当于地址的类型,AF_UNIX 表示地址位于 UNIX 系统内部
        server_addr.sin_addr.s_addr = INADDR_ANY;       //inet_addr("10.10.0.9");
        server_addr.sin_port = htons(9000);
        // 绑定该套接字,使得该套接字和对应的系统套接字文件关联起来。
        ret = bind(server_sockfd, (struct sockaddr*)&server_addr,sizeof(server_addr));

        if (ret == -1) {
                perror("bind");
                exit(1);
        }
        // 创建套接字队列, 保存进入该服务器的客户端请求。
        // ret = listen(server_sockfd, 5);
        // 循环处理客户端请求
        while (1) {
                printf("server waiting\n");
                // 等待并接收客户端请求
                //client_sockfd = accept(server_sockfd, (struct sockaddr*)&client_addr, &client_addr_len);
                recv_len = recvfrom(server_sockfd, buff, sizeof(buff) , 0,(struct sockaddr*)&client_addr, &client_addr_len);
                if (recv_len < 0) {
                        if(errno == EAGAIN ||errno == EWOULDBLOCK){
                                sleep(2);
                                continue;
                        }
                        perror("recvfrom");
                        exit(errno);
                }
                printf("received: %s\n", buff);
        }
        close(server_sockfd);
        return 0;
}

在这里插入图片描述
方式二 demo

#include <sys/un.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>

#define BUFF_SIZE 1024

int main(void)
{
        int server_sockfd;
        int client_sockfd;
        char ch;
        int ret;
        int recv_len;
        char buff[BUFF_SIZE];
        //用于 UNIX 系统内部通信的地址, struct sockaddr_un
        struct sockaddr_in server_addr;
        struct sockaddr_in client_addr;

        int client_addr_len =sizeof(struct sockaddr_in);
        server_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        // 设置服务器地址
        server_addr.sin_family = AF_INET;               //地址的域,相当于地址的类型,AF_UNIX 表示地址位于 UNIX 系统内部
        server_addr.sin_addr.s_addr = INADDR_ANY;       //inet_addr("10.10.0.9");
        server_addr.sin_port = htons(9000);
        // 绑定该套接字,使得该套接字和对应的系统套接字文件关联起来。
        ret = bind(server_sockfd, (struct sockaddr*)&server_addr,sizeof(server_addr));

        if (ret == -1) {
                perror("bind");
                exit(1);
        }
        // 创建套接字队列, 保存进入该服务器的客户端请求。
        // ret = listen(server_sockfd, 5);


        fcntl(server_sockfd, F_SETFL, fcntl(server_sockfd, F_GETFL, 0) | O_NONBLOCK);
        // 循环处理客户端请求
        while (1) {
                printf("server waiting\n");
                // 等待并接收客户端请求
                //client_sockfd = accept(server_sockfd, (struct sockaddr*)&client_addr, &client_addr_len);
                recv_len = recvfrom(server_sockfd, buff, sizeof(buff) , 0,(struct sockaddr*)&client_addr, &client_addr_len);
                if (recv_len < 0) {
                        if(errno == EAGAIN ||errno == EWOULDBLOCK){
                                sleep(2);
                                continue;
                        }
                        perror("recvfrom");
                        exit(errno);
                }
                printf("received: %s\n", buff);
        }
        close(server_sockfd);
        return 0;
}

在这里插入图片描述

  • 11
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

江凡心

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值