2016-11-15 12 views
2

Я пишу простой иллюстративный клиент UDP-сервера. Сервер должен на основе ввода клиента рассчитать порядок байтов сетевого клиента и отправить его клиенту. Я пытался исправить эту ошибку целый день. Любая помощь будет применена. Вот начало сервера и выход: начатьUDP-сервер/клиент в C-sendto ошибке: семейство адресов не поддерживается протоколом

./udpserver.out 4545 
from.sin_family: 12079 
Little Endian 

ERROR UDP_SRV_004 - can not send message to client: Address family not supported by protocol 

Клиент:

./udpclient.out localhost 4545 

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

#include <stdio.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <stdlib.h> 
#include <strings.h> 
#include <string.h> 
#include <netinet/in.h> 
#define BUFFER_SIZE 80 

static void error(char *msg){ 
    perror(msg); 
    exit(1); 
} 


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

    int socketfd, portno, fromlen, n, length; 
    struct sockaddr_in server, from; 
    char buffer[BUFFER_SIZE]; 
    char response[BUFFER_SIZE]; 
    const char *le = "Little Endian\n"; 
    const char *be = "Big Endian\n"; 
    const char *unk = "Unknown \n"; 
    int cli_family; 

    if(argc!=2){ 
     fprintf(stderr,"Error starting the client, please start server as: %s port\n", argv[0]); 
     exit(0); 
    } 

    if((socketfd=socket(AF_INET,SOCK_DGRAM,0))<0) 
     error("ERROR UDP_SRV_001 - can not create socket"); 

    portno=atoi(argv[1]); 

    bzero(&server,sizeof(server)); 
    server.sin_family=AF_INET; 
    server.sin_addr.s_addr=INADDR_ANY; 
    server.sin_port=htons(portno); 

    if(bind(socketfd,(struct sockaddr *)&server,sizeof(server))<0) 
     error("ERROR UDP_SRV_002 - can not bind server address to a socket file descriptor"); 

    bzero(buffer, BUFFER_SIZE); 
    bzero(response,BUFFER_SIZE); 
    n=recvfrom(socketfd,buffer,BUFFER_SIZE-1,0,(struct sockaddr *)&from,&fromlen); 
    if (n<0) 
     error("ERROR UDP_SRV_003 - can not receive client's message"); 

    cli_family=from.sin_family; 
    printf("from.sin_family: %d\n", cli_family); 

    if (buffer[0] == 1 && buffer[1] == 2) 
     strcpy(response, be); 
    else if (buffer[0] == 2 && buffer[1] == 1) 
     strcpy(response, le); 
    else 
     strcpy(response, unk); 

    length=strlen(response); 
    printf("%s\n",response); 

    n=sendto(socketfd,response,length,0,(struct sockaddr *)&from,fromlen); 
    if(n<0) 
     error("ERROR UDP_SRV_004 - can not send message to client"); 


    return 0; 
} 

код клиента:

#include <stdio.h> 
#include <sys/types.h> 
#include <netdb.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <stdlib.h> 
#include <strings.h> 
#include <string.h> 
#include <unistd.h> 
#define BUFFER_SIZE 80 

static void error(char *msg){ 
    perror(msg); 
    exit(1); 
} 

typedef union UNIT{ 
     short s; 
     char c[sizeof(short)]; 
    }unit; 

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

    int socketfd, portno, n, length; 
    struct sockaddr_in server, from; 
    struct hostent *host; 
    char buffer[BUFFER_SIZE]; 
    unit un; 
    un.s=0x0102; 

    if(argc!=3){ 
     fprintf(stderr,"Error starting the client, please start client as: %s hostname port\n", argv[0]); 
     exit(0); 
    } 

    if((host=gethostbyname(argv[1]))==NULL) 
     error("ERROR UDP_CLI_001 - no such host defined, please check your /etc/hosts file"); 

    portno=atoi(argv[2]); 

    if((socketfd=socket(AF_INET,SOCK_DGRAM,0))<0) 
     error("ERROR UDP_CLI_002 - can not create socket"); 

    bzero((char *)&server,sizeof(server)); 

    server.sin_family=AF_INET; 
    server.sin_port=htons(portno); 
    bcopy((char *)host->h_addr,(char *)&server.sin_addr,host->h_length); 
    length=sizeof(server); 

    if(sizeof(short)!=2){ 
     exit(0); 
    } 

    n=sendto(socketfd,un.c,strlen(un.c),0,(struct sockaddr *)&server,length); 
    if(n<0) 
     error("ERROR UDP_CLI_003 - can not send to server"); 
    bzero(buffer,BUFFER_SIZE); 
    n=recvfrom(socketfd,buffer,BUFFER_SIZE,0,(struct sockaddr *)&from, &length); 
    if(n<0) 
     error("ERROR UDP_CLI_004 - can receive from server"); 
    printf("%s",buffer); 


return 0; 
} 
+0

Клиент sin_family, этот сервер получает, должен быть 2 для AF_INET. Но по какой-то причине это перепуталось, и я не могу это исправить, потому что если я попытаюсь переопределить его с помощью AF_INET, это даст мне ошибку sendto invalid аргумент. –

ответ

3

В сервере, не удалось инициализировать fromlen до звонка до sendto. В результате from не был заселен.

От man page:

If src_addr is not NULL, and the underlying protocol provides the source address, this source address is filled in. When src_addr is NULL, nothing is filled in; in this case, addrlen is not used, and should also be NULL. The argument addrlen is a value-result argument, which the caller should initialize before the call to the size of the buffer associated with src_addr, and modified on return to indicate the actual size of the source address. The returned address is truncated if the buffer provided is too small; in this case, addrlen will return a value greater than was supplied to the call.

recvfrom функция пытается прочитать значение fromlen, а потому, что он не инициализируется вызове undefined behavior.

Инициализировать fromlen, и этот вопрос будет рассмотрен.

fromlen = sizeof from; 
n=recvfrom(socketfd,buffer,BUFFER_SIZE-1,0,(struct sockaddr *)&from,&fromlen); 
+0

Nice поймать dbush. @Milos - Вы должны были увидеть предупреждение компилятора для этого. Не игнорируйте их. –

+0

Спасибо! Это решило. –

+0

@BrianMcFarland Да, забыл поставить -Wall в Makefile, поэтому я не увидел предупреждения. –