Skip to main content
GameDev.net gamedev.net
🔒 Locked

Are sockets full duplex?

Started by WebsiteWill Jul 14, 2003 at 10:42 PM 30 replies 8.8k views
Original Post
WebsiteWill
WebsiteWill
What I mean is, if I have only one socket, can I both send and recieve on it at the same time? I''m thinking not and am planning to create an incoming socket and an outgoing socket so that i can have separate threads handle each one. Server might have multiples of both but the client will only need one of each as I see it. Server might not need more than one either. Depends on just how much info can be read/sent on a single socket. Though i''m betting that MMO amounts of traffic will be too much for just a single socket to handle. Thanks, Webby
Gizz
Gizz
You can send and receive on the same connected socket but, as you said, you might want to have one for each.
easlern
easlern
I can''t comment on the MMO part, but sockets are read/write for both client and server.
zfod
zfod

Sockets are full-duplex depending on your definition of terms, of course.

Also, the practicality of such a thing depends on the I/O model that you use. If you do some form of multiplexing, then you can get around the blocking nature of sockets, etc.


.zfod
Max_Payne
Max_Payne
It''s quite a waste to have two sockets... Sockets are byte streams, just like files, you can read and write at the same time.

Plus, a sending thread isn''t such a good idea, because of the big overhead of starting a thread when you want to send... You might just immediatly send.... Since that doesn''t block.

"Though i''m betting that MMO amounts of traffic will be too much for just a single socket to handle."

What difference does it make, wether you use one or two sockets? If you use two, thats just one more socket for the OS to take care of... And things work the same, whatever socket you send/receive on. In the end, the only thing that makes a difference is how efficient your hardware and operating system are.

Looking for a serious game project?
www.xgameproject.com
zfod
zfod
Hmm,

Well, web browsers certainly make use of threads making socket connections to send data.

Like anything, it depends on what you''re doing that will make or break what sort of model you want to use.

Threads on the server-side? Sure, if you can deal with the synchronization issues, thread-safe calls, etc. Threading is usually much better than invoking another heavy process.. but it depends on what thread library you''re using as well as the OS.

Using a server-side thread pool has worked quite well for me, in the regard of the general nature of this forum topic.

YMMV of course,

.zfod

cbenoi1
cbenoi1
> if I have only one socket, can I both send and recieve on it at the same time?

Yes. Make sure you have Winsock 2 or better otherwise ''select()'' will not work properly if you have separate threads for read and write.

> Though i''m betting that MMO amounts of traffic will be
> too much for just a single socket to handle.

A socket is just an OS abstraction; doubling the number of sockets won''t double your network throughput (nor will 100 sockets suddently make your network card''s performance jump from 10Mbs to 1000Mbs). Though you may want to separate the login socket from the data exchange socket for security reasons.

-cb
WebsiteWill
WebsiteWill
That makes sense.
I was thinking that it might work just like a file. For example, if I have file A and I try to write to the file and at the same time I try to read from the file then the 2 operations would potentially overlap and while the write would probably work just fine, there''s no guarantee that the data I read would be correct. It could be part old data and part new data from the present write operation. That is, unless the OS controls simultaneous operations on a file (puts them in sequence through file locking or some other same memory procedure).

Thanks though.
The client shall have only 1 socket. Still going to create a thread for recvs and a threads for sends because I plan to just let them block until something is there. I think that would by far be the fastest model for the client.

Still haven''t decided for the server yet though a single socket again seems like the appropriate choice since it''s all handled by the hardware anyway.

For that I am thinking of a single thread to recieve packets from the socket and simply store them in my own buffer where I handle them later. Then multiple threads to actually handle to packets from my buffers (probably a single thread per unique packet type so that the threads won''t often have to wait for each other to finish thereby limiting the need for mutexes and thread synchrinization). Probably something like one thread to handle chat packets, one to handle player battle commands, etc.

Sending packets back to the clients I''m not so sure. I''d need a way to send to as many clients as possibe, as fast as possible so I''d probably be better off there with multiple threads again. Possibly a send thread for the different types of packets needing to be sent.

Any thoughts?

Thanks, Webby
fingh
fingh
quote:
Well, web browsers certainly make use of threads making socket connections to send data.


And web surfing, as well all know, is dog-ass slow... pardon the expression. High performance is neither required, nor expected. An MMO would be an entirely different story.

quote:
If you do some form of multiplexing, then you can get around the blocking nature of sockets, etc.


Or you can use a non-blocking socket (probably best since he''s talking about using UDP).

quote:
Threading is usually much better than invoking another heavy process..

Yes, in most systems context switching a process is more expensive than context switching threads. But what if the process is running on a completely different system? The beauty of using multiple processes instead of spinning off threads is scalability and relocatability.

