2014-01-22 3 views
0

Итак, вот код для TCP-эхо-клиента. Когда у меня есть эхо-сервер, прослушивающий порт 5000, клиент подключается, но после того, как я набираю сообщение и нажимаю enter, он автоматически отключается. В чем проблема?(TCP) Echo client: Автоматическое отключение после отправленного сообщения

исходный код (tcp_ec.c):

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



#define MAX_BUFFER 1024 

void die(char *s) 
{ 
     perror(s); 
     exit(1); 
} 


int main() 

{ 

    int connector,flags,r; 
    int port; 
    struct hostent*  host; 
    struct in_addr   in; 
    struct sockaddr_in  rmaddr; 
    bool connected = false; 
    char sndbuffer[MAX_BUFFER]; 
    char rcvbuffer[MAX_BUFFER]; 
    char hostname[INET_ADDRSTRLEN]; 
    char* exit = "quit"; 



    if((connector = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))<0){ 
     perror("socket"); 
     return -1; 
    } 


    printf("\n"); 
    printf("Enter the remote hostname(URL/IP4 address): "); 
    scanf("%s", hostname); 
    printf("\n"); 



    printf("Enter the port number you wish to connect(on): "); 
    scanf("%u", &port); 
    printf("\n"); 

    if(port==0){ 
       printf("ERR0R: Port number must be between 1 & 65,535\n"); 
       printf("\n"); 
       printf("Enter the port number you wish to connect(on): "); 
       scanf("%u", &port); 
       printf("\n");   
    } 

    host = gethostbyname(hostname); 

    if(host==NULL){ 
     perror("hostname"); 
     return -1; 
    } 


    bzero(&rmaddr,sizeof(rmaddr)); 
    rmaddr.sin_family = AF_INET; 
    rmaddr.sin_port = htons(port); 
    bcopy((char*)host->h_addr, (char*)&rmaddr.sin_addr.s_addr, host->h_length); 


    if(connect(connector,(struct sockaddr*)&rmaddr,sizeof(rmaddr))<0){ 
     perror("connect"); 
     return -1; 
    }else{ 
     connected=true; 
     printf("\n"); 
     printf("Connected to host: %s",hostname,"on port %u",port); 
     printf("  type 'quit' to disconnect\n"); 
     printf("\n"); 
    } 

    while(connected==true){ 

     printf(">"); 
     scanf("%s",sndbuffer); 
     printf("\n"); 

     if(sndbuffer==exit){ 
      close(connector); 
      connected = false; 
      return 0; 
     } 

     if(send(connector,(void*)sndbuffer,sizeof(sndbuffer),MSG_EOR||MSG_NOSIGNAL)<0){ 
      perror("send"); 
      close(connector); 
      return -1; 
     } 

     if(recv(connector,(void*)rcvbuffer,sizeof(rcvbuffer),MSG_EOR||MSG_NOSIGNAL)<0){ 
      perror("recv"); 
      close(connector); 
      return -1; 
     }else{ 
     printf(">>"); 
      printf("%s\n",rcvbuffer); 
      printf("\n"); 
     } 




    } 




} 

Выход консоли (выход программы файл "дц"):

[email protected] /usr/lib/gcc/x86_64-linux-gnu/4.7.3/include $ ./tec 

Enter the remote hostname(URL/IP4 address): 127.0.0.1 

Enter the port number you wish to connect(on): 5000 


Connected to host: 127.0.0.1  type 'quit' to disconnect 

>asssr 

sendmsg: Broken pipe 
[email protected] /usr/lib/gcc/x86_64-linux-gnu/4.7.3/include $ 

Это делается, когда echo_server работает на порту 5000 .

+0

1) 'if (sndbuffer == exit) {}' Здесь вы сравниваете два строковых указателя. Используйте strncmp() или memcmp() здесь 2) 'printf ("% s \ n ", rcvbuffer);' recvbuffer не будет завершен с помощью recv(). – wildplasser

+0

