Socket between 2 clients and 1 C server

Asked

Viewed 8,664 times

10

How to receive two connections?

The system consists of 2 clients and 1 server, the server must receive the connections and initiate a sequential conversation with the clients. I was able to implement the communication between 1 client and the server (sequential communication via terminal is working), I don’t know how to get the second connection with the 2nd client. Because through this solution I can implement the logic of the business where the server will receive information process and return it.

Servicormain. c

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

#define PORTA 8585
#define BYTE 1024

main(){
        char mensagem[BYTE], *loc;
        int pontarq, tbuf, skt, tskt, escolha;
        struct sockaddr_in serv;

        system("clear");
        /**INICIALIZA ESTRUTURA SOCKETS*/
        skt = socket(AF_INET, SOCK_STREAM, 0);
        serv.sin_family = AF_INET;
        serv.sin_addr.s_addr = INADDR_ANY;
        serv.sin_port = htons (PORTA);
        memset(&(serv.sin_zero),0x00,sizeof(serv.sin_zero));
        tskt = sizeof(struct sockaddr_in);

        printf("\n    ############### Server ###############\n\n");
        /**SOCKET INICIALIZA LISTENER PARA OUVIR PORTA*/
        bind(skt,(struct sockaddr *)&serv,sizeof(struct sockaddr));
        listen(skt,1);
        printf(">> Servidor esta escutando na porta %d\n\n",PORTA);

        /**RECEBE NOVAS CONEXÕES*/
        //O problema acho que está aqui, preciso receber mais uma conexão para o sistema continuar.
        skt = accept(skt,(struct sockaddr *)&serv,&tskt);
        printf(">> A Conexao com o endereco %s foi estabelecida\n\n",inet_ntoa(serv.sin_addr));


        /**ENVIA MENSAGEM PARA CLIENTE*/
        strcpy(mensagem,"Servidor diz: olá!!!");
        send(skt,mensagem,strlen(mensagem), 0);
        sendto()
        send()
        sent
        /**RECEBE MENSAGEM DE CLIENTE*/
        tbuf = recv(skt, mensagem,BYTE, 0);
        mensagem[tbuf]=0x00;
        printf(">: %s\n",mensagem);


        /**LOOP DE COMUNICAÇÃO ENTRE CLIENTE E SERVIDOR*/
        do{
        ///recebe
        tbuf = recv(skt,mensagem,BYTE,0);
        mensagem[tbuf]=0x00;
        printf(">: Cliente diz: %s\n",mensagem);

        ///envia
        printf("> ");
        gets(mensagem);
        send(skt, mensagem, strlen(mensagem), 0);


        }while(strcmp(mensagem,"/x") != 0); ///COMUNICAÇÃO SE ENCERRA QUANDO USUARIO ENVIAR MSG= /X

        close(skt);
        printf(">> A Conexao com o host %s foi encerrada!!!\n\n",inet_ntoa(serv.sin_addr));
        exit(0);
    }

Clientemain. c

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


#define SERVER_IP "127.0.0.1"
#define BYTE 1024
#define PORTA 8585
#define TITULO "\n    ############### BeM VinDo ###############\n\n"

void imprimirAguarde(void);

/************************
*          MAIN         *
************************/
main ()
{

    char mensagem[BYTE], *loc;
    int tbuf, skt, escolha;
    struct sockaddr_in serv;
    system("clear");

    /**INICIALIZA ESTRUTURA SOCKETS*/
    skt = socket(AF_INET, SOCK_STREAM, 0);
    serv.sin_family = AF_INET;
    serv.sin_addr.s_addr = inet_addr(SERVER_IP);
    serv.sin_port = htons (PORTA);
    memset (&(serv.sin_zero), 0x00, sizeof (serv.sin_zero));

    /**INICIA COMUNICAÇÃO COM SERVIDOR*/
    while(connect (skt, (struct sockaddr *)&serv, sizeof (struct sockaddr)) != 0){
        imprimirAguarde();      ///AGUARDA SERVIDOR SE COMUNICAR
    }
    printf(">> A Conexao com o Servidor %s foi estabelecida na porta %d \n\n",SERVER_IP,PORTA);
    printf(">> Envie /x pra sair \n\n");


    /**RECEBE MENSAGEM DO SERVIDOR*/
    tbuf = recv (skt, mensagem, BYTE, 0);
    mensagem[tbuf] = 0x00;
    printf (">: %s\n",mensagem);

    /**ENVIA MENSAGEM PARA O SERVIDOR*/
    strcpy(mensagem, "Cliente diz: olá!!!");
    send(skt, mensagem, strlen(mensagem), 0 );


    /**LOOP DE COMUNICAÇÃO ENTRE CLIENTE E SERVIDOR*/
    do{
        ///envia
        printf("> ");
        gets(mensagem);
        send(skt, mensagem, strlen(mensagem), 0);

        ///recebe
        tbuf = recv (skt, mensagem, BYTE, 0);
        mensagem[tbuf] = 0x00;
        printf (">: Servidor diz: %s\n",mensagem);

    }while(strcmp(mensagem,"/x")!= 0);    ///COMUNICAÇÃO SE ENCERRA QUANDO USUARIO DIGITAR /X


    /**FINALIZA CONEXÃO*/
    close(skt);
    printf (">>A conexao com o servidor foi finalizada!!!\n\n");
    exit(0);
}



/**************************************************************
*   FUNÇÃO RESPOSÁVEL POR IMPRIMIR MENSAGER NA TELA           *
*   ENQUANTO AGUARDA ALGUM SERVIDOR ESTABELECER COMUNICAÇÃO   *
***************************************************************/
void imprimirAguarde(){
    int i=0;
    char dot[12] = "";
    for(i=0; i<4;i++){
        system("clear");
        printf(TITULO);
        printf("\n\nProcurando servidor.");
        printf("\nAguarde %s\n\n", dot);
        strcat(dot,".");
        sleep(1);
    }
    strcpy(dot, "");
}
  • If you want to warm your brains, follow a PHP implementation of a server that serves several clients at this link - I know the language is completely different, but the main logic can serve as a basis. The essential thing: 1 loop that is serving all clients, and accepting new connections (but without blocking. if you have client, accept, or continue), each client having its independent "struct" (done array in the case of PHP), and each valid Accept creating an instance of that struct.

1 answer

4


You have basically three paths:

1) delegate the received connection socket to Accept() for a child process, using Fork(). An example you can base on is https://github.com/elvis-epx/prd-progs/blob/master/bsd_servidor.c.

2) Use select() or Poll() to handle all sockets, including the listening one, in a single process. An example is http://www.gnu.org/software/libc/manual/html_node/Server-Example.html.

3) use threads, one thread for each connection, keeping the main thread only for the listening socket.

Option (1) is the simplest in every respect: it changes your original program slightly and ensures that one connection does not interfere with the other (because each one runs in a separate process).

Option (2) is the most elegant from the POSIX programming point of view as it saves resources (uses only one process and one thread). It is also possible to embed timeout treatment in the call to select() or Poll(). On the other hand it is the most complex to implement: your program has to store the state of each connection and react asynchronously to the received data, erase the state when the respective connection closes, etc.

Option (3) is usually discouraged by additional complexity. Threading is always trouble, only used when it is highly justified. It is interesting to note that in languages like Java, using thread would be the only option because you cannot instantiate child processes and there is asynchronous programming in Java.

Note that this answer aims to answer the original question: how to serve more than one customer at the same time. There are many scalability considerations for your server to meet thousands or tens of thousands of simultaneous connections, and the right answer would then depend on how your application protocol actually works.

  • 1

    Option 1. is extremely heavy: fork() is one of the heaviest syscalls. A 2. is cool, but does not scale. I do not understand the general fear of using thread. They are simple, well understood and fundamental to a scalar application in current processors. And the ideal is to use 2. with 3.: multiple threads, each managing multiple connections.

  • I’m sorry, but I disagree with your disagreement :) For starters, all the question is to enable competition between two customers. Scalability considerations are a complex problem, far beyond the scope of the question.On option 1 being extremely cumbersome, this depends on the application protocol. If the server is to serve millions of simultaneous clients using connections that last only a few milliseconds, maybe one Fork() per client is heavy, but in a case of few clients and long-lasting connections, Fork() is sufficient, and it is quite fast in modern UNIX qq.

  • The fact is that even HTTP servers have already been implemented using Fork() in the past, and are still implemented for didactic purposes, and they work. On option 2, it scales and quite well in order to be able to control thousands of short-term connections. Only if the processing to handle each connection is heavy would you have to think about delegating this processing to subprocesses or threads. As for option 3, I wanted to refer to the use of a thread per connection, which is a naive but very common form. I will clarify this in my original reply.

  • There is no greater proof than the Fastcgi protocol to show that the fork does not scale. Only advantage I see for the fork, is the fact that if an instance suffers an exception, the others continue to run. Therefore, in addition to being controllable (kill Ftw), it can offer more stability. But it is slower, not scaled.

  • I am studying about the POSIX Thread (Pthreads) someone knows, is it valid use or is it preferred Fork? it is very easy to create threads with it.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.