Ok, I've downloaded a few applications that demonstrate the basics in creating connections and sending and reciving data...

The question is (and although I'm not up to the "networking part" I'm asking in advance for help): How do you write a multiple client server? Or more simply:

Does anyone have an example of a multiple client server (the real basics), where you can send some command and have the server respond back (over 1 character both sending and recieving)

ie.
You logged on to 197.43.234.32
(This server allows multiple connections)
> time
the current time is: 99:99:99

I'm struggling with this concept of multi user and being able to process string through a "read" message from telnet

Any help in this area would be appreciated

Sliver
Posted on 2002-02-27 10:34:42 by Sliver
The best method in my opinion is to use a separate thread for every client, in combination with the correct synchronization.
Have one socket listening for incomming connections. As soon as a client connects, create a new thread and pass the socket handle (you get with accept) to it. Then let the thread handle all communication.
For the synchronization (event notification etc) there are several ways. One is using blocking sockets inside the thread but I personally don't like this as you loose control over the thread when it's blocking.
In my webserver I use WSAEventSelect to let winsock set an event object when a network event occurs. I have two events actually, one for the network events, and one for internal communication.
You can also try to create your own sort of message queue inside the thread (I used that in a very early version of my server), and then pass FD_* messages to the thread, but events are easier to use.

Thomas
Posted on 2002-02-27 10:47:59 by Thomas
About the string parsing:
A common mistake most beginners in winsock make is to assume data is received exactly the way they need it (for example, when the client sends 100 byte in one send call, the server doesn't necessarily receive those 100 bytes in one recv).
Especially with telnet sessions, where telnet sends the characters while the user is typing, it's most likely that you receive your string char by char.
Make sure you got the receive notification and waiting for data right, don't just loop recv hoping data arrives, instead wait for the right notification that tells you data is waiting for you.
Then you need a buffer for the command. Keep adding the data you receive to this buffer. Watch out for buffer overflow, or your program can have a serious security bug.
Each time you've added data to the buffer, scan through it looking for CRLF (or CR or LF :( ), if you found one you have a complete line in your buffer. Process it, do something with it and when you're done, remove this line from the buffer, shifting all data behind it (possibly from the next command) back to the buffer base, freeing the rest of your buffer space.

Thomas
Posted on 2002-02-27 11:03:17 by Thomas
That is part of my problem...
I know that sometimes the telnet works by sending 1 character at a time... some what if someone is typing the word "time" and another person types it at the same instance?

ie.
Person 1:
tim
Person 2"
time (return)

I'm not even sure how the server is suppose to handle that :(

I'm usually a guy who learns from example :( Thanks Thomas (you help is always appreciated)... and anyone else too who may have examples or just ideas...

Sliver

ps. In the game programming forum is the "text based game" that I want to try and make networked... if that helps any
Posted on 2002-02-27 11:16:53 by Sliver
Well person 1 and person 2 both have different sockets wichh you can handle in differnet threads and allocate seperate buffers for so they don't interfear with each other.
Posted on 2002-02-27 11:28:31 by Quantum
Quantum is right, every client has it's own socket and his own thread, so everything is nicely seperated. Just make sure that every thread has it's own data set (local vars or dynamically allocated memory) so they won't interfere which each other. Unless of couse the data that has to be global, for example if you want users to meet each other in a room, they all use the same room data, if one user picks up an item, the others shoudn't be able to after that.

Thomas
Posted on 2002-02-27 11:56:53 by Thomas
Maybe I'm in over my head...

Can either of you suggest a place to learn to use threads within the context of my desired goal of making a multi cliented server?

Sliver
Posted on 2002-02-27 12:03:46 by Sliver

Quantum is right, every client has it's own socket and his own thread, so everything is nicely seperated. Just make sure that every thread has it's own data set (local vars or dynamically allocated memory) so they won't interfere which each other. Unless of couse the data that has to be global, for example if you want users to meet each other in a room, they all use the same room data, if one user picks up an item, the others shoudn't be able to after that.


Hi thomas,
well i've to say i'm really interested in this kinda game project
My advice about this probl is to create the game this way:
u've to have a single server with all data about game
it means whats inside rooms, personal data of each character, everything and clients r only "stupid" clients they only have to provide a user friendly interface to communicate with the user
and they'll send all the user actions to the server that will process them and notify the clients with the results
The server should be designed this way:
one main game engine as a single thread which will be the only to perfrom operations on the game datas
and many threads as the clients connected to the server
Every server side thread listening to a client should notify the only server thread about the user action with messages
this way the only work the only server thread has to do is
to handle messages they will be sent to its own thread
So u've to use PostThreadMessage() to communicate and the GetMessage() to take messages

See ya
NikDH
Posted on 2002-02-27 12:09:52 by NikDH

Maybe I'm in over my head...

Can either of you suggest a place to learn to use threads within the context of my desired goal of making a multi cliented server?


Hi sliver,
if u can code with the windows gui so u r familiar with concepts like window procedure, messages handling,... u're already done
Its the best example of thread communication under windows

See ya
NikDH
Posted on 2002-02-27 12:12:09 by NikDH
NikDH: That's a good way to do it, one thing I want to add is that you should take care of the synchronization of the main thread (that performs all the operations), i.e. make sure threads cannot do the same thing at the same time, for example you wouldn't want two users being able to simultaniously pick up an item :).
Like NikDH said, you're client are 'stupid' clients, which isn't hard to understand as they are telnet programs...

