侦听两个不同套接字接口的服务器程序

Posted

技术标签:

【中文标题】侦听两个不同套接字接口的服务器程序【英文标题】:Server program that listens on two different socket interfaces 【发布时间】:2014-01-04 15:05:00 【问题描述】:

有没有可能一个 TCP 服务器程序可以监听两个不同的套接字接口?

问题陈述:

我有一个问题陈述,其中 TCP 服务器将有两个接口:

接口 I:用于接受来自 TCP 客户端的通用数据(IP 地址 192.168.5.10:2000) 接口二:服务器管理接口(IP地址192.168.5.11:2000)

接口 I:此接口应从 TCP 客户端接收数据,处理它们并将其发送回客户端。

接口 II:该接口应接收命令(用于服务器管理目的)。该命令很可能会通过 telnet 发送。

当前状态: 我已经有一个基于线程的 TCP 服务器程序,我已经启动并运行了“Interface I”(我能够从多个客户端接收数据,处理它们并发送它回来了)

谁能给我一些关于如何将 "Interface II" 添加到我的 TCP 服务器程序的指针/原型示例?

注意:TCP 服务器程序是用 C 语言编写的 Linux 操作系统

更新

下面是迄今为止我编写的用于侦听一个套接字的代码片段。我尝试按照您的指示修改它以侦听两个套接字,但是在尝试为另一个套接字接口生成不同的线程时遇到了麻烦。您是否可以修改它以侦听两个套接字?真的很有帮助。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>

void *data_processing_thread(void *arg);

int main(int argc, char **argv) 

        int fdmax, listener, newfd, res;
        int optval=1;
        socklen_t addrlen;
        int server_port = 4000;

        /* master, temp file descriptor list */
        fd_set *master, *read_fds;

        /* client, server address */
        struct sockaddr_in server_addr, client_addr;
        pthread_t thread;

        master = malloc(sizeof(fd_set));
        read_fds = malloc(sizeof(fd_set));

        FD_ZERO(master);
        FD_ZERO(read_fds);

        /* create endpoint for communication */
        if ((listener = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
                perror("failed to create listener\n");
                return -1; 
        
/* check if address is already in use? */
        if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &optval,
                                sizeof(int)) == -1)  
                perror("socket address already in use!\n");
                return -1;
        

        /* bind */
        server_addr.sin_family = AF_INET;
        server_addr.sin_addr.s_addr = INADDR_ANY;
        server_addr.sin_port = htons(server_port);
        memset(&(server_addr.sin_zero), '\0', 8);

        if (bind(listener, (struct sockaddr*)&server_addr,
                                sizeof(server_addr)) == -1) 
                perror("failed to do the bind\n");
                return -1;
        

        /* listen for connect on sockets */
        if (listen(listener, 10) == -1) 
                perror("failed to listen on socket\n");
                return -1;
        
 /* add the listener to the master set */
        FD_SET(listener, master);
        /* keep track of biggest file descriptor */
        fdmax = listener;

        while (1) 
                read_fds = master;
                /* wait till socket descriptor is ready for the operation */
                if (select(fdmax+1, read_fds, NULL, NULL, NULL) == -1) 
                        perror("failed to do select() on socket\n");
                        return -1;
                

                /* Run through existing data connections looking for data to be
                 * read */
                int cnt;
                int *accept_fd = 0;
                for (cnt=0; cnt<=fdmax; cnt++) 
                        if (cnt == listener) 
                                if (FD_ISSET(cnt, read_fds)) 
                                        addrlen = sizeof(client_addr);
                                        if ((newfd = accept(listener, (struct sockaddr*)&client_addr, &addrlen)) == -1) 
                                                perror("failed to accept incoming connection\n");
                                         else 
                                                fprintf(stdout, "Server: Connection from client [%s] on socket [%d]\n",
                                                                inet_ntoa(client_addr.sin_addr), newfd);

