c - 监听两个不同套接字接口(interface)的服务器程序

标签 c linux sockets tcpserver

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

问题陈述:

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

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

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

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

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

谁能给我一些关于如何将“接口(interface) II” 添加到我的 TCP 服务器程序的指示/原型(prototype)示例?

注意:TCP 服务器程序是用 C 编程语言为 Linux OS 编写的

更新

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

#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);
}

最佳答案

  1. 使用 socket() 创建两个监听套接字。
  2. 使用 bind() 将两者绑定(bind)到各自的地址/端口。
  3. 使用 listen() 让两者都听。
  4. 使用 FD_SET() 将两个监听套接字添加到正确初始化的 fd_set 类型变量。
  5. fd_set 传递给对 select() 的调用
  6. select() 返回时检查原因并执行适当的操作,通常是

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

    • 或者如果它是一个触发了 select() 返回的已接受套接字,则调用 read()write()close() 就可以了。如果 close() 也使用 FD_CLR() 将套接字从 fd_set 中移除。

  7. 从第 5 步重新开始。

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

关于c - 监听两个不同套接字接口(interface)的服务器程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20922571/

相关文章:

java - 使用 java ssl 套接字时是否也需要加密流?

c - 意外的结果 - 寻找最大值和第二最大值

c++ - 如何在 C++ 程序中启动可执行文件并获取其进程 ID(在 Linux 中)?

c - GCC double 浮点运算的特殊优化选项

linux - Docker Ubuntu 无法统计 'keys/id_rsa' 没有这样的文件或目录

检查linux中特定程序使用的服务

java - Android 6(棉花糖)的 SSLHandshakeException SSLProtocolException

c - 静态内存分配和动态内存分配哪个效率更高

c - 监听 PF_NETLINK 套接字时获取所有链接和地址信息

c - 如何使这个函数定时宏在 C 中工作?