Sliver: working with threads isn't hard. Iczelion has a tutorial about them. Basically you have one procedure (with one required parameter). When you pass this procedure to CreateThread, a seperate thread is setup, running your procedure. Just think of that procedure running simultaniously for all clients.. It isn't hard.

Thomas
Posted on 2002-02-27 12:20:25 by Thomas
I think I may need to take a step back...

I think I'll search the web for some information on "threads", "client/server applications", "multi socketed connections"... Is that it? I think so...

The problem is I don't know how to even start a multi socketed server that even *has* a main thread?

I just wish there was an example of this somewhere on this board... :( (like the time example)... Oh, well I'll look first and then come back and reread everyones posts...

Maybe a better inital question would have been:
"how do you create a program so that a few people can logon (via telnet) and check the time or whatever -- and have the server handle all the clients at one time. Or possible an example..."

Thanks for all the help so far... I have a long way to go :)

Sliver
Posted on 2002-02-27 12:35:05 by Sliver
You can also use a mutex to protect your global data. Like Thomas said, you don't want two people picking up an object at the same time so lock all thread execution at the point someone attempts to pick up the object to ensure no conflict. You can think of a mutex like a token on a token ring network. Only the nic that has the token can transmit data on the network. If all you do is lock the mutex, change the variable, then unlock it, I don't think the other clients would be adversely affected with lag.
Posted on 2002-02-27 13:05:11 by rdaneel
Sorry I don't have such an example nor the time to write one for you..
Here's the pseudo code:

