首页 > 其他分享 >阻塞IO/非阻塞IO

阻塞IO/非阻塞IO

时间:2023-09-11 16:12:38浏览次数:35  
标签:int 阻塞 应用程序 IO 操作 include

阻塞I/O(Blocking I/O):

  • 在阻塞I/O模式下,当程序执行一个I/O操作(如读取文件、网络通信等)时,它会等待直到该操作完成才会继续执行下一步操作。
  • 在等待期间,程序的执行会被暂停,无法执行其他任务,直到I/O操作完成或者发生超时。
  • 阻塞I/O通常较容易使用和理解,但可能会导致应用程序在高负载或大量I/O操作的情况下性能下降,因为大部分时间都在等待I/O操作完

代码

服务端代码 server.cpp

#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>

int main() {
    // 创建套接字
    int serverSocket = socket(AF_INET, SOCK_STREAM, 0);

    if (serverSocket == -1) {
        std::cerr << "无法创建套接字" << std::endl;
        return 1;
    }

    // 绑定地址和端口
    sockaddr_in serverAddress;
    serverAddress.sin_family = AF_INET;
    serverAddress.sin_addr.s_addr = INADDR_ANY;
    serverAddress.sin_port = htons(8080); // 使用8080端口

    if (bind(serverSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == -1) {
        std::cerr << "绑定失败" << std::endl;
        return 1;
    }

    // 开始监听连接
    if (listen(serverSocket, 5) == -1) {
        std::cerr << "监听失败" << std::endl;
        return 1;
    }

    std::cout << "服务器正在监听端口 8080..." << std::endl;

    while (true) {
        // 接受客户端连接(阻塞)
        sockaddr_in clientAddress;
        socklen_t clientAddressSize = sizeof(clientAddress);
        int clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddress, &clientAddressSize);

        if (clientSocket == -1) {
            std::cerr << "无法接受客户端连接" << std::endl;
            return 1;
        }

        // 与客户端通信(阻塞)
        char buffer[1024];
        std::memset(buffer, 0, sizeof(buffer));
        int bytesRead = read(clientSocket, buffer, sizeof(buffer));

        if (bytesRead == -1) {
            std::cerr << "读取数据失败" << std::endl;
            return 1;
        }

        std::cout << "收到客户端消息: " << buffer << std::endl;

        // 关闭连接
        close(clientSocket);
    }

    // 关闭服务器套接字
    close(serverSocket);

    return 0;
}
		

客户端代码 client.cpp

#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>

int main() {
    // 创建套接字
    int clientSocket = socket(AF_INET, SOCK_STREAM, 0);

    if (clientSocket == -1) {
        std::cerr << "无法创建套接字" << std::endl;
        return 1;
    }

    // 连接到服务器
    sockaddr_in serverAddress;
    serverAddress.sin_family = AF_INET;
    serverAddress.sin_port = htons(8080); // 与服务器相同的端口
    serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1"); // 服务器的IP地址

    if (connect(clientSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == -1) {
        std::cerr << "无法连接到服务器" << std::endl;
        return 1;
    }

    // 发送消息给服务器
    const char* message = "Hello, Server!";
    int bytesSent = send(clientSocket, message, strlen(message), 0);

    if (bytesSent == -1) {
        std::cerr << "发送消息失败" << std::endl;
        return 1;
    }

    // 接收服务器的响应(阻塞)
    char buffer[1024];
    std::memset(buffer, 0, sizeof(buffer));
    int bytesRead = recv(clientSocket, buffer, sizeof(buffer), 0);

    if (bytesRead == -1) {
        std::cerr << "接收服务器响应失败" << std::endl;
        return 1;
    }

    std::cout << "服务器响应: " << buffer << std::endl;

    // 关闭连接
    close(clientSocket);

    return 0;
}

非阻塞I/O(Non-blocking I/O):

  • 在非阻塞I/O模式下,程序会立即返回从I/O操作中获取的结果,而不会等待操作完成。
  • 如果I/O操作尚未完成,程序不会被阻塞,而是可以继续执行其他任务,然后定期轮询或使用回调等方式来检查I/O操作是否已完
  • 非阻塞I/O通常用于构建高并发的应用程序,因为它允许程序同时处理多个I/O操作,提高了应用程序的性能。

阻塞I/O适用于简单的、低并发的应用程序,而非阻塞I/O更适合需要高并发处理或对I/O操作的响应时间要求很高的应用程序。在实际应用中,通常会使用非阻塞I/O的方式来构建多线程、多进程或异步编程模型,以充分利用计算资源并提高应用程序的性能

代码

服务端代码 server.cpp

#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <arpa/inet.h>

int main() {
    // 创建套接字
    int serverSocket = socket(AF_INET, SOCK_STREAM, 0);

    if (serverSocket == -1) {
        std::cerr << "无法创建套接字" << std::endl;
        return 1;
    }

    // 设置套接字为非阻塞模式
    int flags = fcntl(serverSocket, F_GETFL, 0);
    fcntl(serverSocket, F_SETFL, flags | O_NONBLOCK);

    // 绑定地址和端口
    sockaddr_in serverAddress;
    serverAddress.sin_family = AF_INET;
    serverAddress.sin_addr.s_addr = INADDR_ANY;
    serverAddress.sin_port = htons(8080); // 使用8080端口

    if (bind(serverSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == -1) {
        std::cerr << "绑定失败" << std::endl;
        return 1;
    }

    // 开始监听连接
    if (listen(serverSocket, 5) == -1) {
        std::cerr << "监听失败" << std::endl;
        return 1;
    }

    std::cout << "服务器正在监听端口 8080..." << std::endl;

    while (true) {
        // 接受客户端连接(非阻塞)
        sockaddr_in clientAddress;
        socklen_t clientAddressSize = sizeof(clientAddress);
        int clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddress, &clientAddressSize);

        if (clientSocket == -1) {
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                // 没有新连接,继续循环
                continue;
            } else {
                std::cerr << "无法接受客户端连接" << std::endl;
                return 1;
            }
        }

        // 与客户端通信(非阻塞)
        char buffer[1024];
        std::memset(buffer, 0, sizeof(buffer));
        int bytesRead = read(clientSocket, buffer, sizeof(buffer));

        if (bytesRead == -1) {
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                // 没有数据可读,继续循环
                close(clientSocket);
                continue;
            } else {
                std::cerr << "读取数据失败" << std::endl;
                return 1;
            }
        } else if (bytesRead == 0) {
            // 客户端关闭连接
            close(clientSocket);
            continue;
        }

        std::cout << "收到客户端消息: " << buffer << std::endl;

        // 关闭连接
        close(clientSocket);
    }

    // 关闭服务器套接字
    close(serverSocket);

    return 0;
}

		

客户端代码 client.cpp

#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <errno.h>

int main() {
    // 创建套接字
    int clientSocket = socket(AF_INET, SOCK_STREAM, 0);

    if (clientSocket == -1) {
        std::cerr << "无法创建套接字" << std::endl;
        return 1;
    }

    // 设置套接字为非阻塞模式
    int flags = fcntl(clientSocket, F_GETFL, 0);
    fcntl(clientSocket, F_SETFL, flags | O_NONBLOCK);

    // 连接到服务器
    sockaddr_in serverAddress;
    serverAddress.sin_family = AF_INET;
    serverAddress.sin_port = htons(8080); // 与服务器相同的端口
    serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1"); // 服务器的IP地址

    if (connect(clientSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == -1) {
        if (errno != EINPROGRESS) {
            std::cerr << "无法连接到服务器" << std::endl;
            return 1;
        }
    }

    // 使用select来等待连接完成
    fd_set writeSet;
    FD_ZERO(&writeSet);
    FD_SET(clientSocket, &writeSet);

    struct timeval timeout;
    timeout.tv_sec = 5; // 设置超时时间为5秒
    timeout.tv_usec = 0;

    int selectResult = select(clientSocket + 1, nullptr, &writeSet, nullptr, &timeout);

    if (selectResult == -1) {
        std::cerr << "select调用失败" << std::endl;
        return 1;
    } else if (selectResult == 0) {
        std::cerr << "连接超时" << std::endl;
        return 1;
    }

    // 发送消息给服务器
    const char* message = "Hello, Server!";
    int bytesSent = send(clientSocket, message, strlen(message), 0);

    if (bytesSent == -1) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            // 缓冲区不可用,继续循环
            close(clientSocket);
            return 1;
        } else {
            std::cerr << "发送消息失败" << std::endl;
            return 1;
        }
    }

    // 关闭连接
    close(clientSocket);

    return 0;
}

以上代码由GPT-3.5生成 需在Linux环境下运行,感兴趣的可以参考改代码自己手动实现

参考链接

标签:int,阻塞,应用程序,IO,操作,include
From: https://www.cnblogs.com/daydream0928/p/17693792.html

相关文章

  • 无涯教程-JavaScript - MDURATION函数
    描述MDURATION函数返回假定面值为$100的有价证券的经修改Macaulay期限。语法MDURATION(settlement,maturity,coupon,yld,frequency,[basis])争论Argument描述Required/OptionalSettlement证券的结算日期。证券结算日期是指在发行日期之后将证券交易给买方的日......
  • VisionPro学习笔记(3)——BeadInspectTool
    如果需要了解其他图像处理的文章,请移步小编的GitHub地址传送门:请点击我如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPracticeVisionPro有很多的示例和算子,这里再展示一个最新出的算子BeadInspectTool。估计理解这个算子需要有一定的基础,但是使用......
  • 直播流IOS无法播放问题排查
     问题:IOS手机无法播放flv协议视频,改为hls协议后,IOS播放H264视频编码格式正常,但是H265无法播放解决:使用花椒播放器,在IOS上通过Webassembly编解码,播放flv协议视频解决此问题。视频插件:花椒播放器https://github.com/ErosZy/WXInlinePlayer示例地址:https://eroszy.github......
  • 【Kafka】ZooKeeper启动失败报错java.net.BindException_ Address already in use_ bi
    问题描述Kafka2.8.1ZooKeeper启动失败。zookeeper-server-start.bat../../config/zookeeper.properties[2023-09-0418:21:49,497]INFObindingtoport0.0.0.0/0.0.0.0:2181(org.apache.zookeeper.server.NIOServerCnxnFactory)[2023-09-0418:21:49,498]ERRORUnexpected......
  • 飞桨AI Studio(星河社区)推出文心大模型SDK功能
    随着大模型的涌现,我们喜悦于其远远超越小模型的性能,但又不得不面临大模型开发难的困境,训练难、微调难、部署难,开发者难以将其投入实际生产,不仅面临资源的限制,更面临高精数据难寻、时间成本过高等问题。为了让平台更多开发者可以进行大模型开发,体验并使用大模型的真正能力,飞桨AIStu......
  • ValueError: Per-Channel support with QDQ format requires onnx opset version 13 o
    问题:在做静态量化是,遇见onnxopsetversion版本报错解决办法:withtempfile.NamedTemporaryFile()asfp:torch.onnx.export(model,args=tuple(dummy_input.values()),f=output_model_name,input_name......
  • 使用Github Action在Github Pages上部署vue页面
    GithubAction部分:name:NodeJSon:push:branches:["master"]#SetspermissionsoftheGITHUB_TOKENtoallowdeploymenttoGitHubPagespermissions:contents:write#Allowonlyoneconcurrentdeployment,skippingrunsqueuedbetwee......
  • abc288F - Integer Division
    F-IntegerDivision挺有意思的一道题,贪心的做法就是排序之后,逐个加入,如果不能被之前的表示则加入题解证明的话大概是这样考虑第i个数选不选首先加入前面选的数,如果能够表示当前的数,则必然不选否则前面的数不能表示当前的数,假如我们不选\(p_i\)假设最后得到一个合法序列,则......
  • Burp Suite Extension Development Guide
    BurpSuite是什么?BurpSuite是一款Web应用程序渗透测试工具,可以帮助用户发现和利用Web应用程序中的漏洞,提高渗透测试的效率和精度。Web应用程序最常用的传输数据的协议就是HTTP/HTTPS,所以我们将从HTTP协议的数据格式开始介绍。HTTP/HTTPS协议内容简要划分Burp中最为核心的对象......
  • 【题解】Educational Codeforces Round 142(CF1792)
    没有手速,再加上被E卡了,废掉了。A.GamingForces题目描述:Monocarp正在玩电脑游戏。他打算杀死\(n\)个怪兽,第\(i\)个的血量为\(h_i\)。Monocarp的角色有两个魔法咒语如下,都可以以任意顺序用任意次(可以不用),每次使用相当于一次操作。选择两个怪兽并各扣一滴血。选择......