I've been trying to write a simple server-client connection using Winsock2. I've written similar server-client code before and have copied and pasted the same code from a previous project I made, I copied this code because it worked beforehand and when I had pasted it, I kept getting WSA error 10037 and I get this error when attempting to connect to the server from the client, I made sure to call init before I connect to the server, but I continue to get that same error. Server-side I don't get anything saying that there is a client that wishes to connect.
client Initialization:
bool Client::init() {
WSADATA wsa;
int result = WSAStartup(MAKEWORD(2, 2), &wsa);
if (result != 0) {
printf("WSAStartup Failed: %i\n", result);
return false;
}
winSockInit = true;
clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (clientSocket == INVALID_SOCKET) {
printf("Socket Creation Failed: %i\n", WSAGetLastError());
WSACleanup();
winSockInit = false;
return false;
}
socketInit = true;
u_long mode = 1;
result = ioctlsocket(clientSocket, FIONBIO, &mode);
if (result == SOCKET_ERROR) {
printf("ioctlsocket Failed: %i\n", result);
closesocket(clientSocket);
WSACleanup();
socketInit = false;
winSockInit = false;
return false;
}
return true;
}
Connect to server code:
void Client::reset() {
if (socketInit)
closesocket(clientSocket);
if (winSockInit)
WSACleanup();
socketInit = false;
winSockInit = false;
isConnected = false;
}
bool Client::connectToServer(std::string ip, int port) {
sockaddr_in serverAddr;
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
int result = inet_pton(AF_INET, ip.c_str(), &serverAddr.sin_addr);
if (result != 1) {
printf("Failed to convert IP address: %i\n", WSAGetLastError());
reset();
return false;
}
serverIp = ip;
//Connect to the server
serverAddr.sin_port = htons(port);
serverPort = port;
bool success = false;
u64 connectAttempts = 0;
while (connectAttempts < 10 && !success) {
//--------------------------------------------
//Issue On the following line
result = connect(clientSocket, (sockaddr*)&serverAddr, sizeof(serverAddr));//<------------------------------This is the issue
//--------------------------------------------
if (result == SOCKET_ERROR) {
int error = WSAGetLastError();
if (error == WSAEISCONN) {
//printf("Client::Already connected\n");
success = true;
break;
}
else if (error == WSAEWOULDBLOCK) {//It either runs this
printf("Blocked\n");
std::this_thread::sleep_for(std::chrono::seconds(1));
}
else if (error == WSAEALREADY) {//Or this
printf("WSAEALREADY\n");
std::this_thread::sleep_for(std::chrono::seconds(1));
}
else {
printf("Client::Socket Error: %i\n", error);
reset();
return false;
}
}
else {
success = true;
break;
}
connectAttempts++;
}
printf("Attempts: %llu\n", connectAttempts);
if (!success)
return false;
isConnected = true;
return true;
}
Server side Init:
bool Server::init() {
//WSA stuff
int result = WSAStartup(MAKEWORD(2, 2), &wsa);
if (result != 0) {
std::cerr << "Server::WSAStartup Failed: " << result << std::endl;
return false;
}
//Create the listen socket
listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listenSocket == INVALID_SOCKET) {
std::cerr << "Server::Socket Failed: " << WSAGetLastError() << std::endl;
WSACleanup();
return false;
}
//Set socket options
unsigned long argp = 1;
result = setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&argp, sizeof(argp));
if (result != 0) {
printf("Setsockopt failure: %i\n", result);
closesocket(listenSocket);
WSACleanup();
return false;
}
//Set non blocking mode
u_long mode = 1;
result = ioctlsocket(listenSocket, FIONBIO, &mode);
if (result == SOCKET_ERROR) {
std::cerr << "Server::ioctlsocket (Make it non blocking) Failed: " << WSAGetLastError() << std::endl;
closesocket(listenSocket);
WSACleanup();
return false;
}
//Bind address and port
sockaddr_in serverAddr = { 0 };
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddr.sin_port = htons(port);
result = bind(listenSocket, (sockaddr*)&serverAddr, sizeof(serverAddr));
if (result == SOCKET_ERROR) {
std::cerr << "Server::Bind Failed: " << WSAGetLastError() << std::endl;
closesocket(listenSocket);
WSACleanup();
return false;
}
//Set up listening
result = listen(listenSocket, SOMAXCONN);
if (result == SOCKET_ERROR) {
std::cerr << "Server::listen Failed: " << WSAGetLastError() << std::endl;
closesocket(listenSocket);
WSACleanup();
return false;
}
isRunning = true;
return true;
}
Server side checking for client:
struct ServerClient {
sockaddr_in clientAddrWin;
SOCKET clientSocketWin;
};
void Server::checkIncomingConnection() {
fd_set readSet = { 1,{listenSocket} };
timeval timeoutVal = { 0,0 };
int result = select(0, &readSet, NULL, NULL, &timeoutVal);
if (result == SOCKET_ERROR) {
printf("Server::checkIncomingConnection Could not select: %i\n", WSAGetLastError());
return;
}
else if (result == 0) {
//printf("Server::checkIncomingConnection select timed out: %i\n", WSAGetLastError());
return;
}
ServerClient incoming;
int clientAddrLen = sizeof(incoming.clientAddrWin);
incoming.clientSocketWin = accept(listenSocket, (sockaddr*)&incoming.clientAddrWin, &clientAddrLen);
if (incoming.clientSocketWin == SOCKET_ERROR || incoming.clientSocketWin == INVALID_SOCKET) {
printf("Server::checkIncomingConnection Error Accepting Client: %i\n", WSAGetLastError());
return;
}
printf("Has Incoming Client\n");
addClient(&incoming);
}
Error 10037 is WSAEALREADY
(Operation already in progress):
An operation was attempted on a nonblocking socket with an operation already in progress — that is, calling
connect
a second time on a nonblocking socket that is already connecting, or canceling an asynchronous request (WSAAsyncGetXbyY
) that has already been canceled or completed.
You are putting the client socket into non-blocking mode, and then calling connect()
in a loop. And per the connect()
documentation:
With a nonblocking socket, the connection attempt cannot be completed immediately. In this case, connect will return
SOCKET_ERROR
, andWSAGetLastError
will returnWSAEWOULDBLOCK
...Until the connection attempt completes on a nonblocking socket, all subsequent calls to
connect
on the same socket will fail with the error codeWSAEALREADY
, andWSAEISCONN
when the connection completes successfully. Due to ambiguities in version 1.1 of the Windows Sockets specification, error codes returned fromconnect
while a connection is already pending may vary among implementations. As a result, it is not recommended that applications use multiple calls toconnect
to detect connection completion......
Error code Meaning WSAEALREADY A nonblocking connect call is in progress on the specified socket.
So, it makes sense that you would be seeing WSAEALREADY
, since you are calling connect()
up to 9 more times while the 1st call is still trying to connect to the server.
Something else to note is that if your connect()
loop reaches its max attempts, you exit the loop and return false
without reset()
'ing the socket, like you do with every other error condition.
The correct way to wait for a non-blocking connect()
operation to finish its work is to be notified by the socket when the operation is finished:
there are three possible scenarios:
- Use the
select
function to determine the completion of the connection request by checking to see if the socket is writable.- If the application is using
WSAAsyncSelect
to indicate interest in connection events, then the application will receive anFD_CONNECT
notification indicating that the connect operation is complete (successfully or not).- If the application is using
WSAEventSelect
to indicate interest in connection events, then the associated event object will be signaled indicating that the connect operation is complete (successfully or not).
So, you can get rid of the loop altogether. In this case, select()
will suffice:
For connection-oriented, nonblocking sockets, it is often not possible to complete the connection immediately. In such a case, this function returns the error
WSAEWOULDBLOCK
. However, the operation proceeds.When the success or failure outcome becomes known, it may be reported in one of two ways, depending on how the client registers for notification.
- If the client uses the
select
function, success is reported in the writefds set and failure is reported in the exceptfds set.- If the client uses the functions
WSAAsyncSelect
orWSAEventSelect
, the notification is announced withFD_CONNECT
and the error code associated with theFD_CONNECT
indicates either success or a specific reason for failure.
For example:
bool Client::connectToServer(std::string ip, int port) {
sockaddr_in serverAddr;
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(port);
int result = inet_pton(AF_INET, ip.c_str(), &serverAddr.sin_addr);
if (result != 1) {
if (result == -1) {
printf("Failed to convert IP address: %i\n", WSAGetLastError());
}
else {
printf("Invalid IP address given\n");
}
reset();
return false;
}
serverIp = ip;
serverPort = port;
//Connect to the server
result = connect(clientSocket, (sockaddr*)&serverAddr, sizeof(serverAddr));
if (result == SOCKET_ERROR) {
int error = WSAGetLastError();
if (error != WSAEWOULDBLOCK) {
printf("Client::Socket Error: %i\n", error);
reset();
return false;
}
printf("Blocked\n");
fd_set wfd, efd;
FD_ZERO(&wfd); FD_SET(clientSocket, &wfd);
FD_ZERO(&efd); FD_SET(clientSocket, &efd);
timeval timeout;
timeout.tv_sec = 10;
timeout.tv_usec = 0;
result = select(0, NULL, &wfd, &efd, &timeout);
if (result == SOCKET_ERROR) {
printf("Client::Socket Error: %i\n", WSAGetLastError());
reset();
return false;
}
if (result == 0) {
printf("Client::Socket Timed Out\n");
reset();
return false;
}
if (FD_ISSET(clientSocket, &efd)) {
result = getsockopt(clientSocket, SOL_SOCKET, SO_ERROR, (char*)&error, sizeof(error));
if (result == SOCKET_ERROR) {
error = WSAGetLastError();
}
printf("Client::Socket Error: %i\n", error);
reset();
return false;
}
}
isConnected = true;
return true;
}