quote:
For example, if I have file A and I try to write to the file and at the same time I try to read from the file then the 2 operations would potentially overlap and while the write would probably work just fine, there''s no guarantee that the data I read would be correct.

Sockets have two seperate buffers, one for send, one for receive. They are completely independent at the application level. You can increase the size of those buffers as well. There is no need to use multiple UDP sockets on either client or server.

quote:
Sending packets back to the clients I''m not so sure. I''d need a way to send to as many clients as possibe, as fast as possible so I''d probably be better off there with multiple threads again. Possibly a send thread for the different types of packets needing to be sent.

You are probably not going to get the kind of performance increases you expect. Keep in mind that all of those threads don''t really run at the same time... even with additional CPUs you will never see a linear increase in performance.

quote:
Plus, a sending thread isn''t such a good idea, because of the big overhead of starting a thread when you want to send... You might just immediatly send.... Since that doesn''t block.


I don''t think he means start a new thread everytime he wants to call sendto(). I think he means having a persistent thread running to handle sends. But I agree, this isn''t necessary, whether it''s a turn-based RPG or a MMO.

The concerns about the amount of data generated in a MMO are certainly valid, and it''s a very real issue that has been solved commercially in a number of ways. Compromising a solid design by spinning off tons of threads in your network code is not necessary to achieve high data throughput.
WebsiteWill
WebsiteWill
OK. Not talking about tons of threads :0
Here is a base design that I have in mind as of right now.

ThreadA: This thread is passed a function that does nothing but continuously reads the socket for an incoming packet. When a packet arrives then this thread/function reads in the packet and stores it onto a serverside data structure.

ThreadB: This thread pops a packet from the top of my serverside packet holder and processes it. By processing it I mean that it will first determine what kind of packet it is and then send that packet on the the actual thread that handles that kind of packet.

ThreadC: This thread executes a function that simply waits for a packet to be sent. When received, the thread will send the packet through the socket to the other side. It does nothing more than wait for a packet and then send it when it gets one.

ThreadsD-XXX: These will handle packet types. Not individual packet types but more like one thread to handle all chat packets. One thread to handle all movement_request packets. One thread to handle all inventory_specific packets.
This gets broken down however far I feel necessary but probably not very deep.

Ideally, I want the threads to have as little data in common as possible. So a chat thread is fine because chatting won''t require the accessing on any game specific memory.

A movement thread will handle player positions and as such won''t worry about player inventories, battle messages, etc.

This is the kind of design I am working on ATM. I have coded nothing as of yet because I''m still working on design issues, like whether or not this will work. My reasons for using threads are multi-fold. 1) I am planning for quad processor machines minimum for the world servers so 4 threads minimum to utilize all processors. 2) The overall code structure seems well adapted to the use of threads or at least processes because in a MMO there are many concurrent things happening that are often not related at all. To me that just screams "THREAD ME" or "FORK ME"

You mention scalability and relocatability. My thoughts on this fall into some of the above. The way I am designing, if I can''t get a clear cut reason for a separate thread then I do not creat one. I have to have a specific goal that is both large enough and can process independently of all other operations to justify making a thread for it. Because of this design, if I later opt to move some of the logic to another computer (like AI for example) then it will be a simple thing to extract the code for the AI and work up another server specifically for it.

At this point I''m thinking of threads being more like objects that do their own complete thing. There is a word for functions that are too related in the processing that they do, I think it''s called cohesion? Or maybe coupling? Can''t remember but I know it''s a bad thing in a program.

So if I build around this OO point of view then everything should be OK with regards to relocatability and scalability.

All in all I can right now think of a use for at most 8 specific threads. I''m sure others may pop up but I am very much a tightwad when it comes to allowing for extra threads in my design simply because I like the KISS method. In this case however, threading just make more sense than not.

Thanks for all the great advice. Please keep poking holes in the weak spots because I''m sure there are many. I''m tightening the design up every day.

Webby
fingh
fingh
quote:
Original post by WebsiteWill
ThreadA: This thread is passed a function that does nothing but continuously reads the socket for an incoming packet. When a packet arrives then this thread/function reads in the packet and stores it onto a serverside data structure.

ThreadB: This thread pops a packet from the top of my serverside packet holder and processes it. By processing it I mean that it will first determine what kind of packet it is and then send that packet on the the actual thread that handles that kind of packet.

ThreadC: This thread executes a function that simply waits for a packet to be sent. When received, the thread will send the packet through the socket to the other side. It does nothing more than wait for a packet and then send it when it gets one.

ThreadsD-XXX: These will handle packet types. Not individual packet types but more like one thread to handle all chat packets. One thread to handle all movement_request packets. One thread to handle all inventory_specific packets.
This gets broken down however far I feel necessary but probably not very deep.