wildplasser: я изменил код на спецификации, которые вы указали, но я STILL получаю сообщение об ошибке «sendmsg: Broken pipe», когда я ввожу сообщение для передачи. –

+0

'echoclient.c: 31: 3: error: имя неизвестного типа 'bool'' Вы используете компилятор C++? – wildplasser

ответ

0

Заменить:

if(send(connector,(void*)sndbuffer,sizeof(sndbuffer),MSG_EOR||MSG_NOSIGNAL)<0){ 
... and 
if(recv(connector,(void*)rcvbuffer,sizeof(rcvbuffer),MSG_EOR||MSG_NOSIGNAL)<0){ 

По вопросу:

if(send(connector,(void*)sndbuffer,sizeof(sndbuffer),MSG_EOR|MSG_NOSIGNAL)<0){ 
... and 
if(recv(connector,(void*)rcvbuffer,sizeof(rcvbuffer),MSG_EOR|MSG_NOSIGNAL)<0){ 

... плюс некоторые незначительные ошибки.

EDIT: полный исправлен источник

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

#define MAX_BUFFER 1024 

void die(char *s) 
{ 
     perror(s); 
     exit(1); 
} 

int main() { 
    int connector,flags,r; 
    int port; 
    struct hostent*  host; 
    struct in_addr   in; 
    struct sockaddr_in  rmaddr; 
    bool connected = false; 
    char sndbuffer[MAX_BUFFER]; 
    char rcvbuffer[MAX_BUFFER]; 
    char hostname[INET_ADDRSTRLEN]; 
    char* exit = "quit"; 


    if((connector = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))<0){ 
     perror("socket"); 
     return -1; 
    } 

    printf("\n"); 
    printf("Enter the remote hostname(URL/IP4 address): "); 
    scanf("%s", hostname); 
    printf("\n"); 

    printf("Enter the port number you wish to connect(on): "); 
    scanf("%u", &port); 
    printf("\n"); 

    if(port==0){ 
       printf("ERR0R: Port number must be between 1 & 65,535\n"); 
       printf("\n"); 
       printf("Enter the port number you wish to connect(on): "); 
       scanf("%u", &port); 
       printf("\n"); 
    } 
    host = gethostbyname(hostname); 

    if(host==NULL){ 
     perror("hostname"); 
     return -1; 
    } 


    bzero(&rmaddr,sizeof(rmaddr)); 
    rmaddr.sin_family = AF_INET; 
    rmaddr.sin_port = htons(port); 
    bcopy((char*)host->h_addr, (char*)&rmaddr.sin_addr.s_addr, host->h_length); 


    if(connect(connector,(struct sockaddr*)&rmaddr,sizeof(rmaddr))<0){ 
     perror("connect"); 
     return -1; 
    }else{ 
     // connected=true; 
     printf("\n"); 
     printf("Connected to host: %son port %u", hostname, port); 
     printf("  type 'quit' to disconnect\n"); 
     printf("\n"); 
    } 

    // while(connected==true){ 
    while(1){ 

     printf(">"); 
     scanf("%s",sndbuffer); 
     printf("\n"); 

     if(sndbuffer==exit){ 
      close(connector); 
      // connected = false; 
      return 0; 
     } 

     if(send(connector,(void*)sndbuffer,sizeof(sndbuffer),MSG_EOR|MSG_NOSIGNAL)<0){ 
      perror("send"); 
      close(connector); 
      return -1; 
     } 

     if(recv(connector,(void*)rcvbuffer,sizeof(rcvbuffer),MSG_EOR|MSG_NOSIGNAL)<0){ 
      perror("recv"); 
      close(connector); 
      return -1; 
     }else{ 
     printf(">>"); 
      printf("%s\n",rcvbuffer); 
      printf("\n"); 
     } 
    } 

return 0; 
} 

ВЫВОД:

~/src/usenet$ ./a.out 

Enter the remote hostname(URL/IP4 address): 127.0.0.1 

Enter the port number you wish to connect(on): 7 


Connected to host: 127.0.0.1on port 7  type 'quit' to disconnect 

>aap 

>>aap 

>noot 

>>noot 

>mies 

>>mies 

>quit 

>>quit 

>^C 

[не реагирует на "бросить курить" вызвано отсутствием strncmp() // memcmp(), плюс " quit на самом деле «quit \ n» (и не nul-terminated)]

+0

Почему? Какая разница? Какое влияние имеет изменение? Я не вижу ни одной разницы, но даже если она есть, вы должны объяснить. Nb void * casts избыточны. – EJP

+0

Дополнительный '|' (который я отредактировал, добавляя две другие строки ...) И: да (void *) отливки излишни. – wildplasser

+0

wildplaserer, к сожалению EJP верен: в ответе на выход программы нет CHANGE. * вздох * Что-то кажется, что это не так. –

0

Я думал, что проблема связана с функциями байтового заказа, потому что я заметил, что добавление заголовка приводит к предупреждениям компилятора. что то, что вызывает проблему в первую очередь, а также тот факт, что вызов функции bind() в приложении echo server дает ошибку EONOTSUPP, заключается в том, что сокет не привязан к определенному адресу! Он является обязательным для всех адресов, и эта ошибка GCC была зарегистрирована Here. Итак, теперь задача заключается в том, чтобы загрузить и установить патч, и я увижу, как это работает.

+0

Нет, я протестировал его на localhost с эхо-портом (= 8), и он просто сработал после некоторых изменений (например, проблема «||»). Я думаю, что OP просто разместил неправильный код или имеет другой испытательный стенд. – wildplasser

+0

Я использую Linux Mint 15 с версией ядра 3.8.0-19 (вместе с заголовками Linux). Так что да, у меня есть другой тестовый стенд и некоторые заголовки, которые мне пришлось широко отлаживать (например, ). Новые версии ядра имеют некоторые БОЛЬШИЕ проблемы, но я думаю, что это могут быть заголовки с некоторыми функциями упорядочения байтов. –

+0

Не обвиняйте ядро ​​или заголовки (другие заметили бы) Я думаю, что я добавлю исправленный источник ответа. – wildplasser

0

Я уже видел, что connect() к несуществующему порту на 127.0.0.1 может успешно вернуться, но это несколько десятилетий назад, а не Linux. Техника, которую я использовал тогда, заключалась в том, чтобы написать запись нулевой длины, которая не сработает, если соединение действительно не работает. Я так и не дошел до конца, и я не видел эту проблему уже более 20 лет.

Но у вас есть другие проблемы.

Вы игнорируете счет, возвращаемый 'recv()', если он не является отрицательным. Это имеет два последствия:

  1. Возможно, после этого у вас может быть нежелательная печать.
  2. Вы не обнаруживаете конец потока из recv(), поэтому вы не знаете, когда партнер отключился, поэтому цикл продолжается и вы отправляете соединение, которое уже было закрыто одноранговым узлом, проблема с «сломанной трубой». Неправильно вызывать recv(), не сохраняя результат в переменной.

Вы также Отправка утиль. Вместо «sizeof sndbuffer» счетчик, который вы отправляете send(), должен быть «strlen (sndbuffer)» в этом случае, поскольку вы только что прочитали строку с нулевым завершением с помощью «fgets()».

+0

Хорошо, EJP, я попытался внести изменения, которые вы предложили, но все это безрезультатно. Это действительно заставляет меня думать, что что-то не так с API сокетов, потому что эта проблема с функцией connect() также делает то же самое с удаленными адресами. Я использовал программу Netcat для тестирования сетевых интерфейсов loopback и wifi, и они оба работают нормально. Предполагается, что функция connect() вернется успешно IF И ТОЛЬКО ЕСЛИ ответ ACK с сервера! Поэтому ожидается тот факт, что send() не удается из-за неисправного канала, потому что сокет не подключен. Но если вы знаете, что может вызвать эту ошибку, скажите мне. –

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