IO模型:传统IO模型(阻塞IO模型)

105 阅读2分钟

传统IO模型

阻塞式IO模型图

image.png

阻塞式IO使用案例

下面是一个利用传统IO模型实现的简易http服务器

代码如下:

#include <stdio.h>//标准输入输出头文件,定义了一些输入输出函数,比如 printf, scanf 等。
#include <stdlib.h>//标准库头文件,定义了一些库函数,比如 malloc, exit 等。
#include <string.h>//字符串头文件,定义了一些字符串操作函数,比如 strlen, memset 等。
#include <unistd.h>//Unix 标准函数头文件,定义了一些常用的函数,比如 read, write 等。
#include <sys/socket.h>//socket 函数头文件,定义了一些 socket 函数,比如 socket, bind, listen, accept 等。
#include <netinet/in.h>//Internet 地址头文件,定义了一些 Internet 地址结构,比如 sockaddr_in 等。
#include <arpa/inet.h>//Internet 地址转换头文件,定义了一些 Internet 地址转换函数,比如 inet_ntop 等。

#define PORT 8080 //连接的端口号
#define BACKLOG 5 //连接队列长度
#define BUFFERSIZE 4089//缓冲区大小

int main() {
    int listenfd, connfd;
    struct sockaddr_in serv_addr, client_addr;
    char buffer[BUFFERSIZE];
    socklen_t addr_size;

    listenfd = socket(AF_INET, SOCK_STREAM, 0);

    memset(&serv_addr, 0, sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(PORT);

    if (bind(listenfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) == -1) {
        perror("绑定失败");
        exit(EXIT_FAILURE);
    }

    if (listen(listenfd, BACKLOG) == -1) {
        perror("监听失败");
        exit(EXIT_FAILURE);
    }

    addr_size = sizeof(client_addr);

    printf("服务器启动, 监听端口 %d\n", PORT);


    while (1) {
        connfd = accept(listenfd, (struct sockaddr *) &client_addr, &addr_size);

        int port = ntohs(client_addr.sin_port);
        struct in_addr in = client_addr.sin_addr;
        char str[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, &in, str, sizeof(str));

        printf("客户端信息: ip:port = %s:%d\n", str, port);

        if (connfd == -1) {
            perror("accept失败");
            break;
        }


        ssize_t n = read(connfd, buffer, BUFFERSIZE);

        if (n > 0) {
            buffer[n] = '\0';

            printf("收到的请求信息:\n%s\n", buffer);



            char *response = "HTTP/1.1 200 OK\r\n"
                             "Content-Type: text/html;charset=utf-8\r\n"
                             "\r\n"
                             "<html><body><h1>Hello, World!</h1></body></html>\r\n";
            write(connfd, response, strlen(response));
        }

        close(connfd);
    }

    close(listenfd);
    return 0;
}

代码主要逻辑

代码中,服务器的网络通信是基于阻塞式的套接字(socket)来实现的。首先通过socket函数创建一个套接字,然后通过bind函数将套接字与服务器的地址信息关联起来。随后,调用listen函数以使该套接字进入监听状态。

当有客户端连接到服务器时,服务器调用accept函数将返回一个已连接的套接字,使用read函数从已连接的套接字读取客户端的请求信息。如果读取到了数据,服务器使用write函数向客户端发送一个响应。然后,服务器关闭已连接的套接字,并回到监听状态,等待下一个客户端的连接。

该http服务器是一个阻塞式服务器,因为在读取或写入数据时,它始终处于阻塞状态,直到数据到达或操作完成。

运行截图

image.png image.png