In one thread you recv(), lock queue, enqueue request, unlock queue. In another thread you lock queue, pop data off the queue, unlock queue, check the type, then lock another queue, queue data, unlock the second queue, and let it sit until sometime later for processing in yet another thread? Keep in mind that there will be context switches, and periods of time when your threads are waiting for their time slice to run. So this doesn''t necessarily happen in an immediate manner, even with multiple CPUs. I think this is overcomplicated to the extent that it will introduce more overhead than anything else.

ThreadsD-XXX: If you insist on using seperate threads for handling requests, I''d suggest just using a pool of generic worker threads rather than having a specific thread for each request type. That way all of the threads in the pool can spread the load a little better. example: imagine sitting in town where there is no combat, only tons of chat and tons of position updates. The thread handling combat requests is just sitting there while the chat thread appears to be lagging, and the location updates are making the client ''pop'' all over.

quote:
1) I am planning for quad processor machines minimum for the world servers so 4 threads minimum to utilize all processors.

Reality check. That is cost prohibitive to even companies like SOE and Blizzard. They use a larger number of budget Servers (EQ zone servers use single 500MHz systems IIRC). You might want ONE high-end server for your production database server, but you will not get funding for quad processors across the whole backend.

quote:
Please keep poking holes...
Please don''t take this as a flame, it''s just more of what you asked for... Good luck. And if you are a self-funding developer that just inherited a billion dollars or something crazy, then disregard my comments about quad systems.
zfod
zfod
Heh,

As you can see Will, there are many opinions and models to choose from. The trick is to do the work and see for yourself what works for your particular situation. This includes hardware capacity planning in relation to purchases, in addition to application code.


.zfod
WebsiteWill
WebsiteWill
A little uninformed on my end. I was under the assumption that games like EQ or DAoC were actually running multi-processor servers for their worlds. But heck, if a single processor machine can do EQ or DAoC then that means they will work just fine for me.
Considering that EQ came out in what 1999 when processors were I think in the PII 450 range and DAoC is a 2001(?) creation so probably around 1Ghz this gives me good hope. Considering no server purchases/leases will be made for years if ever then I''ll be dealing with quite nice computers. But realistically, if I can achieve even the quality of DAoC at some point in the future then I am pleased

Everything I am working on now is pretty much machine independant. The only dependence will be that, obviously, a faster machine will work even better. I''ll have to dig around and see if i can find any actual details about recent MMORPGs and the server hardware they are using. This would be really helpful. It does indeed make the design a lot more simple if working for a single processor machine. Thanks fingh, I simply wasn''t aware of that being the case. I might be reworking my design in totality. No harm done, that''s why they call it a "design phase"

Thanks,
Webby
zfod
zfod
Heh,

Like anything else it depends on how your application is designed.

To be general, in most cases a well-written single-threaded application will outdo a threaded application ( being very general here ).

However, like anything that is worth a shit, if your application and hardware is designed to exploit threads it can far exceed a single-threaded application. It all depends.

Just because EQ or DAOC does ''X'', doesn''t mean anything. Your application and architecture can have very different needs than the aforementioned products. Also, if you''re looking to do new things I wouldn''t just accept a mentioned paradigm on a forum for hobbyists, nor would I accept a company like SoE or Mythic''s way of doing things as gospel. Don''t assume all of the the best and brightest people in the world are designing MMOs, because they aren''t.

Give people the benefit of the doubt, but don''t act blindly.


.zfod
cbenoi1
cbenoi1
There is an interesting article to help you make a decision about what I/O strategy you can or should use in your case:

http://tangentsoft.net/wskfaq/articles/io-strategies.html

-cb

PS: Hi Todd, there should be a 'list of interesting links' in the forum FAQ and this one should be in this list. (I assume you have time on your hands now that the book is out to the publisher... )

[edited by - cbenoi1 on July 16, 2003 8:51:08 AM]
WebsiteWill
WebsiteWill
Got any websites like that aimed at Unix? According to that site, my options are limited to blocking sockets, non-blocking sockets and threads. Blocking sockets without threads is completely out of the question. Non-blocking sockets are a possibility. Threads according to that site and the book "Unix Network Programming" are the best way to go.

I do see your issues with my design as I presented it. Thread locking a queue to put in a packet. Another thread waits to lock the queue to insert the packet onto the queue.

But, since this is a queue, FIFO, would it be possible to have a thread push a packet onto the queue without having to lock the entire queue? And the other side would be able to read from the queue without locking it also. I can use a simple counter like if (queue.size > 1) then pop. That way I won''t pop the queue unless I know there are at least 2 so that the two threads won''t be using the same memory at the same time.

The sending the handling threads don''t use the queue at all. Only the accessing thread and it then sends the packet directly to the necessary thread for processing so no locking is needed there.

The sending thread simply recieves the packet to send and sends it. I''m using a thread here because the call to send might not happen immediately. I probably won''t need a thread for this in the end but I''m still working with it.

