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; }
过程:

结果:



浙公网安备 33010602011771号