当前位置:首页 > 行业动态 > 正文

c 网络 io 模型 pdf

网络IO模型网络IO模型主要有阻塞IO、非阻塞IO、IO多路复用(如select、poll、epoll)、信号驱动IO和异步IO等,用于优化网络通信性能。

C语言中的网络I/O模型

在C语言中,网络I/O模型是处理网络通信的一种方式,它决定了程序如何与网络进行交互,包括如何处理数据的发送和接收,以下是几种常见的网络I/O模型:

1. 阻塞I/O(Blocking I/O)

描述

在阻塞I/O模型中,当一个进程调用recvfrom()时,系统调用会一直阻塞,直到有数据可读或发生错误。

这种模型简单直观,但效率低下,因为CPU在等待数据时无法执行其他任务。

示例代码

int main() {
    int server_fd, client_fd;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[1024] = {0};
    char hello = "Hello from server";
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(8080);
    if (bind(server_fd, (struct sockaddr )&address, sizeof(address))<0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }
    if ((client_fd = accept(server_fd, (struct sockaddr )&address, (socklen_t)&addrlen))<0) {
        perror("accept");
        exit(EXIT_FAILURE);
    }
    read(client_fd, buffer, 1024);
    printf("%s
",buffer );
    send(client_fd , hello , strlen(hello) , 0 );
    printf("Hello message sent
");
    return 0;
}

2. 非阻塞I/O(Non-blocking I/O)

描述

c 网络 io 模型 pdf  第1张

在非阻塞I/O模型中,recvfrom()调用会立即返回,即使没有数据可读,这允许程序继续执行其他任务。

需要使用select()、poll()或epoll()等机制来检查文件描述符的状态。

示例代码

int main() {
    int server_fd, client_fd;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[1024] = {0};
    char hello = "Hello from server";
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(8080);
    if (bind(server_fd, (struct sockaddr )&address, sizeof(address))<0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }
    if ((client_fd = accept(server_fd, (struct sockaddr )&address, (socklen_t)&addrlen))<0) {
        perror("accept");
        exit(EXIT_FAILURE);
    }
    // Set the socket to non-blocking mode
    fcntl(client_fd, F_SETFL, O_NONBLOCK);
    while (1) {
        ssize_t valread = read(client_fd, buffer, 1024);
        if (valread > 0) {
            printf("%s
", buffer);
            send(client_fd, hello, strlen(hello), 0);
            printf("Hello message sent
");
        } else {
            usleep(100000); // Sleep for a short time before trying again
        }
    }
    return 0;
}

3. I/O多路复用(I/O Multiplexing)

描述

I/O多路复用模型使用select()、poll()或epoll()系统调用来监视多个文件描述符,以查看它们是否就绪,这允许单个线程高效地处理多个连接。

c 网络 io 模型 pdf  第2张

示例代码

#include <sys/select.h>
#include <sys/time.h>
int main() {
    int server_fd, client_fd;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[1024] = {0};
    char hello = "Hello from server";
    fd_set readfds;
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(8080);
    if (bind(server_fd, (struct sockaddr )&address, sizeof(address))<0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }
    while (1) {
        FD_ZERO(&readfds);
        FD_SET(server_fd, &readfds);
        struct timeval tv = {5, 0}; // Timeout after 5 seconds
        int activity = select(server_fd + 1, &readfds, NULL, NULL, &tv);
        if ((activity < 0) && (errno!=EINTR)) {
            printf("select error");
        }
        if (FD_ISSET(server_fd, &readfds)) {
            if ((client_fd = accept(server_fd, (struct sockaddr )&address, (socklen_t)&addrlen))<0) {
                perror("accept");
                exit(EXIT_FAILURE);
            }
            printf("New connection, socket fd is %d, ip is : %s, port: %d 
", client_fd, inet_ntoa(address.sin_addr), ntohs(address.sin_port));
            // Add the new socket to the set of sockets we are monitoring
            FD_SET(client_fd, &readfds);
        } else {
            // No data within five seconds. Terminate after a few iterations.
        }
    }
    return 0;
}

4. 信号驱动I/O(Signal-driven I/O)

描述

在这种模型中,进程通过signal()系统调用为SIGIO信号注册一个处理器,当数据准备就绪时,内核会发送SIGIO信号给进程,进程可以在信号处理函数中调用recvfrom()读取数据。

这种模型不常用,因为它不如其他模型灵活和高效。

5. 异步I/O(Asynchronous I/O)

c 网络 io 模型 pdf  第3张

描述

异步I/O模型允许进程通知内核在数据准备好时执行回调函数,这通常涉及使用aio库或操作系统特定的API。

这种模型非常高效,因为它允许程序在等待I/O操作完成时执行其他任务,它也更复杂,需要更多的设置和资源管理。

示例代码

#include <aio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <time.h>
#include <math.h>
#include <limits.h>
#include <float.h>
#include <locale.h>
#include <byteswap.h>
#include <endian.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/if_tun.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include <netinet/udp.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <syslog.h>
#include <grp.h>
#include <pwd.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/if_tun.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include <netinet/udp.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <syslog.h>
#include <grp.h>
#include <pwd.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/if_tun.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include <netinet/udp.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <syslog.h>
#include <grp.h>
#include <pwd.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/if_tun.h>
#include <sys/mman.h>
#include <fcntl.h>
0