fork前后创建socket对 udp server的影响
结论:
Linux上五元组关系由socket 维护的(但是mac 和linux 表现还不一样)
代码:
udp-client.c
#include <stdio.h> #include <string.h> #include <errno.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/wait.h> #define DEST_PORT 8080 #define DSET_IP_ADDRESS "127.0.0.1" int do_main() { /* socket文件描述符 */ int sock_fd; /* 建立udp socket */ sock_fd = socket(AF_INET, SOCK_DGRAM, 0); if(sock_fd < 0) { perror("socket"); exit(1); } /* 设置address */ struct sockaddr_in addr_serv; int len; memset(&addr_serv, 0, sizeof(addr_serv)); addr_serv.sin_family = AF_INET; addr_serv.sin_addr.s_addr = inet_addr(DSET_IP_ADDRESS); addr_serv.sin_port = htons(DEST_PORT); len = sizeof(addr_serv); int send_num; int recv_num; char send_buf[20] = "hey, who are you?"; char recv_buf[20]; while (1) { printf("client send: %s\n", send_buf); send_num = sendto(sock_fd, send_buf, strlen(send_buf), 0, (struct sockaddr *)&addr_serv, len); if(send_num < 0) { perror("sendto error:"); exit(1); } sleep(1); } recv_num = recvfrom(sock_fd, recv_buf, sizeof(recv_buf), 0, (struct sockaddr *)&addr_serv, (socklen_t *)&len); if(recv_num < 0) { perror("recvfrom error:"); exit(1); } recv_buf[recv_num] = '\0'; printf("client receive %d bytes: %s\n", recv_num, recv_buf); close(sock_fd); return 0; } int main() { for (int i =0; i < 4; i++) { if (fork() == 0) { // 子进程 do_main(); exit(EXIT_SUCCESS); // 子进程处理完请求后退出 } } // 父进程等待子进程结束(可选) while (waitpid(-1, NULL, 0) > 0); return 0; }
udp-server.c
#include <iostream> #include <sys/socket.h> #include <netinet/in.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <cstdlib> #include <sys/types.h> #include <sys/wait.h> #include <arpa/inet.h> #define PORT 8080 #define BUF_SIZE 1024 void handle_client(int server_fd) { while(1){ char buffer[BUF_SIZE]; struct sockaddr_in client_addr; socklen_t client_len = sizeof(client_addr); int n = recvfrom(server_fd, buffer, BUF_SIZE, 0, (struct sockaddr*)&client_addr, &client_len); if (n < 0) { perror("recvfrom"); exit(1); } std::cout << "Received from " << inet_ntoa(client_addr.sin_addr) << ":" << ntohs(client_addr.sin_port) << " in process " << getpid() << std::endl; // 可以选择发送响应给客户端 // sendto(server_fd, buffer, n, 0, (struct sockaddr*)&client_addr, client_len); } } int main() { int server_fd, new_socket; struct sockaddr_in address; int opt = 1; int addrlen = sizeof(address); if ((server_fd = socket(AF_INET, SOCK_DGRAM, 0)) == 0) { perror("socket failed"); exit(EXIT_FAILURE); } if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt))) { perror("setsockopt (SO_REUSEPORT) failed"); exit(EXIT_FAILURE); } address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(PORT); if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { perror("bind failed"); exit(EXIT_FAILURE); } // 创建多个进程来处理客户端请求 for (int i = 0; i < 4; ++i) { // 假设我们创建5个进程 if (fork() == 0) { // 子进程 handle_client(server_fd); exit(EXIT_SUCCESS); // 子进程处理完请求后退出 } } // 父进程等待子进程结束(可选) while (waitpid(-1, NULL, 0) > 0); close(server_fd); return 0; }
udp-server2.c
#include <iostream> #include <sys/socket.h> #include <netinet/in.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <cstdlib> #include <sys/types.h> #include <sys/wait.h> #include <arpa/inet.h> #define PORT 8080 #define BUF_SIZE 1024 void handle_client(int server_fd) { while(1){ char buffer[BUF_SIZE]; struct sockaddr_in client_addr; socklen_t client_len = sizeof(client_addr); std::cout << "ready recv:" << getpid() << std::endl; int n = recvfrom(server_fd, buffer, BUF_SIZE, 0, (struct sockaddr*)&client_addr, &client_len); if (n < 0) { perror("recvfrom"); exit(1); } std::cout << "Received from " << inet_ntoa(client_addr.sin_addr) << ":" << ntohs(client_addr.sin_port) << " in process " << getpid() << std::endl; // 可以选择发送响应给客户端 // sendto(server_fd, buffer, n, 0, (struct sockaddr*)&client_addr, client_len); } } int do_main() { int server_fd, new_socket; struct sockaddr_in address; int opt = 1; int addrlen = sizeof(address); if ((server_fd = socket(AF_INET, SOCK_DGRAM, 0)) == 0) { perror("socket failed"); exit(EXIT_FAILURE); } if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt))) { perror("setsockopt (SO_REUSEPORT) failed"); exit(EXIT_FAILURE); } address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(PORT); if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { perror("bind failed"); exit(EXIT_FAILURE); } handle_client(server_fd); // // 创建多个进程来处理客户端请求 // for (int i = 0; i < 4; ++i) { // 假设我们创建5个进程 // if (fork() == 0) { // 子进程 // handle_client(server_fd); // exit(EXIT_SUCCESS); // 子进程处理完请求后退出 // } // } // 父进程等待子进程结束(可选) // while (waitpid(-1, NULL, 0) > 0); close(server_fd); return 0; } int main() { for (int i =0; i < 4; i++) { if (fork() == 0) { // 子进程 do_main(); exit(EXIT_SUCCESS); // 子进程处理完请求后退出 } } // 父进程等待子进程结束(可选) while (waitpid(-1, NULL, 0) > 0); return 0; }
过程:
结果: