Проблемы с получением данных через TCP-клиентский сокет - PullRequest
3 голосов
/ 26 ноября 2008

Я пытаюсь сделать программу TCP Client на C, где клиент запустится, подключиться к серверу. Затем он отправит немного информации, а затем просто послушает, что он получает, и отреагирует соответствующим образом.

Часть, с которой у меня возникают проблемы, это постоянное прослушивание. Вот что у меня есть

...

while (1) {
   numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0);
   buf[numbytes] = '\0';
   printf("Received: %s\n", buf);
   // more code to react goes here
}

...

При подключении к серверу, после отправки двух строк данных, сервер должен получить хорошую информацию, но когда я запускаю это, он печатает:

Поступило:

А потом продолжает просто сидеть, пока я не заставлю его закрыться.

** РЕДАКТИРОВАТЬ **, когда я делаю то, что сказал мне Джонатан, я получаю следующее:

Количество: -1, ошибка: 111, получено:

Так что это означает, что он ошибается, но что мне с этим делать?

Ответы [ 4 ]

4 голосов
/ 26 ноября 2008

Распечатайте количество полученных байтов - скорее всего, оно будет равно нулю, но подтвердите это.

Стоит проверить, что вы не получаете сообщение об ошибке - и, следовательно, не исчерпываете свой буфер.

[ Примечание: здесь и далее работа Pax - спасибо , и я преобразовал ее в вики сообщества, поэтому я не получаю очки заслуженного ответа. ]

Следующий код сделает это. Попробуйте и сообщите о результатах, пожалуйста.

while (1) {
    numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0);
    buf[numbytes] = '\0';
    printf("Count: %d, Error: %d, Received: %s\n", numbytes, errno, buf);
    // more code to react goes here
}

После редактирования вопроса:

Ошибка 111 - ECONNREFUSED - это не обычный код ошибки для recv (), но больше подходит для вызова открытого типа (open (), connect () и т. Д.).

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

Чтобы проверить это, измените код так, чтобы он подключался к www.microsoft.com через порт 80, а затем отправьте пару строк любого старого мусора. Вы должны получить сообщение об ошибке от их веб-сервера, указывающее на неправильный HTTP-запрос. Это докажет, что на стороне клиента нет проблем.

Это то, что я получаю, когда набираю telnet www.microsoft.com 80 и набираю hello, а затем ENTER дважды:

HTTP/1.1 400 Bad Request
Content-Type: text/html; charset=us-ascii
Server: Microsoft-HTTPAPI/2.0
Date: Thu, 27 Nov 2008 01:45:09 GMT
Connection: close
Content-Length: 326

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Bad Request</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Bad Request - Invalid Verb</h2>
<hr><p>HTTP Error 400. The request verb is invalid.</p>
</BODY></HTML>

Вы должны увидеть нечто подобное.

2 голосов
/ 26 ноября 2008

Я настоятельно рекомендую Руководство Биджа по сетевому программированию .

В этом разделе , в частности, есть код для клиента, который делает именно то, что вы просите.

0 голосов
/ 27 ноября 2008

Что с бесконечным циклом? Почему бы не использовать select (), чтобы вызывать recv () только тогда, когда есть реальные данные для чтения?

В прошлой жизни я писал сетевой код для MUD, и я все еще могу написать цикл опроса в своей голове. Цикл в ПЗУ 2.3 прошел примерно так (из памяти, так что, прости меня, если параметры макросов находятся в неправильном порядке):

#define MAX_CONNECTIONS 256
int main(int argc, char *argv[])
{
  int i = 0;
  int running = 1;
  int connections[MAX_CONNECTIONS];
  while( running )
  {
    fd_set in_fd, out_fd, exc_fd;
    FD_ZERO(in_fd);
    FD_ZERO(out_fd);
    FD_ZERO(exc_fd);
    for( i = 0; i < MAX_CONNECTIONS; i++ )
    {
      if( connections[i] > 0 )
      {
        FD_SET(&in_fd, connections[i]);
        FD_SET(&out_fd, connections[i]);
        FD_SET(&exc_fd, connections[i]);
      }
    }
    select(&in_fd, &out_fd, &exc_fd, NULL); // this will block until there's an I/O to handle.
    for( i = 0; i < MAX_CONNECTIONS; i++ )
    {
      if( FD_ISSET(&exc_fd, connections[i]) )
      { /* error occurred on this connection; clean up and set connection[i] to 0 */ }
      else
      {
        if( FD_ISSET(&in_fd, connections[i]) )
        { /* handle input */ }
        if( FD_ISSET(&out_fd, connections[i]) )
        { /* handle output */ }
      }
    }
  }
}
0 голосов
/ 26 ноября 2008

РЕДАКТИРОВАТЬ: ответ ниже был основан на неправильном понимании вопроса - код OP на самом деле пытается recv () на сокете, который он открывает () для удаленного сервера. Вещи внизу слева для потомков.


Пожалуйста, покажите больше вашего кода.

Несколько замечаний:

  • это розетка listen()ing?
  • у вас accept()ed входящее соединение
  • немного необычно использовать recv() на сокете TCP. Вместо этого используйте read().
  • используйте strerror() для преобразования кода ошибки 111 в локальную строку ошибки - каждая операционная система UNIX может иметь собственное отображение из чисел в коды ошибок Exxx, поэтому мы не можем сказать, что это за ошибка в вашей системе.

Обычный цикл кода (для однопоточного не разветвленного приложения) выглядит следующим образом:

s = socket();
err = listen(s, n); // n = backlog number
while (1) {
    int fd = accept(s, &addr, sizeof(addr));
    while (1) {
        int numrecv = read(fd, ...);
        // break if eof
    }
    close(fd);
}
close(s);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...