2016-02-23 3 views
6

Я пытаюсь написать клиентскую серверную программу с использованием UDP и ждать и останавливаться, но у меня нет этой части, я все еще пытаюсь ее понять как взаимодействуют два процесса (сервер и клиент), потому что в моей клиентской программе пользователю необходимо ввести имя сервера или IP-адрес и имя порта, а затем отправить выражение, которое сервер должен вычислить. Тем не менее, я выкопал некоторые учебные пособия в Интернете и после кодирования соответственно (или, я думал, так), я не могу заставить клиента общаться с сервером. Ниже мой код, пожалуйста, просветите меня, что я делаю неправильно, если это bind(), sendto(), recvfrom() или socket(), или все из них. Я не понимаю, что именно не так. Я знаю, что клиентская сторона не должна работать в бесконечном цикле, но до сих пор я хочу, чтобы программы обменивались данными друг с другом, после чего я буду полировать свой код. Благодаря!Программирование сокетов: UDP Client-Server в C

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

#include <stdio.h>  // Default System Calls 
#include <stdlib.h>  // Needed for OS X 
#include <string.h>  // Needed for Strlen 
#include <sys/socket.h> // Needed for socket creating and binding 
#include <netinet/in.h> // Needed to use struct sockaddr_in 
#include <time.h>  // To control the timeout mechanism 

#define EXPR_SIZE 1024 
#define BUFLEN  512 
#define TRUE  1 
#define FALSE  0 
#define SERVERLEN 1024 

int main(int argc, char **argv){ 

    long portNum;   // Since it's possible to input a value bigger 
          // than 65535 we'll be using long to 
          // avoid overflows 
    char expr[EXPR_SIZE]; 
    char server[SERVERLEN]; 
    int fd;     // file descriptor for the connected socket 
    int buf[512]; 
    struct hostent *h;   // information of the host 
    unsigned int addrLen;  // address length after getting the port number 
    struct sockaddr_in myaddr; // address of the client 
    struct sockaddr_in servaddr; // server's address 
    unsigned int exprLen; 
    socklen_t slen = sizeof(servaddr); 

    printf("Enter server name or IP address:"); 
    scanf("%s",server); 
    printf("Enter port:"); 
    scanf("%ld",&portNum); 
    if ((portNum < 0) || (portNum > 65535)) { 
     printf("Invalid port number. Terminating."); 
     return 0; 
    } 
    printf("Enter expression:"); 
    scanf("%s",expr); 

    if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){ 
     perror("cannot create socket"); 
     return 0; 
    } 

    memset((char *)&myaddr, 0, sizeof(myaddr)); 
    myaddr.sin_family = AF_INET; 
    myaddr.sin_addr.s_addr = htonl(INADDR_ANY); 
    myaddr.sin_port = htons(0); 

    if(bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0){ 
     perror("cannot bind"); 
     return 0; 
    } 

    /* 
    // Discovering the port number the OS allocated 
    addrLen = sizeof(myaddr); 
    if(getsockname(fd, (struct sockaddr *)&myaddr, &addrLen) < 0){ 
    perror("cannot getsockname"); 
    return 0; 
    } 
    printf("local port number = %d\n", ntohs(myaddr.sin_port)); 
    */ 

    memset((char*)&servaddr, 0, sizeof(servaddr)); 
    servaddr.sin_family = AF_INET; 
    servaddr.sin_port = htonl(portNum); 

    exprLen = sizeof(expr); 


    while(TRUE){ 
     printf("Sending message to %s port %ld\n",server, portNum); 
     if (sendto(fd, expr, strlen(expr), 0, (struct sockaddr *)&servaddr, slen) < 0) { 
      perror("cannot sendto()"); 
     } 
     printf("Success\n"); 

    } 


    return 0; 
} 

Серверный код:

#include <stdio.h>  // Default System Calls 
#include <stdlib.h>  // Needed for OS X 
#include <string.h>  // Needed for Strlen 
#include <sys/socket.h> // Needed for socket creating and binding 
#include <netinet/in.h> // Needed to use struct sockaddr_in 
#include <time.h>  // To control the timeout mechanism 

#define EXPR_SIZE 1024 
#define BUFLEN  512 
#define TRUE  1 
#define SERVERLEN 1024 

int main(int argc, char **argv){ 

    struct sockaddr_in myaddr; // address of the server 
    struct sockaddr_in claddr; // address of the client 
    char buf[BUFLEN]; 
    int fd; 
    long recvlen; 
    socklen_t clientlen; 



    if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){ 
     perror("cannot create socket"); 
     return 0; 
    } 

    memset((char *)&myaddr, 0, sizeof(myaddr)); 
    myaddr.sin_family = AF_INET; 
    myaddr.sin_addr.s_addr = htonl(INADDR_ANY); 
    myaddr.sin_port = htons(0); 

    if(bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0){ 
     perror("cannot bind"); 
     return 0; 
    } 
    clientlen = sizeof(claddr); 

    while (TRUE) { 
     recvlen = recvfrom(fd, buf, BUFLEN, 0, (struct sockaddr *)&claddr, &clientlen); 
     if (recvlen < 0) { 
      perror("cannot recvfrom()"); 
      return 0; 
     } 
     printf("Received %ld bytes\n",recvlen); 
     buf[recvlen] = 0; 
     printf("Received message: \"%s\"\n",buf); 

    } 

    return 0; 
} 

