2016-02-10 1 views
0

Я работаю над этим некоторое время, пытаясь изучить программирование сокетов, но я сталкиваюсь с некоторыми проблемами с костяными проблемами.C сокет программирование отправка нескольких отправлений и получение по одному и тому же соединению

Проблема, которую я пытаюсь решить, отправляет 3 идентичных отправления от клиента на сервер с целью регистрации клиента. На данный момент у меня есть один из отправлений и получает работу, но я не могу получить вторую или третью работу. Для целей отладки я печатаю поле данных моей структуры пакета, и, пока он печатает для первого приема, второй прием пуст, а третий прием - нечетное squiggly box, за которым следует знак равенства. Я думаю, что я застрял в первом получении, может быть, но я действительно не уверен, в чем проблема.

В следующем коде я попытался отправить один и тот же пакет более 3 раз, а также попробовал то, что у меня есть внизу, отправив 3 разных пакета, которые должны содержать одну и ту же информацию, результат всегда один и тот же.

Вот код клиента:

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

#define SERVER_PORT 5654 
#define MAX_LINE 256 

/*structure of the packet*/ 
struct packet{ 
    short type; 
    char data[MAX_LINE]; 
}; 

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

    struct packet packet_reg; 
    struct packet packet_reg2; 
    struct packet packet_reg3; 
    struct hostent *hp; 
    struct sockaddr_in sin; 
    char *host; 
    char buf[MAX_LINE]; 
    int s; 
    int len; 
    char hostname[1024]; 
    hostname[1023] = '\0'; 

    if(argc == 2){ 
     host = argv[1]; 
    } 
    else{ 
     fprintf(stderr, "usage:newclient server\n"); 
     exit(1); 
    } 

    /* translate host name into peer's IP address */ 
    hp = gethostbyname(host); 
    if(!hp){ 
     fprintf(stderr, "unkown host: %s\n", host); 
     exit(1); 
    } 

    /* active open */ 
    if((s = socket(PF_INET, SOCK_STREAM, 0)) < 0){ 
     perror("tcpclient: socket"); 
     exit(1); 
    } 

    /* build address data structure */ 
    bzero((char*)&sin, sizeof(sin)); 
    sin.sin_family = AF_INET; 
    bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length); 
    sin.sin_port = htons(SERVER_PORT); 


    if(connect(s,(struct sockaddr *)&sin, sizeof(sin)) < 0){ 
     perror("tcpclient: connect"); 
     close(s); 
     exit(1); 
    } 
    /* main loop: get and send lines of text */ 
    while(fgets(buf, sizeof(buf), stdin)){ 

     gethostname(hostname, 1023); 
     printf("Hostname: %s\n", hostname); 

     packet_reg.type = htons(121); 
     strcpy(packet_reg.data,hostname); 

     /*send the registration packet to the server*/ 
     if(send(s,&packet_reg,sizeof(packet_reg),0)<0){ 
      printf("\nsend failed\n"); 
      exit(1); 
     } 

     packet_reg2.type = htons(121); 
     strcpy(packet_reg2.data,hostname); 

     printf("%s\n",packet_reg2.data); 

     /*send the registration packet to the server*/ 
     if(send(s,&packet_reg2,sizeof(packet_reg2),0)<0){ 
      printf("\nsend failed\n"); 
      exit(1); 
     } 

     packet_reg3.type = htons(121); 
     strcpy(packet_reg3.data,hostname); 

     /*send the registration packet to the server*/ 
     if(send(s,&packet_reg3,sizeof(packet_reg3),0)<0){ 
      printf("\nsend failed\n"); 
      exit(1); 
     } 

    } 
} 

Вот код для сервера, я сделал то же самое с попытками напечатать тот же пакет и заменить информацию в нем, а также использование 3 разных пакета.

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

#define SERVER_PORT 5654 
#define MAX_LINE 256 
#define MAX_PENDING 5 