All in all, the number of threads will probably be fewer than 10 and will each encompass a specific task that in general won''t affect the flow of the rest of the program. This is the method that I see as providing the smoothest IO possible which is what the servers will need.

One design alternative would be to single thread the packet handling with the main processing thread.
So I''d have one thread simply blocking on recvfrom() until it gets a packet. Once a packet is received then it adds it to the back of the packet queue and goes back to blocking on recvfrom()
The main processing thread can be a single thread that does all game logic.
ComputeAI
DetermineCollissionsAsNecessary
ReadInputFromQueue
ProcessInputPacket
DoOutput
etc

So that would narrow it down to 3 threads. One receiving, one processing everything like a single threaded program would and one sending.

This might be a more efficient method as I can certainly see hosting on dual processor machines. Quads and Octets may be out of my range but surely not duals hehe But even on a single processor machine, this model would pretty much work the same because if my theory about the queue is correct, there will be no locking to be done at all on this one.

Thoughts?
Very helpful website BTW.

Webby
cbenoi1
cbenoi1
> I can use a simple counter

You can protect the ''send'' queue with a pair of semaphores. One counts the number of outstanding message the ''send'' thread need to process making it block when there is nothing to process. The other one counts the number of bytes being queued up and blocks any thread that queues a request that exceeds a preset limit (say 4Mb); otherwise you risk having a queue overrun during a network bolus and things get accumulated to the point of chewing up swap space and make your server fall over.

-cb
fingh
fingh
quote:
Just because EQ or DAOC does ''X'', doesn''t mean anything. Your application and architecture can have very different needs than the aforementioned products.

Well, I mostly agree with you. There''s one thing that is missing from the above discussion, and that is questions of design validation. Those of us who have played either of the hit games mentioned knows that despite the flaws the games have in actual gameplay, technically, THEY WORK, and both of them work pretty darn well. Experience is a wonderful thing, never discount it. Nor would I blanketly reject an idea that is ''new'' (see below).

quote:
Also, if you''re looking to do new things I wouldn''t just accept a mentioned paradigm on a forum for hobbyists, nor would I accept a company like SoE or Mythic''s way of doing things as gospel. Don''t assume all of the the best and brightest people in the world are designing MMOs, because they aren''t.


zfod, keep in mind that although this forum consists of mostly ''hobbyists'', there are professional developers (games and otherwise) that frequently take part in discussions here, including people from the aforementioned companies. Does that mean that their word is gospel? Uh, no But usually getting something to work well includes going through several iterations of things that -don''t- work well (which brings us back to never discounting the experiences of those that have gone before us).

quote:
I''ll have to dig around and see if i can find any actual details about recent MMORPGs and the server hardware they are using.

Webby, you probably won''t find much info about the technical specs of commercial MMOs (maybe some middleware though!). The only thing I''ve seen published is the fact that DAoC uses dual CPU servers... good luck at any rate.
WebsiteWill
WebsiteWill
cb

You mention a queue overrun. Do you mean what would happen if say, messages were coming into the queue faster than they are being processed?

If this is the case then I can set some limits on this. Maybe leave the queue dynamic in the sense that it uses STL and only takes up as much memory as is necessary but limit the upper size of the queue. So that if say 300 (random number) packets are on the queue then the recvfrom thread would not be allowed to add another packet to it. That could get difficult but could work. Semaphores...more stuff to hunt up and read about

I''m just not seeing many ways to implement this so that it is
1) scalable to servers with varying #s of processors.
2) fast enough to accommodate XXX clients (probably on the order of a few hundred).

Again, blocking is out unless the blocking function call is isolated to a thread so that other things can still occurr.

Asynchronous IO in Unix is not very good according to "Unix Network Programming" leaving me with non-blocking and threads.
Plain non-blocking in a program with only one process would not scale at all if I can afford better servers to run it on.

That limits of to threads so now it''s just a matter of coming up with the best design I can. I''ll keep spitting out design options with threads for you all to destroy I don''t mind the criticism one bit. Sooner or later, I''ll hit something that works well enough and voila, gamedev will have some nice networking info to view.

Going to take a while now to work on the design. Will report back when I come up with something different, or at least reasons to defend the old way

Webby

WebsiteWill
WebsiteWill
Just found this helpful and interesting bit of info from "Unix Network Programming" page 398, "...there is no actual UDP socket send buffer. The kernel just copies the application data and moves it down te stack, prepending the UDP and IP headers. Therefore an output operation on a blocking UDP socket(the default) should never block".

So, now I no longer need a thread for sends
That''s one fewer stitches I need to make and greatly simplifies things. Now it''s just a matter of a thread handling receives on a blocking socket an another thread/s handling everything else.

Just thought the info might be useful before I forget to post it

Webby

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.