csocketsclient-serveripcposix-select

Client to Client communication using select() function in c


I was trying to implement a client to client communication with a server in between them. The function of the server is that when a client suppose Client A sends a message to the server, the server should forward that message to the other client, Client B. Same way when the Client B sends a message to the server it should be forwarded to Client A. This programs involves only two clients. The error I get when I execute the code is that it says:

Socket Operation on Non-socket

I get this error when the received message from Client A is forwarded to Client B. I think the issue is due to the storing of received address of Client B to the address of Client A. I'm not sure about that.

My server code so far.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <sys/time.h>
#define SERVER_PORT 5009


int main(){
unsigned int sockfd, c,c1,c2, clientlen, clientfd;
struct sockaddr_in server;
struct sockaddr_in client1;
int clientsocks[2];
char rmsg1[100], msg1[100],rmsg2[100], msg2[100];
char w_msg[] = "Connection to server established";

fd_set readfds; // For temp file descriptor list.

clientsocks[0] = 0 ;
clientsocks[1] = 0 ;
//Socket Creation Process.
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if( sockfd < 0){
    perror("Socket cannot be created");
}

//For reusing the socket.
int on = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
//Socket address
bzero((char *) &server, sizeof(server));
server.sin_family = AF_INET; // IPv4 internet Protocols
inet_aton("127.0.0.1", &server.sin_addr);
server.sin_port = htons(SERVER_PORT);

//Binding socket to address.
if (bind( sockfd, (struct sockaddr*)&server, sizeof (server) ) < 0 ){
    perror("Bind Error");
    exit(EXIT_FAILURE);
}

//Listen to accept connection.
if( listen(sockfd, SOMAXCONN) < 0 ){
    perror("Error in Listen");
    exit(EXIT_FAILURE);
}

unsigned int new_sock;
clientlen =sizeof(client1);
int activity;
while(1){

    //Clear socket set.
    FD_ZERO(&readfds);

    //Adding main sockfd to the socket set.
    FD_SET(sockfd, &readfds);
    unsigned int max_sd = sockfd;

    //Add child sockets to set.
    for(int i=0 ; i<2; i++){
           c = clientsocks[i];
        if(c > 0)
            FD_SET(c, &readfds);
        if(c > max_sd)
            max_sd = c;
    }

    activity = select(max_sd + 1, &readfds, NULL, NULL, NULL);
    if(activity < 0){
        perror("Error in select()");
        exit(EXIT_FAILURE);
    }

    //Incoming connection when something happens on sockfd.
    if( FD_ISSET(sockfd, &readfds)){
        new_sock = accept(sockfd, (struct sockaddr *) &client1, &clientlen);
        if(new_sock > 0){
            for(int i=0; i<2; i++){
                if(clientsocks[i] == 0){
                    clientsocks[i] = new_sock;
                    break;
                }
            }
        }
        if(  new_sock < 0){
            perror("Error Accepting");
            exit(EXIT_FAILURE);
        }
        if( send(new_sock, w_msg, strlen(w_msg), 0) != strlen(w_msg)){
            perror("Welcome message");
            exit(EXIT_FAILURE);
        }
    c1 = clientsocks[0];
    c2 = clientsocks[1];
    FD_SET(c1, &readfds);
    FD_SET(c2, &readfds);
    }

    //Else if its not a new incoming connection.
    if(FD_ISSET(c1, &readfds)){
        if(recv(c1, rmsg1, 100, 0) < 0){
            perror("Receive 1");
            exit(EXIT_FAILURE);
        }
        printf("Client1 >> %s\n", rmsg1);
        //Forwarding to Client B.
        if( send(c2, rmsg1, 100, 0) < 0){
            perror("Error forwarding to 2");
            exit(EXIT_FAILURE);
        }
    }
    if(FD_ISSET(c2, &readfds)){
        if(recv(c2, rmsg2, 100, 0) < 0){
            perror("Receive 2");
            exit(EXIT_FAILURE);
        }
        printf("Client2 >> %s\n", rmsg2);
        if( send(c1, rmsg2, 100, 0) < 0 ){
            perror("Error Forwarding to 1");
            exit(EXIT_FAILURE);
        }
    }
}
close(sockfd);
return 1;
}

My problem involves two clients only. I would really appreciate if you could point out some other improvements also.


Solution

  • You've got some structural problems that isn't really the job of StackOverflow members to fix.

    1. Decide if each client is going to connect on the same socket or their own unique socket, listen accordingly.
    2. If you have a shared connection, which it seems you are going for... and by shared connection I mean you are listening on one port and doing multiple accepts, then after a given accept you can't assume who has connected until you read some data from the port. You should have each client send some information through, so that you know if A connected and then B or if B connected and then A.
    3. The code around your setsockopt seems like you forgot {}
    4. When saving the clientsocks you can use the information from the client to determine which array slot to use. Maybe you have 100 clients and they each connect and then send a 32 bit word (which contains their client number, between 1-100).
    5. Once you can read messages from various clients (probably want to print them out for now so you can see what is happening), you can build in various messages. The goal is for client A to be able to ask the server for the contact information of client B so that A can directly connect to B and send B a message.
    6. OR, instead of #5, Client 26 should be able to send a message to the server, indicating its is for client 45 and the server should be able to check the array of clients that have checked in and then send the message to the client in array slot 45.
    7. Clients need to have unique ID/numbers so the server has a way to map the client ID's to clientarray sockets.
    8. Some of those errors are better handled directly than causing the server to exit. Maybe you can close the socket associated with the socket index causing the error. Your error messages should indicate which client/socket index caused the error. You, in general, need more debug messages and more information in the messages.