Question

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);
}
Was it helpful?

Solution

  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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top