包含线程

时间:2018-03-15 15:03:33

标签: c++ multithreading sockets winsock winsockets

我在客户端和服务器之间创建了TCP套接字连接。

我需要使用线程,因为我从另一个进程获取x和y坐标,并使用OpenGL绘制这些值。

我唯一想到的方法就是为OpenGL绘图创建线程,并使用主线程通过套接字来接收坐标。

我的服务器端在添加#include <thread>之前工作得很好,所以我不知道问题是什么,为什么我在使用套接字时不能使用线程。

包含线程后,在调用recv()后,我收到错误:

  

WSAENOTSOCK 10038

使用WSAGetLastError();

我认为代码太长了,我无法发布,所以我可以复制一些必要的部分。

编辑:创建套接字和等待连接的代码。

// 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;
    }

1 个答案:

答案 0 :(得分:2)

  

我的服务器端在添加#include <thread>之前工作得很好,所以我不知道问题是什么,为什么我在使用套接字时不能使用线程。

需要注意的一点是<thread>是C ++ STL标题。如果你的代码碰巧有using namespace std;语句,你的套接字代码最终可能会调用STL的std::bind()函数而不是WinSock的bind()函数,这反过来会导致listen()失败,出现WSAEINVAL错误。由于您未对bind()listen()来电进行任何错误处理,因此您未进行检查。所以要注意这一点。避免使用using namespace std;语句,或将WinSock的bind()称为::bind()。并且总是对API调用进行错误处理。

您还在accept()上注释了您的错误处理。如果bind()listen()失败,accept()也会失败,导致其返回INVALID_SOCKET。这可以解释为什么您在WSAENOTSOCK上收到recv()错误。