Программа сервер не выводить ничего, в то время как клиентские выходы, пока процесс прерывается:

Enter server name or IP address:127.0.0.1 
Enter port:30 
Enter expression:2+2 
Sending message to 127.0.0.1 port 30 
cannot sendto(): Can't assign requested address 

Я попытался изменить имя сервера на localhost и другие порты, но безрезультатно.

+2

«Я не могу сделать клиент общаться с сервером.». Не могли бы вы быть немного конкретными? Оказывает ли программа сбой, не производит ли выход, производит ли он неправильный вывод? и т. д. Также включайте любые отладочные данные, которые вы уже собрали. – kaylum

+0

Переход к редактированию вывода в вопрос –

+1

Ваш клиент должен отправить на тот же порт, к которому привязан сервер. – kaylum

ответ

12

При разработке сетевого программного обеспечения (особенно при использовании интерфейса сокетов BSD) важно максимально упростить процесс, пока вы не установили базовую связь. Затем вы можете постепенно добавлять функциональность, при этом убедитесь, что вы ничего не сломаете на этом пути.

На стороне клиента, сохраняя вещи простых средств

  • Не называйте bind в клиенте. ОС выберет соответствующий интерфейс и назначит случайный номер порта, поэтому нет необходимости в bind сокете.

  • Используйте адрес жесткого кодирования (например, 127.0.0.1). Адрес 127.0.0.1 (0x7f000001) - это адрес локального хоста, подходящий для отправки пакетов на сервер на том же компьютере.

  • Используйте номер жесткого кода (например, 50037). Ephemeral port numbers должно быть больше, чем 0xC000 hex (49152 десятичное).

  • Используйте жестко закодированное сообщение, например. "Здравствуйте".

Имея это в виду, вот что клиентское программное обеспечение выглядит

int main(void) 
{ 
    int fd; 
    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 
     perror("socket failed"); 
     return 1; 
    } 

    struct sockaddr_in serveraddr; 
    memset(&serveraddr, 0, sizeof(serveraddr)); 
    serveraddr.sin_family = AF_INET; 
    serveraddr.sin_port = htons(50037);    
    serveraddr.sin_addr.s_addr = htonl(0x7f000001); 

    for (int i = 0; i < 4; i++) { 
     if (sendto(fd, "hello", 5, 0, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) { 
      perror("sendto failed"); 
      break; 
     } 
     printf("message sent\n"); 
    } 

    close(fd); 
} 

На стороне сервера, сохраняя вещи простыми средствами

  • Привязать к INADDR_ANY, т.е. позволяют медиатор OS соответствующий интерфейс.
  • Привязывается к жестко закодированному порту, например. 50037 (должен быть тот же порт, который использует клиент).
  • Не запрашивайте адресную информацию от recvfrom, то есть передайте NULL, 0 в качестве последних двух параметров.

Имея это в виду, вот что программное обеспечение сервера выглядит

int main(void) 
{ 
    int fd; 
    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 
     perror("socket failed"); 
     return 1; 
    } 

    struct sockaddr_in serveraddr; 
    memset(&serveraddr, 0, sizeof(serveraddr)); 
    serveraddr.sin_family = AF_INET; 
    serveraddr.sin_port = htons(50037); 
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); 

    if (bind(fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) { 
     perror("bind failed"); 
     return 1; 
    } 

    char buffer[200]; 
    for (int i = 0; i < 4; i++) { 
     int length = recvfrom(fd, buffer, sizeof(buffer) - 1, 0, NULL, 0); 
     if (length < 0) { 
      perror("recvfrom failed"); 
      break; 
     } 
     buffer[length] = '\0'; 
     printf("%d bytes: '%s'\n", length, buffer); 
    } 

    close(fd); 
} 
+0

В «игрушечных» приложениях я сомневаюсь, что кто-то будет бить ресницы, но в целом: не используйте эфемерные порты. Если вы указали в этой теме, вы найдете случаи, когда люди это делали и имели проблемы, или вы можете просто взять их совет: http://books.google.si/books?id=Pm4RgYV2w4YC&pg=PA705&lpg=PA705&dq=use%20Ephemeral % 20port% 20for% 20server & источник = бл & отс = qwnYpJGseD & сиг = 3EihPoqMeNH06ge5lChaRmi9hFg & гл = еп & са = Х & е = JoZsU4GBJ4iL7Ab-yICYCA & redir_esc = у # v = OnePage & д = использовать% 20Ephemeral% 20port% 20for% 20server & F = ложь –