我在客户端和服务器之间创建了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;
}
答案 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()
错误。