首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >单个TCP服务器和多个客户端-服务器似乎仅与最后连接的客户端通信

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

Stack Overflow用户
提问于 2018-06-11 07:48:10
回答 2查看 75关注 0票数 0

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

这是我的客户。c

代码语言:javascript
复制
#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

代码语言:javascript
复制
#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;
}

编译客户端.c

代码语言:javascript
复制
gcc client.c -o client

编译server.c

代码语言:javascript
复制
mpicc server.c -o server

当我使用命令./ client 运行-np 2 ./client来运行服务器和客户端时,我在服务器端的上得到了以下输出

代码语言:javascript
复制
 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 

客户端的输出为:

代码语言:javascript
复制
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

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

我还注意到的第二个问题是,即使我使用了message2 ()函数,服务器也无法接收从客户端发送的select。我认为既然我使用了select函数,服务器应该跟踪从客户端发送的任何send或disconnect请求。

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

EN

回答 2

Stack Overflow用户

发布于 2018-06-11 08:47:26

您的程序中存在争用条件。

客户端send()第二个消息,然后立即close()套接字。

在服务器端,当一条消息被读取时,它总是被发送回客户端。

这意味着如果客户端在服务器(完全)发送其回复之前close()套接字,就会发生SIGPIPE

票数 1
EN

Stack Overflow用户

发布于 2018-06-11 08:20:56

address总是最近被接受的客户端的客户端。您永远不能将其重新设置为您从其读取消息的客户端的地址。使用getpeername()可以做到这一点,但只打印实际的套接字FD而不是端口会更好。

无论如何,这条信息总是错误的。它们没有连接到那个端口,它们是从那个端口连接的。

因此,这里没有实际的问题#1需要解决。只是双重误导信息。

您提到的第二个问题是由于没有对send()recv()函数进行错误检查而导致的。因此,您没有证据表明它们没有失败,因此没有理由期望完美的操作。使用错误检查再试一次。可能会很有趣。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50789019

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档