多线程UDP服务器/客户端

3

我刚刚使用UDP创建了一个可靠的文件传输程序,但它只能处理一个客户端。因此,我考虑使用fork()来使服务器处理多个客户端。但是,我不知道如何继续。目前为止,我知道我不需要改变客户端,而是服务器会处理大部分工作。如果您有关于如何解决这个问题的想法或建议,将不胜感激。

P.S. 这是我的起点:

 void sigchldAction(int sig) {
 while (waitpid(-1, 0, WNOHANG) > 0) {
     ;
 }int main(int argc, char *argv[]) {

 return;
} //This is my function that waits for all the processes 

这是我的服务器:
int main(int argc, char *argv[]) {
    struct sockaddr_in serv_addr;
    int port_number, socket_fd;
    port_number = atoi(argv[1]);

    signal(SIGCHLD, sigchldAction);

    if ((socket_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)  exit(EXIT_FAILURE);
    if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR,
 (const void *)&optval, sizeof(int)) < 0) exit(EXIT_FAILURE);

    bzero((void *)&serv_addr, sizeof(struct sockaddr_in));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(port_number);
    if (bind(socket_fd, (struct sockaddr *)&serv_addr,
         sizeof(struct sockaddr_in)) < 0) exit(EXIT_FAILURE);

    pid_t child_pid;
    while (1) {
    child_pid = fork();

    switch (child_pid) {
        case -1:
            perror("Fork() Failed. \n");
            exit(EXIT_FAILURE);
            break;
        case 0:
            process_request(socket_fd);
            exit(EXIT_SUCCESS);
            break;
        case 1:
            close(socket_fd);
            break;

    } 

}
    close(socket_fd);
exit(EXIT_SUCCESS);
}

然后我的process_request函数负责处理任何传入的数据。

2个回答

4
如果你使用UDP,那么你没有连接;这是一种无连接协议。
如果你要进行分叉操作,你需要像ftpd一样告诉远程客户端将分叉的子进程数据包发送到不同于原始端口的端口上(当然,子进程也必须在该端口上接收)。

在UDP中,所有客户端都无法在同一传入端口上运行吗? - fabricemarcelin
2
@fabricemarcelin - 你可以这样做,但会变得很复杂。你可以使用recvfrom()获取源地址(客户端),然后分离它们。但是,如果你在同一个端口上fork子进程,第一个子进程从客户端#2读取初始数据报的情况怎么办?TCP会为你解决这个问题,因为accept()在底层创建了一个新的套接字。 - Duck
@Duck - 快速问题。如果我在套接字处进行分叉,我将如何知道要传递给客户端的新端口号作为参数? - fabricemarcelin
1
@fabricemarcelin - 通过在bind中指定端口号为0,您的服务器请求一个临时端口。然后,您可以通过调用getsockname()来获取分配的端口。 - Duck

1

避免使用fork(),而是根据客户端的源地址进行区分,这样会更好。

采取的基本方法是将当前描述应用程序层连接的所有变量(例如当前文件、文件中的当前位置、客户端地址)提升到一个struct中。然后为每个客户端创建一个此类struct实例。

使用recvfrom()而不是recv()来侦听传入的数据包。这将提供客户端的地址(注意,在这种情况下,地址应包括客户端的端口号),然后您可以查找适当的每个客户端struct实例。


你能否提供一些伪代码或指向类似的示例。谢谢。 - m4n07

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接