2015-02-22 5 views
2

У меня простая клиент-клиентская программа. Когда я устанавливаю соединения для всех клиентов через цикл в одной и той же программе на C++, каждому клиенту назначается другой файловый дескриптор для его подключения к серверу. Но когда я устанавливаю связи в отдельных программах (например, используя следующий скрипт), все клиенты получают один и тот же сокет ФД:дескрипторы файлов сокетов одинаковы для разных процессов.

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

Выход в первом случае (клиенты быть использовано в для цикла) является:

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 

и выход во втором случае (будучи вызван в отдельных процессах) является:

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 

Вот мой код:

клиент (версия 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; 
} 

клиента (версия 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); 
} 

А вот мой использовать Код:

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; 
} 
+0

Каков результат работы с клиентом и сервером? – immibis

+1

Почему, по вашему мнению, клиенты должны получать разные номера FD? – immibis

+0

@immibis Я немного изменил вопрос. Что касается вопроса, не так ли? Возможно, я ошибаюсь, но я думал, что каждый вызов функции 'socket' должен возвращать уникальный дескриптор файла. – narengi

ответ

2

Дескриптор файла обычно является индексом в таблице дескриптора файла, который создается ядром ОС на каждый процесс. Таким образом, их числа фактически независимы, а число 3, которое вы получаете, на самом деле первое число после (0, 1, 2 - stdin, stdout и stderr соответственно).

Однако псевдофайлы сокета могут иметь номера inode, которые являются глобальными по всей системе. Их труднее достичь.

+0

поэтому, когда два отдельных процесса записывают/читают на сокетах с одинаковым номером сокета, они на самом деле пишут/читают/с разных конечных точек? – narengi

+0

@narengi Не совсем. Когда вы пытаетесь читать из сокета с fd = 3, вы вызываете 'read (3, ...) ', ОС проверяет третью запись в таблице fd, обнаруживает, что она является сокетом и передает ваш запрос в сетевой стек с соответствующим объектом сокета (который хранится в таблице fd). Магия, которая происходит в сетевом стеке, немного сложна, но не связана с общим уровнем обработки файлов. – myaut

+1

@narengi, попробуйте вызвать 'lsof -p '. Надеюсь, это улучшит ваше понимание того, что на самом деле является fd. – myaut

1

Это совершенно нормально. Сокет - это еще один файловый дескриптор, поэтому он всего лишь один ... Сетевой стек ОС обрабатывает всю информацию о конечной точке и т. Д., Которые, как вам кажется, должны быть частью FD.

2

Дескрипторы файлов относятся к процессу. Нет ничего плохого в том, что один и тот же номер в двух разных процессах относится к двум различным файлам. Действительно, FD 0 всегда является стандартным входом, а стандартный ввод может быть перенаправлен для разных процессов.

В вашем втором случае все три клиента создают разные сокеты, но все они имеют FD номер 3 (внутри этого процесса).

Смежные вопросы