简体   繁体   中英

socket file descriptors are the same among different processes

I have a simple server-client program. When I establish connections for all clients via a loop in the same c++ program, each client is assigned a different file descriptor for its connection to server. But when I establish connections in separate programs (eg using the following script), all clients get the same socket fd:

for i in {1..3}
do
  ./client &
done

The output in the first case (clients being invoked in a for-loop) is:

output on Server:
    For client 0 on sock 3
    For client 1 on sock 4
    For client 2 on sock 5
output on Client-version1: 
    Client connected to server on sock 4
    Client connected to server on sock 6
    Client connected to server on sock 7

and the output in the second case (being invoked in separate processes) is:

output on Server:
    For client 0 on sock 3
    For client 1 on sock 4
    For client 2 on sock 5
output on Client 1-version2: 
    Client connected to server on sock 3
output on Client 2-version2:    
    Client connected to server on sock 3
output on Client 3-version2:    
    Client connected to server on sock 3

Here's my code:

client(version 1).cpp

int main (int argc, char *argv[]) {
    int sockfd[3];
    std::string ip = "127.0.0.1";
    char temp_char;

    for (int i = 0; i < 3; i++) {
        establish_tcp_connection(ip.c_str(), 45678, &sockfd[i]);
        printf("Client connected to server on sock %d", sockfd[i]);
    }

    // make sure that the socket is not closed before other clients start
    // so, just send a dummy char back and forth
    for (int i = 0; i < 3; i++) 
        sock_sync_data (sockfd, 1, "W", &temp_char);    

    return 0;
}

client(version 2).cpp

int main (int argc, char *argv[]) {
    int sockfd;
    std::string ip = "127.0.0.1";
    char temp_char;

    establish_tcp_connection(ip.c_str(), 45678, &sockfd);
    printf("Client connected to server on sock %d", sockfd);

    // make sure that the socket is not closed before other clients start
    // so, just send a dummy char back and forth
    sock_sync_data (sockfd, 1, "W", &temp_char);    

    return 0;
}

Server.cpp

int main (int argc, char *argv[]) {
    int CLIENTS_CNT = 3;
    int server_sockfd;
    char temp_char;
    int sockfd[CLIENTS_CNT];

    struct sockaddr_in serv_addr, returned_addr;
    socklen_t len = sizeof(returned_addr);

    server_sockfd = socket (AF_INET, SOCK_STREAM, 0);

    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(45678);

    bind(server_sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
    listen (server_sockfd, CLIENTS_CNT);

    for (int c = 0; c < CLIENTS_CNT; c++){
        sockfd[c] = accept (server_sockfd, (struct sockaddr *) &returned_addr, &len);
        printf("For client %d on sock %d", c, sockfd[c]);
    }

    for (int c = 0; c < CLIENTS_CNT; c++) {
        /* just send a dummy char back and forth */
        sock_sync_data (sockfd[c], 1, "W", &temp_char); 
    }

    close(server_sockfd);
}

And here's my util code:

int sock_connect (std::string servername, int port) {
    int sockfd, n;
    struct sockaddr_in serv_addr;
    struct hostent *server;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(port);
    serv_addr.sin_addr.s_addr = inet_addr((char*)servername.c_str());
    if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) LESS_THAN_SIGN 0){ 
        printf("ERROR connecting");
        return -1;
    }
    return sockfd;
}

int establish_tcp_connection(std::string remote_ip, int remote_port, int *sockfd) {
    *sockfd = sock_connect (remote_ip, remote_port);
    if (*sockfd < 0) {
        printf("failed to establish TCP connection to server ");
        return -1;
    }
    return 0;
}

File descriptor is usually an index in file descriptor table which is created by OS kernel per each process. So, their numbers a actually independent, and number 3 you get is actually first number after (0, 1, 2 - stdin, stdout and stderr accordingly).

However socket pseudo-files may have inode numbers which are global across system. They are harder to reach.

File descriptors are specific to a process. There's nothing wrong with having the same number in two different processes refer to two different files. Indeed, FD 0 is always standard input, and standard input can be redirected for different processes.

In your second case, all three clients create different sockets, but they all have FD number 3 (within that process).

This is perfectly normal. A socket is just another file descriptor, so it's just a one-up... The OS's network stack handles all the endpoint information, etc, that you seem to believe should be part of the FD.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM