Один TCP-сервер и несколько клиентов - сервер взаимодействует только с последними подключенными клиентами - PullRequest
0 голосов
/ 11 июня 2018

Я использую функцию select () и пытаюсь запустить несколько клиентов.Каждый клиент - это независимый процесс.Но сервер, кажется, интересуется только последними подключенными клиентами.

Это мой client.c

#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include "mpi.h"
#define PORT 8888

int main(int argc, char const *argv[])
{
    /* Starting the MPI verion from here */

    // Initialize the MPI environment
    MPI_Init(NULL, NULL);

    // Get the number of generators to be run in parallel
    int number_of_clients;
    MPI_Comm_size(MPI_COMM_WORLD, &number_of_clients);

    // Get the rank of each generator
    int client_rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &client_rank);

    struct sockaddr_in address;
    int sock = 0, valread;
    struct sockaddr_in serv_addr;
    char *message1 = "Hello from client";
    char *message2 = "I am disconnecting";
    char buffer[1024] = {0};
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        printf("\n Socket creation error \n");
        return -1;
    }

    memset(&serv_addr, '0', sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);

    // Convert IPv4 and IPv6 addresses from text to binary form
    if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0) 
    {
        printf("\nInvalid address/ Address not supported \n");
        return -1;
    }

    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
    {
        printf("\nConnection Failed \n");
        return -1;
    }
    send(sock , message1 , strlen(message1) , 0 );
    printf("Hello message sent from client_rank %d\n",client_rank);
    valread = read( sock , buffer, 1024);


    buffer[valread] = '\0';
    printf("The message received from server by client_rank %d is %s\n", client_rank, buffer );
    send(sock, message2, strlen(message2), 0);
    printf("The message sent again from client_rank %d is %s\n", client_rank, message2);
    close(sock);
    // Finalize the MPI environment.
    MPI_Finalize();
    /*Ending the parallel version here*/

    return 0;
}

Это мой server.c

#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <errno.h> 
#include <unistd.h>   //close 
#include <sys/types.h> 
#include <sys/time.h> //FD_SET, FD_ISSET, FD_ZERO macros 

#define PORT 8888

int main(int argc, char const *argv[])
{
    int totalconnections = 0;
    int server_fd, new_socket, valread;
    struct sockaddr_in address, cli_addr;;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[1024] = {0};
    char *hello = "Hello from server";

    socklen_t clilen;
    int closed_connections = 0;
    int client_socket[3] , max_clients = 2 , activity, i , sd, max_sd;
    int connected_clients = 0;  
    fd_set readfds;

    //initialise all client_socket[] to 0 so not checked 
    for (i = 0; i < max_clients; i++)  
    {  
        client_socket[i] = 0;  
    } 

    // Creating socket file descriptor
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
    {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // Forcefully attaching socket to the port 8080
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR,(char *)&opt, sizeof(opt)) < 0)
    {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons( PORT );

    // Bind the server to the port and address
    if (bind(server_fd, (struct sockaddr *)&address,sizeof(address))<0)
    {
        perror("Binding Error : ");
        exit(EXIT_FAILURE);
    }
    //listen to the connections
    if (listen(server_fd, 5) < 0)
    {
        perror("Listen Error : ");
        exit(EXIT_FAILURE);
    }

    while(1)  
    {  
        //clear the socket set 
        FD_ZERO(&readfds);  

        //add master socket to set 
        FD_SET(server_fd, &readfds);  
        max_sd = server_fd;  

        //add child sockets to set 
        for ( i = 0 ; i < max_clients ; i++)  
        {  
            //socket descriptor 
            sd = client_socket[i];                 
            //if valid socket descriptor then add to read list 
            if(sd > 0)  
                FD_SET( sd , &readfds);                  
            //highest file descriptor number, need it for the select function 
            if(sd > max_sd)  
                max_sd = sd;  
        }      
        //wait for an activity on one of the sockets , timeout is NULL, so wait indefinitely 
        activity = select( max_sd + 1 , &readfds , NULL , NULL , NULL); 

        if ((activity < 0) && (errno!=EINTR))  printf("select error"); 

        //If something happened on the master socket ,then its an incoming connection 
        if (FD_ISSET(server_fd, &readfds))  
        {  
            if ((new_socket = accept(server_fd, (struct sockaddr *)&address,(socklen_t*)&addrlen))<0)  
            {  
                perror("accept");  
                exit(EXIT_FAILURE);  
            }  

            //Print out the details of the new connection 
            printf("New connection , socket fd is %d , ip is : %s , port : %d\n" , new_socket , inet_ntoa(address.sin_addr) , ntohs(address.sin_port));   

            //add new socket to array of sockets 
            for (i = 0; i < max_clients; i++)  
            {  
                //if position is empty 
                if( client_socket[i] == 0 )  
                {  
                    client_socket[i] = new_socket;                         
                    break;  
                }  
            }   
        }  

        //else its some IO operation on some other socket
        else
        {
            for (i = 0; i < max_clients; i++)  
            {  
                sd = client_socket[i];  

                if (FD_ISSET( sd , &readfds))  
                {  
                    //Read the incoming message. If valread = 0, then that client disconnected
                    valread = read( sd , buffer, 1024) ;
                    if(valread == 0) 
                    {  
                        //Somebody disconnected , get his details and print 
                        getpeername(sd , (struct sockaddr*)&address ,(socklen_t*)&addrlen);  
                        printf("Host disconnected , ip %s , port %d \n" ,inet_ntoa(address.sin_addr) , ntohs(address.sin_port));  

                        //Increase the closed connection by 1    
                        closed_connections++;  
                        client_socket[i] = 0;  
                    }  

                    //Send message to the client that sent the message
                    else
                    {  

                        buffer[valread] = '\0'; 
                        getpeername(sd , (struct sockaddr*)&address ,(socklen_t*)&addrlen);
                        printf("Message received from client connected to port %d is %s \n",ntohs(address.sin_port), buffer );
                        send(sd , hello , strlen(hello) , 0 );
                        printf("Hello message sent to client connected on port %d\n", ntohs(address.sin_port));
                    }  
                }  
            }            
        }

        //If all the clients disconnected then break out of while loop
        if(closed_connections == max_clients) break;
    }
    close(server_fd);
    return 0;
}

