Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Threading for multi-client server

Status
Not open for further replies.

digitalpacman

Programmer
Apr 4, 2003
17
US
I'm currently learning how to create servers and clients for gaming purposes. I wrote a simple program which acts as either server or client. It uses multithreading for the login part of the server so that it can listen while running the program, basic heh. The error is that sometimes I get a "Unhandled handle" error, which seems to have gone away but now the server shuts down after 2 people connect to the server.

// Standard Includes
#include <iostream.h>
#include <stdio.h>
#include <conio.h>
#include <SocketObject.h>
#include <apvector.h>

void vServerConnection( int iListenPort );
void vClientConnection( char *szServerIP, int iServerListenPort );
void thrClientsThread(SocketObject *sm);
SocketObject ClientSocketObject[10];
SocketObject ServerSocketObject; // Server Socket Object
// Mutex handle
HANDLE g_hCreditMutex;
int clients = -1;

struct stChatPacket
{
stPacketHeader stHeader;
char szChatMessage[128];
};

//
// ----> Main Program Function (REQUIRED)
//
int main( int argc, char *argv[] )
{
g_hCreditMutex = CreateMutex(
NULL,
0,
&quot;Credit Mutex&quot;
);

if( argc < 3 ) {
return( 0 );
}

if( !stricmp( argv[1], &quot;server&quot; ) )
vServerConnection( atoi( argv[2] ) );
else
vClientConnection( argv[2], atoi( argv[3] ) );

return( 1 );
}

// Function for server
void vServerConnection( int iListenPort )
{
SocketObject ClientSObject; // Server Socket Object
DWORD dwCreditsID;
HANDLE hClientsThreadHandle;

char DataPacket[128]; // Data Packet to Transmit
int iBytesReceived = 0; // # of Bytes Received
int iBytesSent = 0;
stChatPacket ChatPacket;
char szPacketBuffer[32768];

cout << &quot;<Server> Attempting to listen on Port &quot; << iListenPort << endl;

// Attempt to start the server
if ( ServerSocketObject.Bind( iListenPort ) )
{
hClientsThreadHandle = CreateThread(
NULL, // Security, default is ok
NULL, // Initial stack size, default ok
(LPTHREAD_START_ROUTINE ) &thrClientsThread, // The thread function
&ClientSocketObject, // Data to pass to the function
NULL, // Creation flags, keep NULL
&dwCreditsID // Identifier (we dont use this)
);
// Loop forever or until a break is issued
char szTempChar;
while (1)
{
while( !_kbhit() )
{
WaitForSingleObject( g_hCreditMutex, INFINITE );
// Check for incomming data
for ( int a = 0; a <= clients; ++a )
{
iBytesReceived = ClientSocketObject[a].vGetPacket(szPacketBuffer);
if( iBytesReceived > 0 )
{
// Copy the received data into the chat packet
memcpy(&ChatPacket,szPacketBuffer,sizeof(ChatPacket));
strcpy(DataPacket,ChatPacket.szChatMessage);
cout << endl << &quot;<Client> &quot; << DataPacket << endl;
printf(&quot;<Server> &quot;);
}
}
ReleaseMutex( g_hCreditMutex );
}
szTempChar = getche();
if( szTempChar == 13 )
break;
}
// Disconnect the client
for ( int a = 0; a <= clients; ++a )
{
ClientSocketObject[a].Disconnect();
}

cout << &quot;<Server> Clients Disconnected&quot; << endl;
}
else {
cout << &quot;<Server> Failed to Listen&quot; << endl;
}
CloseHandle( g_hCreditMutex );
CloseHandle( hClientsThreadHandle );
}

// Function for client
void vClientConnection( char *szServerIP, int iServerListenPort )
{
SocketObject ClientSObject; // Server Socket Object
char szTempChar;
int iBytesSent;

cout << &quot;<Client> Connecting to &quot; << szServerIP << &quot;, Port &quot; << iServerListenPort << endl;

// Connect to the IP and Port
if( ClientSObject.Connect( szServerIP, iServerListenPort ) )
{
while (true)
{
while ( !_kbhit() )
{
iBytesSent = ClientSObject.Send(&quot;Testing&quot;,128,0);
}
szTempChar = getche();
if( szTempChar == 13 )
break;
}
}

// Disconnect from the server
ClientSObject.Disconnect();
}

void thrClientsThread( SocketObject *sm )
{
// Loop until we are told to quit
while( 1 )
{
ServerSocketObject.Listen();
WaitForSingleObject( g_hCreditMutex, INFINITE );
clients += 1;
ServerSocketObject.Accept( sm[ clients ] );
cout << &quot;<Server> Client Connected to Port &quot; << 6000 << &quot;; ID: &quot; << clients << endl;
ReleaseMutex( g_hCreditMutex );
}
}
 
You can't run under the debugger?

Also, a bit of advice about posting on Tek-tips: nobody is going to want to read your entire program to find a problem in it.

Do you think you could post only the relevant parts of your code, and maybe try stepping through code, to watch it go under.
 
