1

我在客户端和服务器之间创建了 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;
    }
4

1 回答 1

2

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

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

您还注释掉了您对accept(). 如果bind()listen()失败,那么将accept()导致它返回INVALID_SOCKET。这可以解释为什么您会WSAENOTSOCKrecv().

于 2018-03-15T18:03:03.120 回答