Sockets 单个TCP服务器和多个客户端-服务器似乎只与最后连接的客户端通信

Sockets 单个TCP服务器和多个客户端-服务器似乎只与最后连接的客户端通信,sockets,tcp,Sockets,Tcp,我正在使用select函数并尝试运行多个客户端。每个客户端都是独立的进程。但是服务器似乎只对最后连接的客户端感兴趣 这是我的客户 #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

我正在使用select函数并尝试运行多个客户端。每个客户端都是独立的进程。但是服务器似乎只对最后连接的客户端感兴趣

这是我的客户

#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;
}
编译服务器.c

当我使用命令./client和mpirun-np2./client运行服务器和客户机时,我在服务器端得到以下输出

客户端的输出是:

我不知道,为什么服务器不关心老客户机

我还注意到的第二个问题是,即使我使用了select函数,服务器也没有收到从客户端发送的message2。我认为,由于我使用了选择功能,服务器应该跟踪从客户端发送的任何发送或断开连接请求

任何形式的帮助都将不胜感激。

地址始终是最近接受的客户的地址。您从未将其设置回您刚刚从中读取消息的客户端地址。使用getpeername可以做到这一点,但最好只打印实际的套接字FD而不是端口

不管怎样,这个信息总是错误的。它们没有连接到该端口,而是从该端口连接的


所以这里没有要解决的实际问题1。只是双重误导的信息


您提到的第二个问题是由于未能对send和recv函数进行错误检查造成的。所以你没有证据表明他们没有失败,所以没有理由期待完美的运作。请通过错误检查重试。可能会很有趣。

您的程序中存在竞争条件

客户端发送第二条消息,然后立即关闭套接字

在服务器端,当读取消息时,总是将其发送回客户端


这意味着,如果客户端在服务器完全发送回复之前关闭套接字,则可能会出现SIGPIPE。

开始时,客户端打印此消息Hello message,该消息是从客户端\u秩%d发送的,但输出中没有此类内容。请编辑您的问题,并仔细检查输出是否与您的源匹配。@GillesGouaillardet这是仅从服务器输出的。您必须在客户端发送最后一个“\0”字符,或者在服务器端手动添加它,然后才能打印f…,bufalso请注意,您的程序不处理短发送和短接收,这也可能是一个问题。也就是说,为什么要混合使用MPI和TCP套接字?如果代码已经更改,那么输出也必须更改。您的问题不是自一致的。客户端应该打印从客户端再次发送的消息。\u等级0是我正在断开连接,但没有此类消息,这是实际问题。是的,使用getpeername解决了一个问题。现在服务器说它将发送到两个不同的客户端。但是服务器没有收到从客户端发送的消息2。为什么?您从未实现任何代码来处理消息。您只需读写流。如果您想发送和接收消息,您需要编写代码来完成此操作。@downvoter OP表示,这解决了一个问题。这到底有什么用处呢?所以这里没有实际问题需要解决。这完全是错误的。
#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;
}
gcc client.c -o client
mpicc server.c -o server
 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