Um debugger just goes &quot;eee find the .cpp file!&quot; so there's no help there. Plus this is a server/client program so like yeah I dun think debugger can work on something like that. Section of code I guess that is &quot;relevant&quot;:

void thrClientsThread( SocketObject *sm )
{
// Loop until we are told to quit
while( 1 )
{
ServerSocketObject.Listen();
WaitForSingleObject( g_hCreditMutex, INFINITE );
clients += 1;
ServerSocketObject.Accept( sm[ clients ] );
cout << &quot;<Server> Client Connected to Port &quot; << 6000 << &quot;; ID: &quot; << clients << endl;
ReleaseMutex( g_hCreditMutex );
}
}

and

char szTempChar;
while (1)
{
while( !_kbhit() )
{
WaitForSingleObject( g_hCreditMutex, INFINITE );
// Check for incomming data
for ( int a = 0; a <= clients; ++a )
{
iBytesReceived = ClientSocketObject[a].vGetPacket(szPacketBuffer);
if( iBytesReceived > 0 )
{
// Copy the received data into the chat packet
memcpy(&ChatPacket,szPacketBuffer,sizeof(ChatPacket));
strcpy(DataPacket,ChatPacket.szChatMessage);
cout << endl << &quot;<Client> &quot; << DataPacket << endl;
printf(&quot;<Server> &quot;);
}
}
ReleaseMutex( g_hCreditMutex );
}
szTempChar = getche();
if( szTempChar == 13 )
break;
}
 
Well I took your advice and it seems still no one=p

I got a new question tho. Does this code even if its in a thread make the program wait for connections and NOT do anything else even when in a thread?

void thrClientsThread( SocketObject *sm )
{
// Loop until we are told to quit
while( 1 )
{
ServerSocketObject.Listen();
WaitForSingleObject( g_hCreditMutex, INFINITE );
clients += 1;
ServerSocketObject.Accept( sm[ clients ] );
cout << &quot;<Server> Client Connected to Port &quot; << 6000 << &quot;; ID: &quot; << clients << endl;
ReleaseMutex( g_hCreditMutex );
}
}

I think it will because I also have code in the server part of the program which when the enter button is hit, the server should shut down. Like this:

// Loop forever or until a break is issued
char szTempChar;
while (1)
{
while( !_kbhit() ) {...}

szTempChar = getche();
if( szTempChar == 13 )
break;
}

---hmm
thats it.. anyone know?
 
I'm not familiar with this SocketObject class you're using.

>> Does this code even if its in a thread make the program wait for connections and NOT do anything else even when in a thread?

A call to a wait function blocks the thread until the synchronization object signals. It doesn't block the entire process, but it does block the thread.

However, the Windows Sockets functions, by default, have a blocking nature, i.e. the accept function will WAIT for a connection, and the receive function will WAIT for incoming data.

Anyway, the typical server is configured such that there is one thread that listens, and more threads -- one for each connection that is present.

Wow, suddenly this is starting to look like something I posted not too long ago. Only I was the one asking the question.
 
Well.. since you obviously see what I'm trying to do.. you got a way for me to do it? ;X Cause this way doesn't seem to work to well. The data isn't being sent to the server. I think... o.o

if( ClientSObject.Connect( szServerIP, iServerListenPort ) )
{
while (true)
{
while ( !_kbhit() ) { }
iBytesSent = ClientSObject.Send(&quot;Testing&quot;,128,0);
szTempChar = getche();
if( szTempChar == 13 )
break;
}
}
 
Also here is some more information. SocketObject is just a prewritten class I'm using to learn this stuff with It is just the predefined windows SOCKET class with some variability.

Here is the code for the functions I use:

-----

int SocketObject::Listen( void )
{
return listen( skSocket, 32 );
}

-----

int SocketObject::Send(char *szBuffer, int iBufLen, int iFlags)
{
return send(skSocket,szBuffer,iBufLen,iFlags);
}

-----

int SocketObject::Recv( char *szBuffer, int iBufLen, int iFlags)
{
return recv(skSocket, szBuffer, iBufLen, iFlags);
}

-----

bool SocketObject::Accept( SocketObject &skAcceptSocket )
{
sockaddr_in saClientAddress;
int iClientSize = sizeof(sockaddr_in);
SOCKADDR IPAddress;

skAcceptSocket.skSocket = accept( skSocket, (struct sockaddr*)&saClientAddress, &iClientSize );

if( skAcceptSocket.skSocket == INVALID_SOCKET )
{
return false;
}
else
{
memcpy(&IPAddress,&saClientAddress,sizeof(saClientAddress));
printf(&quot;%d.%d.%d.%d is Connecting\n&quot;,saClientAddress.sin_addr.S_un.S_un_b.s_b1,saClientAddress.sin_addr.S_un.S_un_b.s_b2,saClientAddress.sin_addr.S_un.S_un_b.s_b3,saClientAddress.sin_addr.S_un.S_un_b.s_b4);

skAcceptSocket.stReceive.skSocket = skAcceptSocket.skSocket;
skAcceptSocket.stReceive.szBuffer[0] = NULL;
skAcceptSocket.stReceive.iReadPos = 0;
skAcceptSocket.stReceive.iWritePos = 0;
skAcceptSocket.stReceive.iTerminate = 0;

// Create the thread to receive data
CreateThread(
NULL, // pointer to security attributes
NULL, // initial thread stack size
(LPTHREAD_START_ROUTINE ) &skAcceptSocket.thrReceiveThread, // pointer to thread function
&skAcceptSocket.stReceive, // argument for new thread
NULL, // creation flags
&skAcceptSocket.dwReceiveHandle // pointer to receive thread ID
);

return true;
}
}
 