accept_fd = malloc(sizeof(int));
                                                *accept_fd = newfd;

                                                if ((res = pthread_create(&thread, NULL, data_processing_thread, (void*)accept_fd)) != 0) 
                                                        perror("Thread creation failed\n");
                                                        free(accept_fd);
                                                
                                        
                                
                                continue;
                        
                
        

        return 1;


void *data_processing_thread(void *arg)

        int nbytes;
        int *recv_fd = (int*)arg;
        char *buffer = malloc(sizeof(char)*256);

        while(1) 
                fprintf(stdout, "Server: Waiting for data from socket fd %d\n", *recv_fd);

                /* receive incoming data from comm client */
                if ((nbytes = recv(*recv_fd, buffer, sizeof(buffer), 0)) <= 0) 
                        if (nbytes != 0) 
                                perror("failed to receive\n");
                        
                        break;
                 else 
                        fprintf(stdout, "Data received: %s\n", buffer);
                
        
        close(*recv_fd);
        free(recv_fd);
        pthread_exit(0);

【问题讨论】:

我正在寻找的是一个 TCP 服务器程序示例,它打开了两个不同的套接字——一个用于处理数据,另一个用于处理管理命令。我需要保持这两个接口不同。谁能帮我解决这个问题? 你测试过这段代码吗?有用吗? 是的,它确实有效。为什么? 【参考方案1】:
    使用socket() 创建两个监听套接字。 使用bind()将两者绑定到各自的地址/端口。 使用listen() 让两者都收听。 使用FD_SET() 将两个侦听套接字添加到正确初始化的fd_set 类型变量。 将fd_set 传递给select() 的调用

    select() 的返回检查原因并执行适当的操作,通常是

    在两个侦听套接字之一上调用accept() 并将接受的套接字(由accept() 返回)添加到fd_set

    或者如果它是触发select()返回的已接受套接字,则在其上调用read()write()close()。如果close()ing 套接字也使用FD_CLR() 将其从fd_set 中删除。

    从第 5 步重新开始。

重要提示:以上步骤是一个粗略的方案,没有提及所有可能的所有陷阱,因此绝对有必要仔细阅读每个步骤的相关手册页,以了解正在发生的事情。

【讨论】:

我已经粘贴了在一个套接字上侦听的更新代码。但是我无法编写用于侦听第二个套接字的代码部分。我面临的问题是从第二个插座的第 5 步开始。无法理解如何在第二个套接字上进行选择以及如何生成一个单独的线程来处理在第二个套接字接口上接收到的命令。请帮忙? 您根本不会“在第二个套接字上进行选择”。您可以同时在 both 套接字上执行 select(),方法是将它们都放在 fd_set. 中。同样,您也可以同时选择所有接受的套接字。这就是 select() 的用途:复用 I/O。 注意select()修改了传递给它的fd_set,所以每次调用select()时都必须用相关的socket构造一个新的fd_set。为避免这种情况,您可以改用poll() 好的,明白了。因为我正在监听所有可用的接口(使用 INADDR_ANY),所以我所做的只是产生了一个与 data_processing_thread() 不同的线程,用于处理可用接口中的一个接口的命令。它确实为我的问题提供了解决方案。感谢您的帮助。 我不知道为什么人们在不使用提供的答案时会在这里提问。【参考方案2】:

你可以绑定0.0.0.0,即绑定所有接口。 您不能仅使用一个套接字绑定两个接口。 您应该创建一个新的套接字,并将 ti 绑定到接口 II。

【讨论】:

以上是关于侦听两个不同套接字接口的服务器程序的主要内容,如果未能解决你的问题,请参考以下文章

远程登录我的套接字侦听端口正在关闭套接字

不同用户会话中 Windows 服务和应用程序之间的通信

将套接字传递给新的 AppDomain

两个独立应用程序之间的通信

客户端可以同时有两个连接到同一个套接字侦听器吗?

您的服务器套接字侦听积压限制为 100 个连接