TCP/IP 网络编程 (抄书笔记 5) – select 和 IO 复用
TCP/IP 网络编程 (抄书笔记 5) – select 和 IO 复用
利用 fork() 生成子进程 可以达到 服务器端可以同时响应多个 客户端的请求, 但是这样做有缺点:
需要大量的运算和内存空间, 每个进程都要有独立的内存空间, 数据交换也很麻烦 (IPC, 如管道)
IO 复用:
以太网的总线结构也是采用了 复用技术, 如果不采用, 那么两两之间就要直接通信 网络知识
int server_sock; int client_sock; struct sockaddr_in server_addr; struct sockaddr_in client_addr; socklen_t client_size; server_sock = socket(AF_INET, SOCK_STREAM, 0); memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(atoi(argv[1])); bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)); listen(server_sock, 5); fd_set reads; fd_set read_init; int fd_max; int fd_num; struct timeval timeout; char buf[BUF_SIZE+1]; int str_len; fd_max = server_sock; FD_ZERO(&read_init); FD_SET(server_sock, &read_init); while (1) { reads = read_init; timeout.tv_sec = 5; timeout.tv_usec = 0; fd_num = select(fd_max+1, &reads, 0, 0, &timeout); if (fd_num < 0) { // select error break; } else if (fd_num == 0) { printf("timeout ...\n"); continue; } for (int i = 0; i < fd_max+1; i++) { if (FD_ISSET(i, &reads)) { if (server_sock == i) { // 表示有客户端发起连接请求 client_size = sizeof(client_addr); client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &client_size); FD_SET(client_sock, &read_init); if (fd_max < client_sock) { fd_max = client_sock; } printf("client connect: %d\n", client_sock); } else { // 表示有客户端发送信息来了 str_len = read(i, buf, BUF_SIZE); buf[str_len] = 0; if (str_len == 0) { FD_CLR(i, &read_init); close(i); printf("client closed: %d\n", i); } else { write(i, buf, str_len); } } } } } close(server_sock); close(client_sock);
时间: 2024-10-05 04:19:33