okay.. does anyone have a thread they can copy paste for me that will accept connections? ;/
 
digitalpacman,

What is your background with the C++ language. What is your background with Socket development. What is your background with regards to multi-thread application development.

this question concerns me:
does anyone have a thread they can copy paste for me

If you are trying to create a C++ multi-threaded Socket server application by copy/paste technique, i cannot help. That is just not a reasonable approach to such a project.

-pete


 
I was just following this example in this book for learning how to game programming. I don't have any background in online programming. But I have a background in C++ programmming and computer science. I've taking 2 computer programming C++ and 2 years of AP Computer Science. I also program in a bunch of online programming languages. No background in the socket object seeing it is for accepting data and sending out data. I just really need to learn how to write a program that will sit and wait for connections but at the same time it will STILL be able to do operations.
 
>> I just really need to learn how to write a
>> program that will sit and wait for connections but at
>> the same time it will STILL be able to do operations.

I question the decision to research two separate technologies ( Sockets, Threading) in a single project when you have no previous experience with either of them. You are over complicating each issue with the presence of the other.

-pete




 
Over complicating? But I know it's a simple thing -.- Why can't you guys just show me? lol. It can't be THAT long of code can it?
 
>> I know it's a simple thing

Is that a contradiction or am i missing something? If you already &quot;know&quot; then why are you asking us?

Or... how can you “know” it is simple if you don’t know “how” to do it? [bugeyed]
-pete


 
Um I know its a simple thing seeing how every single game and program on the internet has to do it so someone would have by now figured out a simple and effecient way to do it. Just because its simple doesn't mean I am obliged to instantly know how to do it. In theory my way would work, but apparently it makes the computer stop and wait for connections even tho it's a seperate thread which shouldn't effect the process of the rest of the program.
 
I just went through this thread of discussion. It's simply amazing!
 
im going to cry:( why doesnt my solution worrrrrrrk?

void thrClientsThread( SocketObject *sm )
{
// Loop until we are told to quit
while( 1 )
{
ServerSocketObject.Listen();
WaitForSingleObject( g_hCreditMutex, INFINITE );
clients += 1;
ServerSocketObject.Accept( sm[ clients ] );
cout << &quot;<Server> Client Connected to Port &quot; << 6000 << &quot;; ID: &quot; << clients << endl;
ReleaseMutex( g_hCreditMutex );
}
}

/*Socket object is defined above in a previous post. Listen just makes the computer listen for a connection, it continues after there is a connection. But for some reason when it's in a thread it still makes the rest of the program freezor:( */
 
>> im going to cry:(

That won't help... don't waste your time. My guess is that your missing something fundamental in mult-threaded development. That was why i suggested simplifying the problem you are trying to understand.

I have been doing multi-threaded socket application development for almost 10 years and i have never seen a server socket accept call being synchronized before. If you are not familiar with using synchronization objects you can easily realize the symptoms you describe.

-pete

 
Ok I found the problem I think. My method of accepting users was fine, but my use of the mutex wasn't. Here it is;p
declaration
HANDLE g_hCreditMutex;

while( 1 )
{
ServerSocketObject.Listen();
WaitForSingleObject( g_hCreditMutex, INFINITE );
clients += 1;
ServerSocketObject.Accept( ClientSocketObject[ clients ] );
cout << &quot;<Server> Client Connected to Port &quot; << 6000 << &quot;; ID: &quot; << clients << endl;
ReleaseMutex( g_hCreditMutex );
}
//Thats in a thread

while (1)
{
while( !_kbhit() )
{
WaitForSingleObject( g_hCreditMutex, INFINITE );
// Check for incomming data
cout << &quot;sdf&quot;;
for ( int a = 0; a <= clients; ++a )
{
iBytesReceived = ClientSocketObject[a].vGetPacket(szPacketBuffer);
if( iBytesReceived > 0 )
{
// Copy the received data into the chat packet
memcpy(&ChatPacket,szPacketBuffer,sizeof(ChatPacket));
strcpy(DataPacket,ChatPacket.szChatMessage);
cout << endl << &quot;<Client> &quot; << DataPacket << endl;
printf(&quot;<Server> &quot;);
}
}
ReleaseMutex( g_hCreditMutex );
}
}
Thats where its used in the main program. Any help? To me that looks fine.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top