c 网络 io 模型 pdf
- 行业动态
- 2025-03-22
- 7
网络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)
描述:
在非阻塞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()系统调用来监视多个文件描述符,以查看它们是否就绪,这允许单个线程高效地处理多个连接。
示例代码:
#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)
描述:
异步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>