I'm trying to use two threads to run a server and a client.
I use a semaphore to block the client thread from doing too much before the server has been set up (ListenSocket
, etc.).
When The server gets far enough, I use ReleaseSemaphore()
but it returns an Invalid Handle
error.
I've read that there are many possible issues which can be the source of this error.
The exact line is if (ReleaseSemaphore(semaphore, 1, NULL)){}
which can be found about 55% of the way into the Server.cpp
file
Header.h:
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <process.h>
unsigned int __stdcall servermain(void*);
unsigned int __stdcall clientmain(void*);
static HANDLE semaphore;
Source.cpp:
#include "Header.h"
int main(int argc, char* argv[])
{
HANDLE serverHandle, clientHandle;
semaphore = CreateSemaphore(
NULL,
0, //initial count
1, //max count
NULL);
if (semaphore == NULL){
printf("CreateSemaphore error: %d
", GetLastError());
return 1;
}
/*call to the methods in the Client and Server files*/
serverHandle = (HANDLE)_beginthreadex(0, 0, &servermain, 0, 0, 0);
clientHandle = (HANDLE)_beginthreadex(0, 0, &clientmain, 0, 0, 0);
WaitForSingleObject(serverHandle, INFINITE);
WaitForSingleObject(clientHandle, INFINITE);
CloseHandle(serverHandle);
CloseHandle(clientHandle);
CloseHandle(semaphore);
return 0;
}
Server.cpp:
#include "Header.h"
#pragma comment(lib, "Ws2_32.lib")
#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "27015"
unsigned int __stdcall servermain(void* data)
{
printf("SERVER STARTED. Thread: %i
", GetCurrentThreadId());
WSADATA wsaData;
int iResult;
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET ClientSocket = INVALID_SOCKET;
struct addrinfo
*result = NULL,
hints;
int iSendResult;
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); //initiates the use of the Winsock DLL
if (iResult != 0) {
printf("%i Server: ", GetCurrentThreadId());
printf("WSAStartup failed with error: %d
", iResult);
return 1;
}
//////////////////////////////////////
// Creating a Socket for the Server //
//////////////////////////////////////
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
// Resolve the local address and port to be used by the server
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
printf("%i Server: ", GetCurrentThreadId());
printf("getaddrinfo failed with error: %d
", iResult);
WSACleanup();
return 1;
}
// Create a SOCKET for the server to listen for client connections
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("%i Server: ", GetCurrentThreadId());
printf("socket failed with error: %ld
", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
//////////////////////
// Binding a Socket //
//////////////////////
// Setup the TCP listening socket
iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
printf("%i Server: ", GetCurrentThreadId());
printf("bind failed with error: %d
", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
char answer = 'y'; // char answer[8]; // char *answer = "";
do{
printf("%i Server: ", GetCurrentThreadId());
printf("Would you like to wait for client?(Y/N) ");
answer = getchar(); // fgets(answer, 1, stdin);
printf("%c
", answer);
} while (answer != 'y' && answer != 'n'); // double quotes "" are for c-strings. single quotes '' are for chars.
if (answer == 'n'){
return 1;
}
else printf("%i Server: Listening for a client...
", GetCurrentThreadId());
freeaddrinfo(result);
printf("Semaphore value: %i
", semaphore);
//Now that the server is running, signal the semaphore to allow client to connect.
if (ReleaseSemaphore(semaphore, 1, NULL)) //ReleaseSemaphore() returns a bool value
{
printf("%i Server: Semaphore Released
", GetCurrentThreadId());
}
else
{
printf("Server Release Semaphore error: %d
", GetLastError());
printf("Server Semaphore value: %i
", semaphore);
return 1;
}
///////////////////////////
// Listening on a Socket //
///////////////////////////
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
printf("%i Server: ", GetCurrentThreadId());
printf("Listen failed with error: %ld
", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
////////////////////////////
// Accepting a Connection //
////////////////////////////
// Accept a client socket
ClientSocket = accept(ListenSocket, NULL, NULL);
if (ClientSocket == INVALID_SOCKET) {
printf("%i Server: ", GetCurrentThreadId());
printf("accept failed: %d
", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
// No longer need server socket
closesocket(ListenSocket); // This will need to be changed if multiple clients shall be allowed
//////////////////////////////////////////////
// Receiving and Sending Data on the Server //
//////////////////////////////////////////////
// Receive until the peer shuts down the connection
do {
iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
if (iResult > 0) {
printf("%i Server: ", GetCurrentThreadId());
printf("Bytes received: %d
", iResult);
// Echo the buffer back to the sender
iSendResult = send(ClientSocket, recvbuf, iResult, 0);
if (iSendResult == SOCKET_ERROR) {
printf("send failed: %d
", WSAGetLastError());
closesocket(ClientSocket); //why close a socket if something doesn't send correctly?
WSACleanup();
return 1; //kills main()
}
printf("Bytes sent: %d
", iSendResult);
}
else if (iResult == 0)
printf("Connection closing...
");
else {
printf("recv failed with error: %d
", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup(); //function terminates use of the Winsock 2 DLL (Ws2_32.dll)
return 1;
}
} while (iResult > 0);
// shutdown the send half of the connection since no more data will be sent
iResult = shutdown(ClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("%i Server: ", GetCurrentThreadId());
printf("shutdown failed with error: %d
", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
// cleanup
closesocket(ClientSocket);
WSACleanup();
_endthreadex(0); //end thread within the thread.
return 0;
}
Client.cpp:
#include "Header.h"
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")
#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "27015"
unsigned int __stdcall clientmain(void* data)
{
printf("CLIENT STARTED. Thread: %i
", GetCurrentThreadId());
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
struct addrinfo *result = NULL,
*ptr = NULL,
hints;
char *sendbuf = "this is a test";
char recvbuf[DEFAULT_BUFLEN];
int iResult;
int recvbuflen = DEFAULT_BUFLEN;
// Validate the parameters
/*if (argc != 2) {
printf("usage: %s server-name
", argv[0]);
return 1;
}*/
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("%i Client: ", GetCurrentThreadId());
printf("WSAStartup failed with error: %d
", iResult);
return 1;
}
printf("Client winsock initialized
");
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port
/*iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed with error: %d
", iResult);
WSACleanup();
return 1;
}*/
printf("%i Client: before semaphore
", GetCurrentThreadId());
//Wait for Server to be up and running
bool cont = TRUE;
while (cont)
{
DWORD returnval = WaitForSingleObject(semaphore, 0L); // 0 vs 0L ?
//printf("Semaphore value: %i
", semaphore);
switch (returnval)
{
// The semaphore object was signaled.
case WAIT_OBJECT_0:
printf("Thread %d: wait succeeded
", GetCurrentThreadId());
break;
// The semaphore was nonsignaled, so a time-out occurred.
case WAIT_TIMEOUT:
printf("Thread %d: wait timed out
", GetCurrentThreadId());
break;
}
}
printf("%i Client: after semaphore
", GetCurrentThreadId());
// Attempt to connect to an address until one succeeds
for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {
printf("%i Client: ", GetCurrentThreadId());
printf("socket failed with error: %ld
", WSAGetLastError());
WSACleanup();
return 1;
}
// Connect to server.
iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (ConnectSocket == INVALID_SOCKET) {
printf("%i Client: ", GetCurrentThreadId());
printf("Unable to connect to server!
");
WSACleanup();
return 1;
}
// Send an initial buffer
iResult = send(ConnectSocket, sendbuf, (int)strlen(sendbuf), 0);
if (iResult == SOCKET_ERROR) {
printf("%i Client: ", GetCurrentThreadId());
printf("send failed with error: %d
", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
printf("Bytes Sent: %ld
", iResult);
// shutdown the connection since no more data will be sent
iResult = shutdown(ConnectSocket, SD_SEND