2015-07-16 2 views
-1

Я пытаюсь передать эту простую программу эхо-трафика TCP (https://github.com/mafintosh/echo-servers.c/blob/master/tcp-echo-server.c) под Windows для учебных целей. Моя адаптация компилируется и запускается, но она не работает:Порт сервера эхо-сигналов Winsock

**** EDIT: прослушивание было как-то вырезано. Спасибо Remy ****

Клиент подключается, но не получает никакого эха.

адаптированного код выглядит следующим образом (сообщения об ошибках на итальянском языке, но они должны быть ясно, тем не менее):

#include <stdio.h> 
#include <stdlib.h> 
#include <winsock.h> 

#define BUFFER_SIZE 1024 
void on_error(char *s) { fprintf(stderr,"%s\n",s); fflush(stderr); exit(1); } 

int main(int argc, char *argv[]) { 
    WSADATA wsadata; 
    int server_fd, client_fd, err; 
    struct sockaddr_in server, client; 
    char buf[BUFFER_SIZE]; 

    int port = 6666; 
    int risultato = WSAStartup(MAKEWORD(2,2),&wsadata); 
    if (risultato != NO_ERROR) 
     {fprintf(stderr,"Errore in WSAStartup");fflush(stderr); exit(1);} 

    server_fd = socket(AF_INET, SOCK_STREAM, 0); 
    if (server_fd < 0) on_error("Non ho potuto creare il socket\n");  
    server.sin_family = AF_INET; 
    server.sin_port = htons(port); 
    server.sin_addr.s_addr = htonl(INADDR_ANY); 

    const char opt_val = 1; 
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt_val, sizeof opt_val); 
    /** bind & listen **/ 
    err = bind(server_fd, (struct sockaddr *) &server, sizeof(server)); 
    if (err < 0) on_error("Non ho potuto fare il bind del socket\n"); 
    err = listen(server_fd, 128); 
    if (err < 0) on_error("Non ho potuto mettermi in ascolto sul socket\n"); 
    printf("SERVER LISTENING ON PORT %d\n", port); 

    while (1) { 
     int client_len = sizeof(client); 
     do { 
     client_fd = accept(server_fd, (struct sockaddr *) &client, &client_len); 
     } while (client_fd = SOCKET_ERROR); 

     if (client_fd < 0) on_error("Non riesco a stabilire una nuova connessione\n"); 

     while (1) { 
     int read = recv(client_fd, buf, BUFFER_SIZE, 0); 

     if (!read) break; 
     if (read < 0) on_error("Errore nella lettura dal client\n"); 

     err = send(client_fd, buf, read, 0); 
     if (err < 0) on_error("Errore nella scrittura verso il client\n"); 
    } 
    } 

    WSACleanup(); 
    return 0; 
} 
+0

