• Advertisement
Sign in to follow this  

Thread Design

This topic is 4408 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello! First of all, I'm new in this forum and I'm not English, so there might be many mistakes. Please tell me then, so i can practise a little bit. I've got a question about the design of my threads, where I send and recv. I am programming a chat. On the server, every client has a thread and the clients have only one thread, where they send and recv. So that's my question: I always send and then recv. If someone wanna say, that there's nothing to do, he sends an 0 byte. If he has something to say, he send something non 0. So there is every time traffic, although the computers don't wanna say something. I think it might be a solution, if i create two sockets and for every connection 2 threads. One thread for send and one for recv. But is that the right solution? I hope you had understood my problem. mfg. (<- german word for "greetings" or something like this)

Share this post


Link to post
Share on other sites
Advertisement
Quote:
. On the server, every client has a thread


That is almost never the right solution.

There are a couple of other threads on this board right now about how to use select() instead of threads, and how to use select() to be prepared to handle both user input, incoming chat data, and outgoing chat data. I suggest you look into them. In general, you will not need threads at all for a chat application.

Etwork is a small network messaging library that comes with a sample chat client and chat server (using Win32 GUI). You may get something out of studying that code (it's open source; MIT license).

Share this post


Link to post
Share on other sites
Okay, thank you very much!

I have read a tutorial and now i have another question:
If I use select() on both sides, when does select() know, that i can send data, because on the other side, im waiting with recv until there is something sent. You understand what i wanna say?

mfg.

Share this post


Link to post
Share on other sites
The networking infrastructure will buffer data until you ask for it. Thus, the sending side doesn't need to know whether the remote side is currently listening -- it can just send, and when the remote calls recv(), the data will get there.

Share this post


Link to post
Share on other sites
Although threads aren't needed for situation, i think you should still experiment with threads. They are wierd creatures with the ability to expand simple programs into... 2 simple programs :) (or more). But seriously, threads aren't always the best way to go, but they can make your programming experience a bit more fun and flexible. Here is how a thread would be created..

Thread prototype:
Quote:
// Thead prototype to receive data
DWORD WINAPI RecvThreadProc(LPVOID lpParameter);


Thread implementation:
Quote:
DWORD WINAPI RecvThreadProc(LPVOID lpParameter)
{
while (1)
{
int bytesRecv;
char recvbuf[512];
bytesRecv = recv( m_socket, recvbuf, 512, 0 );
if ( bytesRecv == -1 )
{
// The connection was closed. Deal with it,
// send the user a message box or whatever.
closesocket(m_socket);
break;
}

if (!bytesRecv == 0 ||
(bytesRecv == SOCKET_ERROR &&
WSAGetLastError()== WSAECONNRESET ))
{
recvbuf[strlen(recvbuf)] = '\0'; // Add the NULL terminator
// Do as you please with the message. Presumably
// sending it to the screen.
}
}
}


To execute the thread:
Quote:

HANDLE hThread;
DWORD dwThread;

hThread = CreateThread(0,0,(LPTHREAD_START_ROUTINE)
RecvThreadProc, 0, 0, &dwThread);

Share this post


Link to post
Share on other sites
You should not need to use threads for a simple chat server, and even if you do decide to use them, a thread per client is a waste of resources and adds complexity that is not useful.

Also, be aware that threads are handled in different ways under linux and windows. If you are targetting both for your network system, you will need to either use a third party library, or roll your own thread wrapper. This can be a fair amount of work to implement and test properly. Don't get into the habit of placing platform specific code in #defines in general code.


Share this post


Link to post
Share on other sites
Quote:
Quote:
On the server, every client has a thread


That is almost never the right solution.


Thanks for the tip. I've just started a mmorpg and I'm currently using a thread per client on the server. The threads are responsible only for filling the global command queue (global in nature, not scope). Why is it so bad to create threads per socket as opposed to non-blocking sockets in a single thread? It seems like it would be more expensive to keep polling every socket in one thread, especially when a lot of the time, many of the clients aren't sending anything.

I'm using Java at the moment. I've found it quite easy to put each client in its own thread and use a BufferedReader and PrintStream for input and output respectively (just using strings at the moment). I haven't got the command queing code yet, but I figure I'll just use a ConcurrentLinkedQueue and all will be good.

[Edited by - SteveTaylor on January 21, 2006 5:15:28 AM]

Share this post


Link to post
Share on other sites
Creating a thread per client has a significant overhead. There's also a per-socket overhead - creating / releasing sockets is expensive.

If using TCP, a common solution is to use non-blocking sockets and poll them using select() from within a thread, and have a separate listening thread, with a single socket. Select will return the sockets that have pending data on them, from the entire set. It's very fast.




Share this post


Link to post
Share on other sites
Thanks for your answers!
I will practise a little bit with select().

Yes, you're right, it's important for me that i can use my source on every os. At the moment i'm working with boost::thread, but i will try to use select(). If I have more questions i will ask you.

mfg.

Share this post


Link to post
Share on other sites
Ok - if you're doing cross platform stuff, be sure to check if there's any differences between the windows and linux socket functions - (I've not touched Java in over 10 years) in C/C++ there's the ioctl() (linux) and socketioctl() (windows) disparity, and some differences in #defined names for return values, and the error checking differs.

Edit: Sorry got confused as to who I was replying to. :-)

Share this post


Link to post
Share on other sites
Here's a problem with non-blocking sockets. Suppose the server has a list of clients. It iterates through the list, retrieving any data from the sockets, and building commands from the data where possible. The server then uses those commands to execute all the turns in the next timeslice. The problem is that as the list of clients grows, the newest clients in the list have their turns executed closer to the next timeslice. This means that the longer a player is logged in, the more laggy his or her exprience becomes. However if threads are used, the time between command sending and executing is fair and nondeterministic.

Share this post


Link to post
Share on other sites
The trick here is to manage your server update and message priorities properly. That said, iteration is the least of your worries. You won't get a sufficient number of TCP sockets for it to be a major problem.

I use a structure similar to this:
[queue - packets out] (dissembled messages)
[rbTree - packets in] (for assembling messages)
[vector - clients [queue - messages In] [queue - messages Out]] (clients and what goes where)
[thread - listener] (make new clients)
[thread - network IO] (send / receive and prioritize packets, deal with keep-alive, cull orphan packets)
[thread - server] (game logic - respond to messages with messages)

The three threads are fairly simple -

The listener simply dumps clients to the network IO thread once they're connected. This thread isn't required for UDP.

The network IO thread ONLY deals with IO of messages, and receives and sends packets for a certain amount of time per cycle, if the queues are not empty. Complete messages received are passed to the appropriate client's queue. Messages are despatched by priority. Once despatched to the network thread, they are the responsibility of that thread - packets are 'skimmed', ie. a packet is sent from each queue until empty. Incoming messages are again prioritized, and if a 'replacement' message is received, the original is destroyed. Further packets for that message will be orphaned and eventually culled.

The server thread iterates clients looking for high priority messages first. These are dealt with before lower priority messages. All high priority messages are dealt with, without timeout. Lower priority messages are dealt with with a timeout.

With the message priority system, lag can be limited to some extent - chat might lag, but combat will not lag so much, for example.

Share this post


Link to post
Share on other sites
I think for now I'll stick with multithreading for two reasons:

1. It's easy to implement.
2. All the client threads do is fill a command queue from the clients' input. The only time these threads lock out the gameplay thread is when they add commands to the queue, which would take a very minimal amount of time.

Of course, I think it would be absolutely crazy to have client threads actually perform gameplay. Absolute madness.

Share this post


Link to post
Share on other sites
I have still a question: Should i use one Socket which recv after send and the he sends again and then recv. Or should I user 2 sockets, one for recv and one for send?

mfg.

Share this post


Link to post
Share on other sites
I'd use a single socket for most purposes. Multi-processor platforms can leverage some gains by having several sockets running in separate threads, but the network driver is often the bottleneck in these cases.

Edit: That said, gains are usually found in multiple-receiving socket cases, where the sources differ- for example a separate set of sockets (and/or protocols) may be used in a game server for accessing other servers rather than clients, which might use a single UDP socket.

Be aware that TCP is a 'connected' protocol, and there is an overhead in making / breaking connections (over and above the socket creation overhead), so in the situations where you have many clients communicating with a limited socket pool, you should take care in selecting which sockets to cycle out.

Share this post


Link to post
Share on other sites
Quote:
Original post by SteveTaylor
I'm using Java at the moment. I've found it quite easy to put each client in its own thread and use a BufferedReader and PrintStream for input and output respectively (just using strings at the moment). I haven't got the command queing code yet, but I figure I'll just use a ConcurrentLinkedQueue and all will be good.


This may be easy but it's not scalable. For an application that has few clients it's no big deal. But as the client numbers start rising you run into difficulties. Unfortunately, using the java.net API there is no other option as the sockets cannot be set to nonblocking mode. Many thread-per-client Java applications have been released into the wild. Sun added NIO (new IO) in 1.4 to address this issue. NIO allows sockets to be set to nonblocking mode and is more efficient than the java.net API when handling large numbers of clients. It's also scalable, and allows you to condense your network code into a single thread if you want.

[Edited by - Aldacron on January 22, 2006 6:37:13 PM]

Share this post


Link to post
Share on other sites
Yeah I looked at the java.nio stuff briefly. I'll probably do a conversion later. I'm keeping the networking code out of the gameplay code. The incoming commands just fill a queue. The gameplay code consumes items in the queue. Hopefully that level of separation will facilitate a conversion to non-blocking I/O if it becomes necessary.

I thought java.net.Socket could be used in a non-blocking fasion anyway: Suppose you get an InputStream from a Socket and call it in. A call to in.available() will return the number of bytes that can be read without blocking. So what's the deal with all the java.nio stuff then?

Share this post


Link to post
Share on other sites
Quote:
Original post by SteveTaylorI thought java.net.Socket could be used in a non-blocking fasion anyway: Suppose you get an InputStream from a Socket and call it in. A call to in.available() will return the number of bytes that can be read without blocking.


Yes, and then simply calling 3 arg version of read you can pull out exactly that number of bytes, yes? This is highly inefficient. The problem is that the socket itself can not be configured to be nonblocking in through the java.net API. This means that in order to simulate nonblocking IO you must repeatedly poll each socket (through the associated input stream) to see if any data is available to read immediately. For a handful of clients this won't hurt too badly. But as the number of clients increases you'll start to feel the pain. But that's not all. The read operation can still block. Just because in.available says you can read X bytes without blocking does not mean you won't block on read. There are no guarantees.

Quote:
So what's the deal with all the java.nio stuff then?


It allows the programmer to make use of nonblocking sockets via a select mechanism. Rather than the programmer polling sockets for data, the operating system does at in a much more efficient manner. Once per frame (or whenever you're ready to process data) you ask the selector to look for any sockets that have input pending, then read the ones that do. It reduces the amount of time you spend looping over sockets. At a conceptual level, the networking API is doing the same thing you suggested originally - polling sockets for pending data. The reason it can do it more efficiently than you is because you don't have access to the innards of the system.

Furthermore, Java is free to use the most efficient method possible on the current operating system. On Windows, it might be through the select API, or it might be using AsyncSockets, or maybe IO Completion Ports (the most scalable networking API on Windows systems). The point is, you don't have to worry about it. By using java.net and polling InputStream.available, you take away Java's opportunity to use the best avaialble while at the same time throwing efficiency out of the window.

NIO also introduces ByteBuffers. ByteBuffers can be allocated in JVM space, in which case they are essentially wrappers for Java byte arrays. But more importantly, ByteBuffers can be allocated outside of the JVM heap in native memory. SocketChannels allow you to send and recieve data through ByteBuffers. Natively allocated BBs are more efficient than those allocated in the JVM heap.

The benefits of NIO are big. It allows you to write efficient, highly scalable servers in Java. This was not possible before without dropping down to native code and JNI yourself. Sun is currently building a game server that can run multiple virtual worlds with thousands and thousands of players across server clusters. It's imaginatively named the Sun Game Server. It's a massive project. There's a "significant announcement" (to quote one of the SGS developers) coming at GDC this year. And I hear they have a couple of game developer shops on board to do some stuff already and are talking with more. That's getting off topic though. All I wanted to say, really, is that SGS would not have been possible through the java.net and java.io packages alone.

Share this post


Link to post
Share on other sites
I have a question which might be quick answered so i didn't started a new topic.

I'm looking for a tutorial or a code expample how to use select() and connect(). I heard that i have to use nonblocking sockets but i don't know anything about that.

mfg.

Share this post


Link to post
Share on other sites
search google for "Beej's networking tutorial". There is a table of contents on his site that you can look through and use as a reference whenever you want to see how a certain function works. I used his select() guide to help me. Took me about 2 hours to get comfortable with them, playing around and then created my own async server.

Share this post


Link to post
Share on other sites
Quote:
Original post by cherryhouse
search google for "Beej's networking tutorial". There is a table of contents on his site that you can look through and use as a reference whenever you want to see how a certain function works. I used his select() guide to help me. Took me about 2 hours to get comfortable with them, playing around and then created my own async server.


Thanks! I've found the tutorial and read a little bit.
So i have to use nonblocking sockets if i wanna use connect() and select()?? Or is there another possibility?

Share this post


Link to post
Share on other sites
Quote:
Original post by SteveTaylor
Not if you want high performance.


And how i can make connect() and select() work with blocking sockets?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement