1

I created TCP socket connection between client and server.

It is necessary for me to use threads because I'm getting x and y coordinates from another process, and drawing those values with OpenGL.

Only way I had in mind was to create thread for OpenGL drawing, and use main thread to recieve coordinates by socket.

My server side worked perfectly before adding #include <thread>, so I have no idea what could the problem be and why couldn't I use threads while using sockets.

After including thread, after calling recv(), I'm getting error:

WSAENOTSOCK 10038

by using WSAGetLastError();

I think that code is too long for me to post it so I can copy some parts of it that are necessary.

EDIT: code of creating socket and waiting for connection.

// Inicijaliziraj winsock
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);

int wSocket = WSAStartup(ver, &wsData);
if (wSocket != 0) {
    cerr << "Problem with initialization of Winsock, exiting!" << endl;
    return;
}

// Create a socket
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET) {
    cerr << "Unable to create a socket! Quitting" << endl;
    return;
}

// Bind the ip address and port to a socket
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(54000);
hint.sin_addr.S_un.S_addr = INADDR_ANY; // Could also use inet_pton

bind(listening, (sockaddr*)&hint, sizeof(hint));

// Tell winsock socket is for listening
listen(listening, SOMAXCONN);

// Wait for a connection
sockaddr_in client;
int clientSize = sizeof(client);

SOCKET clientSocket = accept(listening, (sockaddr*)&client, &clientSize);
/*
if (clientSocket == INVALID_SOCKET) {
cerr << "Unable to connect to client socket, Quitting!" << endl;
return;
}*/

char host[NI_MAXHOST];              // Client's remote name
char service[NI_MAXHOST];           // Service (PORT) the client is connected on

ZeroMemory(host, NI_MAXHOST);       // Could use memset(host, 0, )
ZeroMemory(service, NI_MAXHOST);

if (getnameinfo((sockaddr*)&client, sizeof(client), host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0)
{
    cout << host << " connected on port " << service << endl;
}
else
{
    inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
    cout << host << " connected on port " << ntohs(client.sin_port) << endl;
}

// Close listening socket
closesocket(listening);

// While loop: accept and echo message back to client
char buf[4096];

//Opens new thread with canvas because otherwise while loop for recieving will block drawing
//std::thread t1(setDrawing, &iArgc, cppArgv);

while (true) {
    ZeroMemory(buf, 4096);

    // Wait for client to send data
    int bytesRecieved = recv(clientSocket, buf, 4096, 0);
    if (bytesRecieved == SOCKET_ERROR) {
        int err = WSAGetLastError();
        cerr << "Error in recv(). Quitting!" << endl;
        break;
    }
    if (bytesRecieved == 0) {
        cout << "Client disconnected " << endl;
        break;
    }
mr. Gauss
  • 601
  • 6
  • 14
  • `WSAENOTSOCK: Socket operation on nonsocket. An operation was attempted on something that is not a socket. Either the socket handle parameter did not reference a valid socket, or for select, a member of an fd_set was not valid.` Could you provide the code from creation of the socket to calling recv? – FloIsAwsm Mar 15 '18 at 15:12
  • I edited my post, the code is now in there. – mr. Gauss Mar 15 '18 at 15:16
  • Why have you commented out the check on `clientSocket`? What values are returned from `bind` and `listen`? Do you, at any point, have `using namespace std`? – G.M. Mar 15 '18 at 15:48
  • "*use main thread to recieve coordinates by socket*" - DON'T use the main thread for anything other than GUI updates and user interaction. If you are going to use threads to prepare OpenGL drawings, you can and should use threads or IOCP for your socket operations as well so you don't hinder the main thread in any way (unless you switch to window message based socket I/O calls, which I don't recommend). – Remy Lebeau Mar 15 '18 at 17:57

1 Answers1

2

My server side worked perfectly before adding #include <thread>, so I have no idea what could the problem be and why couldn't I use threads while using sockets.

One thing to pay attention to is that <thread> is a C++ STL header. If your code happens to have a using namespace std; statement, your socket code may end up calling the STL's std::bind() function instead of WinSock's bind() function, which would in turn cause listen() to fail with an WSAEINVAL error. Which you are not checking for since you are not doing any error handling on your bind() or listen() calls. So be aware of that. Avoid using namespace std; statements, or call WinSock's bind() as ::bind() instead. And ALWAYS do error handling on API calls.

You have also commented out your error handling on accept(). If bind() and listen() fail, so will accept(), causing it to return INVALID_SOCKET. Which could explain why you are then getting the WSAENOTSOCK error on recv().

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770