2017-02-09 24 views
0

Я хотел бы построить модель клиент-сервер, где для любого количества клиентов, подключенных к серверу, сервер должен отправить широковещательное сообщение. Ниже приведен код, который я реализовал, он не вызывает никаких ошибок, но я не вижу связи между сервером и клиентом. Пожалуйста, дайте мне знать, где проблема в коде.Программирование сокетов (клиент - сервер UDP)

Я хотел бы видеть сообщение, переданное с сервера в системе клиентов.

/************* UDP SERVER CODE *******************/ 

#include <stdio.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <string.h> 
#include <stdlib.h> 

int main(int argc, char *argv[]){ 
    int udpSocket, nBytes, buflen; 
    char buffer[1024]; 
    char string[1024]; 
    int portNum; 
    struct sockaddr_in serverAddr, clientAddr; 
    struct sockaddr_storage serverStorage; 
    socklen_t addr_size, client_addr_size; 
    int i; 

    /*Create UDP socket*/ 
    udpSocket = socket(AF_INET, SOCK_DGRAM, 0); 
    portNum=atoi(argv[1]); 
    /*Configure settings in address struct*/ 
    serverAddr.sin_family = AF_INET; 
    serverAddr.sin_port = htons(5000); 
    serverAddr.sin_addr.s_addr = inet_addr("192.168.1.117"); 

    memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero); 

    /*Bind socket with address struct*/ 
    int bStatus=bind(udpSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr)); 
    if (bStatus < 0) { 
     printf("error binding on server's port number\n"); 
     exit(1); 
    }  


    /*Initialize size variable to be used later on*/ 
    addr_size = sizeof serverStorage; 

memset(&clientAddr, 0, sizeof(clientAddr)); 
    clientAddr.sin_family = AF_INET; 
    clientAddr.sin_port = htons(portNum); // this is where client is bound 
    clientAddr.sin_addr.s_addr = inet_addr("192.168.1.114"); 

    while(1){ 
sprintf(buffer,"Hello Client"); 
    buflen=strlen(buffer); 
    int bytesSent = sendto(udpSocket,buffer,buflen,0,(struct sockaddr *)&clientAddr, sizeof(clientAddr)); 
    if (bytesSent < 0) { 
     printf("Error sending/ communicating with client\n"); 
     exit(1); 
    } 
    printf("%s\n",buffer); 

/* 
// **************************************************** 

memset(buffer, 0, 1024); 
buflen=65536; 
recvfrom(udpSocket,buffer,buflen,0,(struct sockaddr *)&serverStorage, &addr_size); 
printf("Received from server: %s\n",buffer); 

*/ 
} 

    return 0; 
} 

Ниже приведен код клиента:

 /************* UDP CLIENT CODE *******************/ 

#include <stdio.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <string.h> 

int main(int argc, char *argv[]){ 
    int clientSocket, portNum, nBytes, buflen; 
    char buffer[1024]; 
    char string[1024]; 
    struct sockaddr_in serverAddr,clientAddr; 
    socklen_t addr_size; 

    /*Create UDP socket*/ 
    clientSocket = socket(AF_INET, SOCK_DGRAM, 0); 
portNum = atoi(argv[1]); 
    /*Configure settings in address struct*/ 
    serverAddr.sin_family = AF_INET; 
    serverAddr.sin_port = htons(portNum); 
    serverAddr.sin_addr.s_addr = inet_addr("192.168.1.117"); 

// memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero); 
memset(&serverAddr,0,sizeof(serverAddr)); 


// binding 
bind(clientSocket, (struct sockaddr *) &clientAddr, sizeof(clientAddr)); 


    /*Initialize size variable to be used later on*/ 
    addr_size = sizeof serverAddr; 

    while(1){ 

memset(buffer, 0, 1024); 
buflen=65536; 
recvfrom(clientSocket,buffer,buflen,0,(struct sockaddr *)&serverAddr, &addr_size); 
//recvfrom(clientSocket,buffer,buflen,0,NULL,NULL); 
printf("Received from server: %s\n",buffer); 

/* 
//******************************************************************** 

sprintf(buffer,"Hello Client");  
buflen=strlen(buffer); 
sendto(clientSocket,buffer,buflen,0,(struct sockaddr *)&serverAddr,addr_size); 
printf("%s\n",buffer); 
*/ 
} 

return 0; 
} 
+0

Вы не должны «связывать» с принимающим концом? –

+2

"* UDP *", "* connected *", hmmm? – alk

+0

@KevinDTimm это не действительный код C++? –

ответ

0

На высоком уровне есть несколько вещей, которые должны быть решены. Учитывая код в посте имеет сервер, который инициирует связь с клиентом следующей строкой необходимо изменить (и связанный с ними код для них)

На стороне сервера:

sendto(udpSocket,buffer,buflen,0,(struct sockaddr *)&serverStorage,addr_size); 

По сути то, что здесь происходит, что udpSocket привязан к serverAddr, и мы пытаемся отправить serverStorage (второй последний аргумент). Проблема заключается в том, что серверная система не привязана ни к чему. В основном sendto имеет право источника, но не пункт назначения.

