문제

Is it possible that a TCP server program can listen on two different socket interface?

Problem Statement:

I've a problem statement where the TCP server will be having two interfaces:

  • Interface I: For accepting generic data from TCP client (IP address 192.168.5.10:2000)
  • Interface II: Management Interface for the server (IP address 192.168.5.11:2000)

Interface I: This interface shall receive data from TCP client, processes them & send it back to client.

Interface II: This interface shall receive commands (meant for Servers management purpose). This commands most probably would be sent through telnet.

Current Status: I already have a thread based TCP server program where I've "Interface I" up & running(I'm able to receive data from multiple clients, process them & send it back)

Can anyone give me some pointers/prototype example on how to add "Interface II" to my TCP server program?

NOTE: TCP server program is written in C programming language for Linux OS

UPDATE

Below is the code fragment I've written so far for listening on one socket. I tried modifying it for listening over two sockets as you've directed but I'm facing trouble while trying to spawn a different thread for the other socket interface. Will it possible for you to modify this to listen on two sockets? It would be really helpful.

#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. Create two listening sockets using socket().
  2. Bind both to respective address/port using bind().
  3. Make both listen using listen().
  4. Add both listening sockets to a properly initialised fd_set typed variable using FD_SET().
  5. Pass the fd_set to a call to select()
  6. Upon select()'s return check the reason and perform the appropriate action, typically

    • either calling accept() on one of the both listening sockets and add the accepted socket (as returned by accept()) to the fd_set,

    • or if it's an accepted socket that had triggered select() to return, then call read(), write() or close() on it. If close()ing the socket also remove it from the fd_set using FD_CLR().

  7. Start over with step 5.

Important note: The steps above are a rough scheme, not mentioning all possible all traps, so it is absolutly necessary to also read the related man-pages for each step carefully, to understand what is happening.

다른 팁

you can bind 0.0.0.0 which means binding all interfaces. you can't bind two interfaces using only one socket. you should create a new socket, and bind ti to interface II.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top