Запустить Wireshark, чтобы узнать, в чем проблема. Или попробуйте запустить другой сервер (например, netcat -L') на том же порту. –

+0

Ну, какие сообщения выводятся? Когда вы останавливаетесь с вашим отладчиком, достигает ли он вызова accept()? Есть ли блок accept(), как и ожидалось? –

+0

Прошу прощения, но «но это не работает: netcat/telnet просто не подключается» просто недостаточно. Сделайте некоторые отладки и сообщите нам, что происходит. Вы даже не сказали нам, какие сообщения выводились на stdout и 'on_error' (что бы это ни было). –

ответ

1

Вы вызываете bind() настроить порт прослушивания, но не вызывая listen() на самом деле начните прослушивать порт перед входом в цикл accept().

После того, как вы исправить эту ошибку, ваш цикл accept() нарушается в любом случае, потому что это заставляет client_fd к SOCKET_ERROR даже если accept() успешно. Условие while() использует оператор присваивания =, если вместо этого необходимо использовать оператор сравнения ==. И вы должны проверить на INVALID_SOCKET вместо SOCKET_ERROR.

Теперь с этим сказал, есть некоторые другие вещи, чтобы рассмотреть следующие вопросы:

  • WinSock не использует int для представления сокетов, он использует SOCKET вместо этого, который является UINT_PTR. При проверке недействительного дескриптора сокета не используйте < 0, вместо этого используйте == INVALID_SOCKET.

  • Большинство функций сокетов возвращают коды ошибок через WSAGetLastError() (WSAStartup()). Получите привычку использовать его и сообщайте коды ошибок в своих выходных сообщениях, чтобы вы знали, почему что-то не удается.

  • SO_REUSEADDR ожидает значение BOOL, а не значение char. A BOOL - это typedef для int и, следовательно, 4 байта.

  • Не все ошибки сокета являются фатальными, поэтому вы не должны убивать весь ваш сервер, если операция 10/send() завершилась с ошибкой при нефатальной ошибке.

  • send() не гарантирует, что вы отправите все, о чем вы просите его отправить, так что вы должны учитывать это.

  • не забудьте закрыть принятый клиентский сокет, когда вы закончите его использование.

Попробуйте это:

#include <stdio.h> 
#include <stdlib.h> 
#include <winsock.h> 

#define BUFFER_SIZE 1024 

void on_error(char *s, int *errCode = NULL) 
{ 
    int err = (errCode) ? *errCode : WSAGetLastError(); 
    fprintf(stderr, "%s: %d\n", s, err); 
    fflush(stderr); 
    exit(1); 
} 

int main(int argc, char *argv[]) 
{ 
    WSADATA wsadata; 
    SOCKET server_fd, client_fd; 
    struct sockaddr_in server, client; 
    int port = 6666, err; 
    char buf[BUFFER_SIZE]; 

    err = WSAStartup(MAKEWORD(2,2), &wsadata); 
    if (err != 0) 
     on_error("Errore in WSAStartup", &err); 

    server_fd = socket(AF_INET, SOCK_STREAM, 0); 
    if (server_fd == INVALID_SOCKET) 
     on_error("Non ho potuto creare il socket"); 

    memset(&server, 0, sizeof(server)); 
    server.sin_family = AF_INET; 
    server.sin_port = htons(port); 
    server.sin_addr.s_addr = INADDR_ANY; 

    /** bind & listen **/ 
    const BOOL opt_val = TRUE; 
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&opt_val, sizeof(opt_val)); 
    err = bind(server_fd, (struct sockaddr *) &server, sizeof(server)); 
    if (err == SOCKET_ERROR) 
     on_error("Non ho potuto fare il bind del socket"); 
    err = listen(server_fd, 1); 
    if (err == SOCKET_ERROR) 
     on_error("Non ho potuto mettermi in ascolto sul socket"); 

    printf("SERVER LISTENING ON PORT %d\n", port); 

    while (1) 
    { 
     int client_len = sizeof(client); 
     client_fd = accept(server_fd, (struct sockaddr *) &client, &client_len); 

     if (client_fd == INVALID_SOCKET) 
      on_error("Non riesco a stabilire una nuova connessione"); 

     bool keepLooping = true; 
     do 
     { 
      int read = recv(client_fd, buf, BUFFER_SIZE, 0); 

      if (read == 0) 
       break; 

      if (read == SOCKET_ERROR) 
      { 
       err = WSAGetLastError(); 
       if ((err != WSAENOTCONN) && (err != WSAECONNABORTED) && (err == WSAECONNRESET)) 
        on_error("Errore nella lettura dal client", &err); 
       break; 
      } 

      char *pbuf = buf; 
      do 
      { 
       int sent = send(client_fd, pbuf, read, 0); 
       if (sent == SOCKET_ERROR) 
       { 
        err = WSAGetLastError(); 
        if ((err != WSAENOTCONN) && (err != WSAECONNABORTED) && (err == WSAECONNRESET)) 
         on_error("Errore nella scrittura verso il client", &err); 

        keepLooping = false; 
        break; 
       } 

       pbuf += sent; 
       read -= sent; 
      } 
      while (read > 0); 
     } 
     while (keepLooping); 

     closesocket(client_fd); 
    } 

    WSACleanup(); 
    return 0; 
} 
+0

Реми, хотя есть некоторые интересные моменты в вашем коде (особенно из-за обучения POW), я получаю пару ошибок; Во-первых, легко: он должен быть отправлен = send (client_fd, pbuf, read, 0); Во-вторых, не так, я получаю «closeSocket, не объявленный в этой области» – piffy

+0

@piffy: Я исправил эти ошибки. –

+0

Был недостающий ')' в setsockopt (server_fd, SOL_SOCKET, SO_REUSEADDR (символ *) & opt_val, SizeOf (opt_val); , но теперь я получаю эту странную ошибку Л.Д. C: \ Program Files (x86) \ dev-cpp \ mingw32 \ mingw32 \ bin \ ld.exe \t не может открыть выходной файл winsock_srv.exe: Permission denied , что странно, так как версия C скомпилирована ОК. Уверена проблема с настройками Dev C++ с моей стороны. – piffy

1

Я извиняюсь, но

while (client_fd = SOCKET_ERROR) 

не имеете в виду?

(client_fd == SOCKET_ERROR) 
+2

Хотя это действительно логическая ошибка, это не тот, который мешает клиентам подключиться в первую очередь. Отсутствует вызов 'listen()' is. –

+0

ДА! это было как-то отрезано редактором в процессе portin ... – piffy

+0

Это происходит. Во всяком случае, они не получают никакого эха? Попробуйте 'printf' то, что вы получили сразу после' recv', чтобы убедиться, что вы действительно что-то получаете. Также обнулите свой буфер ('memset') до того, как вы не сохраните байты от последних данных. –

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