main.cpp:
#include "Globals.h"
#include "Network_Init&Shutdown.h"
#include "acceptingThreadProcedure.h"
void main()
{
int serverSocket;
bool gQuitFlag = false;
// For threading, we will need a thread handle. We will receive this handle when we create the thread
// and can use this handle any time we need to reference our thread.
HANDLE threadHandle;
// a mutex for my shared data
HANDLE mutexHandle;
// Finally the file descriptor set (FD_SET). A FD_SET is simply our list of sockets.
// my master socket set which will be protected by my mutex
FD_SET masterSet;
cout << "MMORPG Server\n";
cout << "=============\n\n";
serverSocket = startupServerForListening(2751);
for (;;)
{
if (gQuitFlag)
{
break;
}
// check for errors
if (serverSocket == -1) {
printf("Network Startup Failed!\nProgram Terminating\n");
return;
}
// create the mutex
mutexHandle = CreateMutex(NULL, false, NULL);
if (mutexHandle == NULL)
{
printf("Error creating mutex\n");
shutdownServer(serverSocket, threadHandle, mutexHandle);
return;
}
// create the thread
int threadId;
threadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)acceptingThreadProcedure, &serverSocket, 0, (LPDWORD)&threadId);
if (threadHandle == NULL)
{
printf("Could not start acceptance thread!\n");
shutdownServer(serverSocket, threadHandle, mutexHandle);
return;
}
Sleep(100);
}
return;
}
Globals.h:
#include <iostream.h>
#include <winsock2.h>
#include <stdio.h>
#include <string>
using namespace std;
acceptingThreadProcedure.cpp:
#include "Globals.h"
#include "acceptingThreadProcedure.h"
// -----------------------------------------------------------------------------------
// acceptingThreadProcedure() - a procedure that will accept clients and add their
// sockets to the master file descriptor set
void acceptingThreadProcedure(int* serverSocket, int id, bool gQuitFlag, HANDLE mutexHandle, FD_SET masterSet)
{
// copy my socket over to a local variable
int mySocket = *serverSocket;
// run forever
for (;;) {
// accept a client like normal
unsigned int clientSocket = accept(mySocket, 0, 0);
// make sure things are ok
if (clientSocket == SOCKET_ERROR) {
// just stop of we received any errors
printf("Accept Failed!\n");
// signal to quit the application
gQuitFlag = true;
// and quit this thread
return;
} else {
// Everything went well. We need to take the client socket we received, and add
// it to our master socket set so the other thread can use it. Remember though,
// since our masterSet can be accessed by both threads, we need to make sure
// that we are not trying to write to it in this thread while at the same time we are trying
// to read from it in the other. We need to lock our mutex. We do this with the function
// WaitForSingleObject(). We need to give WaitForSingleObject() our mutex handle
// and a time value to wait. We will use INFINITE for the time value, because there
// really isn't anything else our thread needs to do.
// lock the mutex
WaitForSingleObject(mutexHandle, INFINITE);
// add this socket to the master set using our FD_SET() macro
FD_SET(clientSocket, &masterSet);
// Now we have to unlock our mutex so that our main thread can also access the data
// To be absolutely clear on this, here is how it works. When we call WaitForSingleObject()
// we have locked the data. We have control of the mutex until we call ReleaseMutex().
// If the main thread were to call WaitForSingleObject() before we call ReleaseMutex(),
// WaitForSingleObject() will block until we unlock the mutex. At that point, WaitForSingleObject()
// would immediately get a lock on the mutex, and the main thread would be able to continue.
// So always lock the mutex, write/read the data, and then unlock the mutex. This will make
// everyone trying to access the data very happy.
// unlock the mutex
ReleaseMutex(mutexHandle);
// a quick message
printf("client on %d connected\n", clientSocket);
id = id + 1;
send(clientSocket, (char*)&id, sizeof(id), 0);
}
}
}
acceptingThreadProcedure.h:
void acceptingThreadProcedure(int* serverSocket, int id, bool gQuitFlag, HANDLE mutexHandle, FD_SET masterSet);
NetworkInit&Shutdown.cpp:
#include "Globals.h"
#include "Network_Init&Shutdown.h"
// -----------------------------------------------------------------------------------
// startupServerForListening() - a function to startup winsock, and open a socket for listening
int startupServerForListening(unsigned short port)
{
// an error code we will use to get more information about our errors
int error;
// the winsock data structure
WSAData wsaData;
// startup winsock
if ((error = WSAStartup(MAKEWORD(2, 2), &wsaData)) == SOCKET_ERROR) {
printf("Could Not Start Up Winsock!\n");
return -1;
}
// create my socket
int mySocket = socket(AF_INET, SOCK_STREAM, 0);
// make sure nothing bad happened
if (mySocket == SOCKET_ERROR) {
printf("Error Opening Socket!\n");
return -1;
}
// the address structure
struct sockaddr_in server;
// fill the address structure with appropriate data
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = INADDR_ANY;
// and now bind my socket
if (bind(mySocket, (sockaddr*)&server, sizeof(server)) == SOCKET_ERROR) {
printf("Bind Failed!\n");
closesocket(mySocket);
return -1;
}
// mark my socket for listening
if (listen(mySocket, 5) == SOCKET_ERROR) {
printf("Listen Failed!\n");
closesocket(mySocket);
return -1;
}
printf("Server Started\n");
return mySocket;
}
// -----------------------------------------------------------------------------------
// shutdownServer() - a function to shutdown a socket and clean up winsock
void shutdownServer(int socket, HANDLE threadHandle, HANDLE mutexHandle)
{
// kill my thread and my handle
WaitForSingleObject(threadHandle, INFINITE);
CloseHandle(threadHandle);
CloseHandle(mutexHandle);
// close our socket
closesocket(socket);
// shut down winsock
WSACleanup();
printf("Server Shutdown\n");
}
NetworkInit&Shutdown.h:
[source lang = "cpp"]int startupServerForListening(unsigned short port);
void shutdownServer(int socket, HANDLE threadHandle, HANDLE mutexHandle);
When I try to connect my blitz client to this server, the client connects, but I get a windows error from the server:( I can't seem to figure out why! :'( Can anyone tell me why?