- Initalize winsock, create socket, set socket listening and set window message to receive notifications
- on FD_ACCEPT, call accept to accept the connection. It returns a socket handle. You need a table that associates threads with sockets (say an interleaved table: socket handle, thread, next socket handle, next thread, and so on). Create a new thread for your socket, put the socket handle and threadID in the table, and set a new custom window message (say WM_CLIENTSOCKET) for the new socket. Let it notify on FD_CLOSE, FD_READ and FD_WRITE messages. You can use the same message for all client sockets!
- In the WM_CLIENTSOCKET handler, you will receive FD_CLOSE, FD_READ and FD_WRITE notifications. However these are for all clients. So you'll have to find out for which socket it was meant. The socket handle is in wParam. Look up this socket handle in your socket-thread table (see above) to find out the threadID of the thread you created for that specific socket.
- Call PostThreadMessage to send a message to that thread (using it's ID). You can create any message you like for this, just define some equates for them (say TM_READ, TM_CLOSE, TM_WRITE ).
- In the procedure you used to set up the thread, you should have a message loop (GetMessage etc), just like in your WinMain.
For example:

...
LOCAL threadMsg:MSG
...
.WHILE TRUE
invoke GetMessage, addr threadMsg,0,0,0
.BREAK .IF (!eax) ; eax is zero on WM_QUIT, send that message to stop the thread!
...
mov ecx, MSG.message
.IF ecx==TM_READ
... put your read data handling code here...
.ELSEIF ecx==TM_CLOSE
...on closed connection....
.ELSEIF ecx==TM_WRITE
...on 'ready to write' notification...
.ENDIF
.....

Hope this helps,

Thomas
Posted on 2002-02-27 13:05:23 by Thomas
the per-client threads should only send/receive data, they shouldn't
perform any game actions (like NikDH says). Input from clients should
be queued, not directly acted on (otherwise clients with fast linespeeds
and low latency will have an unfair advantage over the rest).

The main game thread will do its actions in "heartbeats", so you get
a consistant game speed. Also, in each heartbeat, it should randomize
the order of client processing, so all clients will eg have a fair chance
of picking up an object, instead of having the first connected client
being favored.

This way there shouldn't be synchronization problems with accessing
game structures - you'll need some critical sections around the
client command queues though.
Posted on 2002-02-27 13:19:00 by f0dder
The algo. for the random client processing sounds like the hardest part. Fodder, would you create one command queue and then randomly place client commands from each thread in the main queue, or create a seperate queue for each thread and access each queue randomly.
Posted on 2002-02-27 14:37:42 by rdaneel
I'd probably have one queue for each client.
Posted on 2002-02-27 14:42:22 by f0dder

The main game thread will do its actions in "heartbeats", so you get
a consistant game speed. Also, in each heartbeat, it should randomize
the order of client processing, so all clients will eg have a fair chance
of picking up an object, instead of having the first connected client
being favored.

This way there shouldn't be synchronization problems with accessing
game structures - you'll need some critical sections around the
client command queues though.


Hi f0dder,
well i like this idea of having one main thread performing all actions upon data in heartbeats to avoid sync problems
but i dont agree so much about random clients execution order
Perhaps i'll suggest this way:
when a character tries to pick up an object from the ground
(so hes performing an operation where other ppl should be involved coz in the same time some other characters should try to pick up the object) u should set sorta timeout 4 performing the operation (of coz little time so its not nagging) in the meanwhile should arrive others msgs notification of other guys trying
to pick up the same object so we've n guys trying to pick up the same object at almost the same time
When timeout it reached we've to process the operation and so we've to give the object to the guys that have tried to pick it up
We should check some abilities of the characters such as speed
and luck and so on and so we decide who has succeded in the operation
Well i think this idea of setting a timeout 4 an operation that should involve many ppl is quite near to reality
In the real world the action of picking up a thing takes some seconds and in the meanwhile should come someone stronger
or faster that should break our balls

See ya
NikDH
Posted on 2002-02-28 06:23:09 by NikDH
Sliver: for more winsock related information, have a look at the winsock faq here: http://tangentsoft.net/wskfaq/.
There are several examples (in C), also with multithreading.

Thomas
Posted on 2002-02-28 15:26:26 by Thomas
Hola,
I've used Qweerdy idea of a simple telnet server to get my network idea back on track... (thanks Qweerdy -- the work you've done is perfect for this test bed)

So I've scrapped "part of"my original network set-up and used a modified version...

The problem is I'm now at the sync point...

So I was hoping someone could run the program and

just use
127.0.0.1 port 75

and tell me how can I form a set up to sync the players and an possible even allow for communication between thread (ie. players talking to each other -- who are in the same room)

All help is needed and appreciated,
Sliver
Posted on 2002-04-15 23:52:49 by Sliver
I tested your program but it ignores everything I type. I've traced your code and it seems that your recv (the one with MSG_PEEK) keeps on receiving the same char (the first char I tyed), everytime it's called.

I think your method of getting a full line won't work this way, as it probably won't fill the internal buffer with more chars until you've really received the first.

A better method is to receive data when it arrives, and add it to a buffer until the buffer contains a newline char. When this is the case, process the buffer upto the newline char and after processing, shift the rest of it (after the newline) to the start of the buffer.

Also, don't use sleep to wait for data. select is much better as it waits until a network event happens. But the asynchronous functions (WSAAsyncSelect or better, WSAEventSelect) are faster and allow more control (e.g. the thread doesn't hang when waiting for something).

Thomas
Posted on 2002-04-16 11:19:20 by Thomas