На стороне клиента:

recvfrom(clientSocket,buffer,buflen,0,(struct sockaddr *)&serverAddr, &addr_size); 

ClientSocket не связан ни к чему, так что система выбирает случайный порт, где он будет слушать. В вызове recvfrom второй последний аргумент фиксирует данные адреса другой стороны. Если в коде вы привязали его к IP-адресу и порту сервера, это не имеет никакого эффекта, поскольку оно заполняется вызовом recvfrom и возвращается.

Чтобы заставить вещи работать здесь то, что я хотел бы предложить (вы можете добавить детали, но разработали скелет, основанный на том, что вы вывесили)

server_initiating_with_client.c

//... 
    int udpSocket, nBytes, buflen; 
    char buffer[1024]; 
    int portNum; 
    struct sockaddr_in serverAddr, clientAddr; 
    struct sockaddr_storage serverStorage; 
    socklen_t addr_size, client_addr_size; 

    /*Create UDP socket*/ 
    udpSocket = socket(AF_INET, SOCK_DGRAM, 0); 
    portNum=atoi(argv[1]); 
    /*Configure settings in address struct*/ 
    memset(&serverAddr, 0, sizeof(serverAddr)); 
    serverAddr.sin_family = AF_INET; 
    serverAddr.sin_port = htons(5000); // Making sure server has a unique port number 
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); 

    /*Bind socket with address struct*/ 
    int bStatus = bind(udpSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr)); 
    if (bStatus < 0) { 
     printf("error binding on server's port number\n"); 
     exit(1); 
    } 

    /*Initialize size variable to be used later on*/ 
    addr_size = sizeof serverStorage; 

    /* Because server is initiating the communication here one needs to set the 
    * clientAddr and needs to know the port number of the client 
    */ 
    memset(&clientAddr, 0, sizeof(clientAddr)); 
    clientAddr.sin_family = AF_INET; 
    clientAddr.sin_port = htons(portNum); 
    clientAddr.sin_addr.s_addr = htonl(INADDR_ANY); 

    while(1){ 
     sprintf(buffer,"Hello Client"); 
     buflen=strlen(buffer); 
     int bytesSent = sendto(udpSocket,buffer,buflen, 0, 
      (struct sockaddr *)&clientAddr, 
      sizeof(clientAddr)); 
     if (bytesSent < 0) { 
      printf("Error sending/ communicating with client\n"); 
      exit(1); 
     } 
      printf("Done sending %s\n", buffer); 
       sleep(1); 
    } 
    .. 

, так и на на стороне клиента что-то вдоль этих линий

//.. 
    int clientSocket, portNum, nBytes, buflen; 
    char buffer[1024]; 
    struct sockaddr_in serverAddr; 
    struct sockaddr_in clientAddr; 
    socklen_t addr_size; 

    /*Create UDP socket*/ 
    clientSocket = socket(PF_INET, SOCK_DGRAM, 0); 
    portNum = atoi(argv[1]); 
    /*Configure settings in address struct*/ 
    memset(&clientAddr, 0, sizeof(clientAddr)); 
    clientAddr.sin_family = AF_INET; 
    clientAddr.sin_port = htons(portNum); 
    clientAddr.sin_addr.s_addr = htonl(INADDR_ANY); 

    memset(&serverAddr, 0, sizeof(serverAddr)); 


    /*Bind on client side as well because you are specifically sending something over 
    * to the client. Usually the server will know where to talk back to the client 
    * but in your example because of the reversed semantics this will be needed 
    */ 

    bind(clientSocket, (struct sockaddr *) &clientAddr, sizeof(clientAddr)); 

    /*Initialize size variable to be used later on*/ 
    addr_size = sizeof serverAddr; 

    while(1){ 
     memset(buffer, 0, 1024); 
     buflen=65536; 
     recvfrom(clientSocket,buffer,buflen,0,(struct sockaddr *)&serverAddr, &addr_size); 
     printf("Received from server: %s\n",buffer); 
     sleep(1); 
    } 
    return 0; 

код можно упростить, если поменять местами комлинк от клиента к серверу, таким образом, устраняя необходимость в фикс d номер порта на стороне клиента.

+0

Спасибо, @Aniruddh, за объяснение и за код. Основываясь на ваших рекомендациях, я изменил код и обновил его в разделе кода. Сбивающий с толку аспект заключается в том, что он все еще не сообщает. – 034568

+0

Обновлено немного больше, чтобы дать вам больше подсказок. Запустите программу с номером порта, отличным от 5000, который есть на стороне сервера для привязки. Но я предлагаю вам подумать об этом от клиента, взаимодействующего с сервером. Клиентов, как правило, будет много, и для сервера не имеет смысла знать номер порта априорного порта. По сути, я бы рекомендовал начать с отправки на сервер в хорошо известном порту, но на стороне клиента не привязан ни к чему. Затем сервер должен прочитать из recvfrom и связаться с тем же адресом. Удачи –