BnetEx

BlitzMax Forums/BlitzMax Programming/BnetEx

Drackbolt(Posted 2009) [#1]
Hello there,
I've been working on trying to use TCP via BNetEx, but I've run into a problem. Whenever the client has SetTimeOuts (Recv) on anything above 0, the client will hang for that precise amount of time before processing any incoming message. This occurs with the sample code that comes with BNetEx itself, so it is not isolated to my own code. I've tried it on WinXP, Win7, two different computers, and through local and internet traffic, with no differences.
If I try to avoid the problem by setting recv timeouts to 0, I lose longer incoming strings in the stream; it cuts apart anything over 30-40 characters or so at random. The remaining data comes in eventually, but as a new message, I imagine because RecvMsg() is running too soon again.
So, if I set up the following scenarios (again Vertex's own code has this problem), here is what happens in either case:

1. Server and client initiate connection
2. Client sets SetTimeOuts(5000,5000)
3. Server sends a single line to client stream: "ThisStringWillGetRandomlyCutOff"
4. Client runs While MyClient.RecvMsg() ; Wend
5. Client hangs for 5 seconds
6. Client receives full message

1. Server and client initiate connection
2. Client sets SetTimeOuts(0,0)
3. Server sends a single line to client stream: "ThisStringWillGetRandomlyCutOff"
4. Client immediately receives one of two things:
a. The full string is received if lucky
b. Or, something like "ThisStringWillGet", followed by another
message of "RandomlyCutOff"

I should also point out that this issue does not exist for the "Send" portion of the timeouts. The client is always able to send messages to the server without either node suffering hangs.

I contacted the author last month and we talked the problem over, but he has not been responsive for whatever reason since then. Has anyone seen this issue, and/or knows of a workaround? Or could point out how I am misunderstanding the system?

Thanks.


_Skully(Posted 2009) [#2]
Hmmm... well, TCP is a reliable only packet... so if you are exiting before receiving the entire packet then I suppose you would have to get an entirely different packet next.

If your doing any kind of live game related networking I highly recommend that you go UDP... TCP will actually cause pauses in your code as it waits for TCP receipts

If its not live, then wait for the whole packet man! ;)


Mahan(Posted 2009) [#3]
This is not 100% on topic, but enet solves this problem (and much more). You simply pass it a buffer with data and then it's up to enet to deliver the whole buffer over the network, regardless of size. Enet handles splitting/joining/assembling of transfered buffers on its own internally.

So in you example above, converted to enet, you either receive the whole string (as you sent it) or nothing at all. Note that enet uses UDP, but there is a flag for guaranteed delivery. Besides enet also guarantees delivery of buffers in the right order (as sent).

Just FYI, coz why reinvent the wheel, right?


Drackbolt(Posted 2009) [#4]
Thanks for responding guys.
In this case, it's an RTS project (http://drackbolt.blogspot.com) so I'm using TCP for its reliability. I expect some performance hit but I need high sync. That being said, I'm not opposed to using other reliable networking libs; it's just that BNetEx marries with my code base in an almost perfect way and I'd love to keep using it. I honestly don't know a lot about the hard code of networking, so it's also nice to have something simple to work with. I wouldn't know how to make an equivalent version in Enet.
So _Skully, is this behavior something you would expect? Would the Recv timeout normally cause the system to hang when receiving a message in most libraries? It doesn't seem intuitive to me.


_Skully(Posted 2009) [#5]
Its just the nature of TCP...

The reason no one uses TCP transmission for RTS's is because of the pauses while the transmission/acknowledgement takes place... i highly recommend you go with UDP... something like what Mahan is talking about


TaskMaster(Posted 2009) [#6]
Pauses? I don't think there has to be pauses. You just don't get packets until they have been acknowledged. So, they will seem a little slower.

What do you mean by pauses?


Drackbolt(Posted 2009) [#7]
Thanks for jumping in TaskMaster.
I mean the moment any message reaches the client, the client immediately hangs completely, and does not respond again until the Recv timeout has elapsed. So if I set SetTimeOuts(5000,5000), the client will, upon receiving any message, wait for 5000ms before resuming. So, effectively, setting a Recv timeout higher than zero will make the game virtually unplayable. If I set the timeout to zero, everything runs quickly, but then I run into that problem I mentioned with long data getting chopped off.
I hope someone else can recreate this because I've seen it with Vertex's own code in every configuration I've tried it on.


TaskMaster(Posted 2009) [#8]
That problem is something to do with BNetEx, not TCP.

Sorry, but I have never used BNetEx, so I can't help you with it.


Drackbolt(Posted 2009) [#9]
That's what I figured when I started this thread. :) Thanks for responding though.

If anyone else here uses BNetEx, please let me know what your experiences have been with it.


Tibit(Posted 2009) [#10]
TCP doesn't have to hang your application @ recv, that is just one way to deal with TCP - if you have threads. And I assume you don't so setting timeout to 0 is correct I think. But it does hang when you call "connect" doesn't it? ;)

What it looks like to me is that you (or BNetEx) is not treating TCP like the streambased protocol it is. You don't want TCP to act like it is a stream in your games --> you want full complete packages. UDP come in packages so it would be simpler to use in that sense.

While it does seem like a bit strange that you get a cutoff on such a short message, the solution is to add a identifier to your messages. Because it is TCP you will receive everything from the "stream" in the same order it was sent. So you can start every message sent by writing an int (or short would do) that is the size of the complete message.

When the message arrive you know how much you should read until you have the complete package. Sometimes you might get it cut-off, and you'll need to read more (until that size is met), or you might need to stop reading (when you have gotten the full size) - The next data is going to be part of the next message --> start reading the size, then that data..

And regarding TCP for a RTS - in my experience, if you are using a Lock-Step protocol that should work just fine, there is no downside to it except that you can't push as efficiently as you could do with UDP using the quake3 model for example. Normal reliable and ordered UDP have little or no benefit compared to TCP in a lockstep application anyway, however neither do TCP bring an advantage compared to UDP in that case. And using a Lock-Step protocol for RTS games is quite common as it has several advantages, like that you only need to send delta values (actions) and no full states = low bandwidth and the possibility to save replays. The downside is responsiveness when playing with people with bad ping, but you'll get perfect Consistency :P


Drackbolt(Posted 2009) [#11]
Thanks Tibit.

My thoughts exactly on using TCP here... I'd have to make UDP both ordered and reliable anyway, because (for the moment) I'm using a p2p full client architecture, sending only sync updates. So, my model is definitely low traffic and high consistency. This is only for a two-player early version of networking so I'm not worried about exponential traffic increases yet. I have plans eventually to make a dedicated server with thin clients, in which case I'll definitely use UDP, as some loss of data won't be a concern from the client side.

For now, I do have a workaround in place. Thankfully there is only one place where I need to gather very long strings and it is during game initialization, so I've added a larger Recv timeout to a specific place after signaling a need for it. I have also used the "end of message" idea to make sure all the data arrives, but of course it's ridiculous to me to have to do this for a TCP connection. I really do think there is a problem with BNetEx. Maybe it's because it started out only with UDP, so Vertex is not treating TCP correctly, as you said?

At any rate, it won't matter to me as long as it works from now on the way I'm handling it. My only worry is that when people start playing games with some lag online, even very small strings may get cut off, which will be a big problem. We'll see what happens.

In the meantime, I'm keeping my eyes open for other libs I can use to do a quick conversion away from BNetEx. Basically I just need something that can send long strings back and forth. I do all the parsing and calculations on the other end. Anybody know of a good library, wrapper, or module that might fit?


Tibit(Posted 2009) [#12]
I did fix that thing with TCP in my network library TNet. So I figured I'd try to see if it still works. And it mysteriously did.

I'm not sure if you want to use it, but you are free to if you want.

I threw together a quick application to test if it works. It is built to be simple to use so I hope it still is :P It also comes with a simple packing library if you want to send things other that strings ;)

TCP CLIENT TEST


TCP SERVER TEST

You need to download these 5 source-files and put them in the same folder as the examples.
TNetBASIC_Source1.20v2.zip
Manual here:
List of Commands

Whatever the site says - it is now 100% FREE to use for whatever you want :)


Drackbolt(Posted 2009) [#13]
Thanks a lot Tibit! I'm taking a close look at your stuff right now.


Drackbolt(Posted 2009) [#14]
Looks like I might be able to use TNet here. I've started swapping out the code using your simple examples and everything seems to be working beautifully now. So, it looks like BNetEx was in fact the issue. I'm very glad you popped in here and offered your assistance. I'll be sure to credit you if things proceed all the way to the finish line.