Компиляция client.c

gcc client.c -o client

Компиляция server.c

mpicc server.c -o server

Когда я запускаю сервер и клиент с помощью команды . / client и mpirun -np 2 ./client, я получаю следующий вывод на стороне сервера

 New connection , socket fd is 4 , ip is : 127.0.0.1 , port : 57448
    New connection , socket fd is 5 , ip is : 127.0.0.1 , port : 57450
    Message received from client connected to port 57450 is Hello from client 
    Hello message sent to client connected on port 57450
    Message received from client connected to port 57450 is Hello from client 
    Hello message sent to client connected on port 57450
    Host disconnected , ip 127.0.0.1 , port 57448 
    Host disconnected , ip 127.0.0.1 , port 57450 

Вывод на стороне клиента это:

Hello message sent from client_rank 0
Hello message sent from client_rank 1
The message received from server by client_rank 0 is Hello from server
The message received from server by client_rank 1 is Hello from server

Я не знаю, почему серверу плевать на старого клиента.

Вторая проблема, которую я также заметил, заключается в том, что сервер не получает сообщение2, отправленное клиентом, даже если я использовал функцию select ().Я думаю, что поскольку я использовал функцию выбора, сервер должен отслеживать любые запросы на отправку или отключение, отправленные клиентом.

Любая помощь будет признательна.

Ответы [ 2 ]

0 голосов
/ 11 июня 2018

В вашей программе имеется состояние гонки.

Клиент send() второе сообщение, а затем close() сокет сразу.

На стороне сервера, когда сообщениечитается, это всегда отправляется обратно клиенту.

Это означает, что SIGPIPE может произойти, если клиент close() сокет перед сервером (полностью) отправляет свой ответ.

0 голосов
/ 11 июня 2018

address - это всегда последний принятый клиент.Вы никогда не устанавливаете адрес клиента, с которого вы только что прочитали сообщение.Вы можете сделать это с помощью getpeername(), но было бы лучше просто напечатать фактические FD сокета вместо порта.

В любом случае сообщение всегда было неверным.Они не подключены к этому порту, они подключены к этому порту.

Так что здесь нет реальной проблемы №1, которую нужно решить.Просто вдвойне вводящие в заблуждение сообщения.

Вторая проблема, о которой вы упомянули, связана с вашей ошибкой проверки функций send() и recv().Таким образом, у вас нет доказательств того, что они не потерпели неудачу, поэтому нет никаких оснований ожидать идеальной работы.Попробуйте еще раз с проверкой ошибок.Может быть интересно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...