Boardy
Boardy

Reputation: 36227

Sending and receiving data on a socket in c++

I am currently learning C++ and trying to understand sockets. I've done sockets before in high level languages in C# and Java but having problems in C++.

I've gone through the example at https://msdn.microsoft.com/en-us/library/windows/desktop/ms737593(v=vs.85).aspx.

The code I have is pretty much working except there's one thing I'm not sure of. When I've written other socket apps, I don't usually receive the response until after a new line character is received.

I thought maybe C++ add 1 character received at a time and adds to the buffer, so then when I close the socket, the buffer would contain everything that was received, but it seems to be a hex value, but the hex in an ascii converter seems to print gibberish instead of the socket data.

Below is my code

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;

If I'm not mistaken, if I was doing this in C# and connect via telnet to my socket I could send Hello but the app wouldn't do anything until I sent \r\n or the buffer was full.

However, in my C++ app, as soon as I enter H my app immediately responds prints out the recvBuf which just contains H plus a load of blank characters (shows as squares in cmd) which I'm assuming is the blank parts of the array buffer, and sends the reply.

Upvotes: 1

Views: 2596

Answers (2)

Vivek
Vivek

Reputation: 330

In a streaming protocol, it is useful to establish a protocol for determining the content length.

For example, a client could send the content-length followed by data and the server would first read the content length and then read the socket in a loop and buffer the data until content-length number of bytes have been received.

Upvotes: 1

user207421
user207421

Reputation: 311023

Sockets don't care about newlines or nulls. Only higher-level streaming APIs do that. The important thing is the return value of recv(). That tells you exactly how many bytes were received. Nothing in the buffer beyond that count is valid.

Upvotes: 2

Related Questions