2016-11-03 2 views
0

В настоящее время я изучаю C++ и пытаюсь понять сокеты. Я делал сокеты раньше на языках высокого уровня в C# и Java, но имел проблемы на C++.Отправка и получение данных в сокете в C++

Я рассмотрел пример на https://msdn.microsoft.com/en-us/library/windows/desktop/ms737593(v=vs.85).aspx.

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

Я подумал, что возможно, C++ добавляет 1 символ и добавляется в буфер, поэтому, когда я закрываю сокет, буфер будет содержать все, что было получено, но оно, как представляется, является шестнадцатеричным значением, но hex в конвертере ascii, похоже, печатает тарабарщину вместо данных сокета.

Ниже мой код

const int DEFAULT_BUF_LEN = 525; 
    InitialiseLibrary initLibrary("tunnel.conf"); 
    if (initLibrary.initialise(0)) 
    { 
     cout << "Failed to initialise library" << endl; 
    } 

    BitsLibrary bitsLibrary; 
    StaticSettings staticSettings(&bitsLibrary, "tunnel.conf"); 

    //Open a socket connection 
    WSAData wsaData; 
    int iResult; 

    SOCKET listenSocket = INVALID_SOCKET; 
    SOCKET clientSocket = INVALID_SOCKET; 

    struct addrinfo *result = NULL; 
    struct addrinfo hints; 

    int iSendResult; 
    char recvBuf[DEFAULT_BUF_LEN]; 
    int recBufLen = DEFAULT_BUF_LEN; 

    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); 
    if (iResult != 0) 
    { 
     cout << "WSAStartup Failed with error: " << iResult << endl; 
     return EXIT_FAILURE; 
    } 

    ZeroMemory(&hints, sizeof(hints)); 
    hints.ai_family = AF_INET; 
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_protocol = IPPROTO_TCP; 
    hints.ai_flags = AI_PASSIVE; 

    iResult = getaddrinfo(NULL, "500", &hints, &result); 
    if (iResult != 0) 
    { 
     cout << "getaddrinfo failed with error: " << iResult << endl; 
     return EXIT_FAILURE; 
    } 

    listenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol); 
    if (listenSocket == INVALID_SOCKET) 
    { 
     cout << "Socket failed with error: " << WSAGetLastError() << endl; 
     freeaddrinfo(result); 
     WSACleanup(); 
     return EXIT_FAILURE; 
    } 

    iResult = ::bind(listenSocket, result->ai_addr, (int)result->ai_addrlen); 
    if (iResult != 0) 
    { 
     cout << "bind failed with error: " << iResult << endl; 
     FreeAddrInfo(result); 
     closesocket(listenSocket); 
     WSACleanup(); 
     return EXIT_FAILURE; 
    } 

    freeaddrinfo(result); 
    iResult = listen(listenSocket, SOMAXCONN); 
    if (iResult == SOCKET_ERROR) 
    { 
     cout << "Listen failed with error: " << WSAGetLastError() << endl; 
     closesocket(listenSocket); 
     WSACleanup(); 
     return EXIT_SUCCESS; 
    } 
    sockaddr_in clientAddr; 
    socklen_t sin_size = sizeof(struct sockaddr_in); 
    clientSocket = accept(listenSocket, (struct sockaddr*)&clientAddr, &sin_size); 
    send(clientSocket, "welcome", string("welcome").length(),0); 
    if (clientSocket == INVALID_SOCKET) 
    { 
     cout << "accept failed with error: " << WSAGetLastError() << endl; 
     closesocket(listenSocket); 
     WSACleanup(); 
     return EXIT_FAILURE; 
    } 

    closesocket(listenSocket); 

    do { 
     iResult = recv(clientSocket, recvBuf, recBufLen, 0); 
     if (iResult > 0) 
     { 
      cout << "Bytes received: " << iResult << endl; 
      cout << "Received: " << recvBuf << endl; 

      iSendResult = send(clientSocket, recvBuf, iResult, 0); 
      if (iSendResult == SOCKET_ERROR) 
      { 
       cout << "send failed with error: " << WSAGetLastError() << endl; 
       closesocket(clientSocket); 
       WSACleanup(); 
       return EXIT_FAILURE; 
      } 
      cout << "Bytes sent " << iSendResult << endl; 
     } 
     else if (iResult == 0) 
     { 
      cout << "Connection closing" << endl; 
     } 
     else 
     { 
      cout << "Recv failed with error: " << WSAGetLastError() << endl; 
      closesocket(clientSocket); 
      WSACleanup(); 
      return EXIT_FAILURE; 
     } 
    } while (iResult > 0); 

    iResult = shutdown(clientSocket, SD_SEND); 
    if (iResult == SOCKET_ERROR) 
    { 
     cout << "shutdown failed with error: " << WSAGetLastError() << endl; 
     closesocket(clientSocket); 
     WSACleanup(); 
     return EXIT_FAILURE; 
    } 
    closesocket(clientSocket); 
    WSACleanup(); 

    cout << "Message was: " << recvBuf << endl; 

    return EXIT_SUCCESS; 

Если я не ошибаюсь, если я делаю это в C# и подключение через телнет к моему гнезду я мог отправить Hello но приложение никогда ничего не делал бы, пока я отправлен \r\n или буфер был заполнен.

Однако в моей C++ приложение, как только я вхожу H мое приложение немедленно реагирует распечатывает recvBuf, который просто содержит H плюс груз пустых символов (показывает, как квадраты в ЦМД), который я предполагаю, что это пустая части буфера массива и отправляет ответ.

ответ

2

Розетки не заботятся о новых символах или нулях. Это делают только потоковые API верхнего уровня. Важное значение имеет возвращаемое значение recv(). Это точно указывает, сколько байтов было получено. Ничто в буфере за пределами этого счета не является допустимым.

+0

А я думал, что это может быть так, поэтому в C++ нет ничего, что сделало бы это для меня, если бы я хотел, чтобы recv возвращался только к новым строкам, мне нужно было бы это сам кодировать, нет библиотек или чего-то еще часть C++, которая сделала бы это – Boardy

+0

@Boardy Существует около бесконечных библиотек, которые делают это (большинство из них плохие, но все же). – deviantfan

+0

ха-ха. Хорошо, привет. Спасибо за вашу помощь – Boardy

1

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

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