/*structure of the packet*/ 
struct packet{ 
    short type; 
    char data[50]; 
}; 

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

    struct packet packet_reg; 
    struct packet packet_reg2; 
    struct packet packet_reg3; 
    struct sockaddr_in sin; 
    struct sockaddr_in clientAddr; 
    char buf[MAX_LINE]; 
    int s, new_s; 
    int len; 




    /* setup passive open */ 
    if((s = socket(PF_INET, SOCK_STREAM, 0)) < 0){ 
     perror("tcpserver: socket"); 
     exit(1); 
    } 


    /* build address data structure */ 
    bzero((char*)&sin, sizeof(sin)); 
    sin.sin_family = AF_INET; 
    sin.sin_addr.s_addr = INADDR_ANY; 
    sin.sin_port = htons(SERVER_PORT); 


    if(bind(s,(struct sockaddr *)&sin, sizeof(sin)) < 0){ 
     perror("tcpclient: bind"); 
     exit(1); 
    } 
    listen(s, MAX_PENDING); 

    /* wait for connection, then receive and print text */ 
    while(1){ 
     if((new_s = accept(s, (struct sockaddr *)&clientAddr, &len)) < 0){ 
      perror("tcpserver: accept"); 
      exit(1); 
     } 

     printf("\n Client's port is %d \n", ntohs(clientAddr.sin_port)); 


     if(recv(new_s,&packet_reg,sizeof(packet_reg),0)<0){ 
      printf("\ncouldnt receive first reg packet\n"); 
      exit(1); 
     } 
     printf("%s\n",packet_reg.data); 


     if(recv(new_s,&packet_reg2,sizeof(packet_reg2),0)<0){ 
      printf("\not recieved second reg packet\n"); 

      exit(1); 
     } 
     printf("%s\n",packet_reg2.data); 


     if(recv(new_s,&packet_reg3,sizeof(packet_reg3),0)<0){ 
      printf("\ncouldnt receive first reg packet\n"); 
      exit(1); 
     } 
     printf("%s\n",packet_reg3.data); 



    } 
} 

Любая помощь на этом была бы принята с благодарностью. Я уверен, что это глупая ошибка, и я просто не понимаю, как это работает. Первый раз с использованием c.

+0

Вы предполагаете, что каждый 'recv()' заполняет буфер. Он не обязан это делать. Вы должны зациклиться. Вы также не проверяете конец потока, и вы не закрываете какие-либо сокеты. – EJP

ответ

3

Так одна путаница у вас есть то, что вы не имеете сокет пакета - вы используете SOCK_STREAM поэтому у вас есть гнездо потока, который передает поток байтов не пакеты. Каждый вызов и recv может отправлять или получать любое количество байтов, и между размерами нет необходимости в соединении - байты, отправленные в нескольких отправлениях, могут быть получены вместе в одном recv или байты в одной передаче могут быть разделены в mulitple получает.

Это приводит сразу к вашей основной проблеме - ваш клиент отправляет 258 байт «пакеты», а ваш сервер читает 52 байта «пакеты». Итак, ваш первый recv получает не более 52 байт первого send, а второй recv получает следующие байты с середины первого send (вероятный случайный неинициализированный мусор). Вероятно, что вызовы recv возвращают все 52 байта, но не гарантируются.

+0

Спасибо, я изменил размер получающего пакета на тот же размер размера отправляющего, и это исправило проблему. Я знал, что это была глупая ошибка. Спасибо, что помогли мне учиться. –

+0

Обратите внимание, что вы по-прежнему не имеете никакой гарантии, что вызовы 'send' или' recv' не будут возвращать меньше количества запрошенных байтов - буфер сокета может заполнить (что приведет к короткой 'send') или сети слой может вставлять границы пакетов в разных точках, что приводит к короткому «recv». Вам нужно проверить возвращаемые значения и действовать соответствующим образом. –

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