SDL_net: non-blocking TCP?

Hi everyone,

I hope this is also the right list for SDL_net questions…

Looking through the SDL_net docs and code, I noticed that while "accept"
is non-blocking, the TCP reading and writing functions aren’t. It seems
that it should be possible to get non-blocking operations fairly easily,
using select or setting the sockets to non-blocking.

I need non-blocking operations for a game project of mine, and I’m sure
they would be useful for a lot of other real-time networking projects.
I’d like to use SDL_net for it’s simplicity and portability. I’m willing
to add the non-blocking code myself and share with everyone, except for
the following:

  1. Has anyone already done this? I wouldn’t want to reinvent the wheel
    yet another time.

  2. I would only be able to work on the Linux/Unix code, and maybe the
    Windows version (no Visual Studio, though). Someone else would need to
    supply the Mac version, from what I see.

Any comments?

Bye,

Benjamin–
:: Benjamin Deutsch
(OO) @Benjamin_Deutsch
(
)
=""=========================

Hi everyone,

I hope this is also the right list for SDL_net questions…

Looking through the SDL_net docs and code, I noticed that while "accept"
is non-blocking, the TCP reading and writing functions aren’t. It seems
that it should be possible to get non-blocking operations fairly easily,
using select or setting the sockets to non-blocking.

SDL_net has select call that goes by the name of SDLNet_CheckSockets()
that does what you want.

I need non-blocking operations for a game project of mine, and I’m sure
they would be useful for a lot of other real-time networking projects.
I’d like to use SDL_net for it’s simplicity and portability. I’m willing
to add the non-blocking code myself and share with everyone, except for
the following:

  1. Has anyone already done this? I wouldn’t want to reinvent the wheel
    yet another time.

  2. I would only be able to work on the Linux/Unix code, and maybe the
    Windows version (no Visual Studio, though). Someone else would need to
    supply the Mac version, from what I see.

Take a look at NET2 at http://gameprogrammer.com/game.html. It does
pretty much everything you want. It is already written. And, it run
entirely on top of SDL so it is portable.

	Bob Pendleton

P.S.

I wrote it.On Thu, 2004-04-15 at 15:30, Benjamin Deutsch wrote:

Any comments?

Bye,

Benjamin

±--------------------------------------+

SDL_net has select call that goes by the name of SDLNet_CheckSockets()
that does what you want.

Nope, not good enough. CheckSockets only tells me IF a socket can be
read, not HOW MUCH. I could, of course, call CheckSockets, then read one
byte, then call CheckSockets etc.

What I actually want is a “give me what you’ve got, even if it’s zero,
and return the number read.”, like read typically does, much to the
annoyance of new-timers.

Take a look at NET2 at http://gameprogrammer.com/game.html. It does
pretty much everything you want. It is already written. And, it run
entirely on top of SDL so it is portable.

Thanks, I’ll look into it!

Bye,

Benjamin–
:: Benjamin Deutsch
(OO) @Benjamin_Deutsch
(
)
=""=========================

SDL_net has select call that goes by the name of SDLNet_CheckSockets()
that does what you want.

Nope, not good enough. CheckSockets only tells me IF a socket can be
read, not HOW MUCH. I could, of course, call CheckSockets, then read one
byte, then call CheckSockets etc.

The SDL_net demos send each message in two parts: the first part just
tells you the size of the second part. You can download them from:

http://jcatki.no-ip.org/SDL_net/

JamesOn Thu, 15 Apr 2004 23:22:35 +0200, Benjamin Deutsch wrote:

SDL_net has select call that goes by the name of SDLNet_CheckSockets()
that does what you want.

Nope, not good enough. CheckSockets only tells me IF a socket can be
read, not HOW MUCH. I could, of course, call CheckSockets, then read one
byte, then call CheckSockets etc.

What I actually want is a “give me what you’ve got, even if it’s zero,
and return the number read.”, like read typically does, much to the
annoyance of new-timers.

SDLNet_TCP_Recv() and SDLNet_UDP_Recv() do exactly that.

Do you have a copy of the SDL_net documentation? You can find it at
http://www.libsdl.org/projects/SDL_net/ All of the questions you have
asked so far are covered in there.

	Bob PendletonOn Thu, 2004-04-15 at 16:22, Benjamin Deutsch wrote:

Take a look at NET2 at http://gameprogrammer.com/game.html. It does
pretty much everything you want. It is already written. And, it run
entirely on top of SDL so it is portable.

Thanks, I’ll look into it!

Bye,

Benjamin

±--------------------------------------+

SDLNet_TCP_Recv() and SDLNet_UDP_Recv() do exactly that.

Do you have a copy of the SDL_net documentation? You can find it at
http://www.libsdl.org/projects/SDL_net/ All of the questions you have
asked so far are covered in there.

Bob Pendleton

Well, the documentation is confusing I think. From the SDLNet_TCP_Recv()
docs…

Receive data of exactly length maxlen bytes from the socket sock, into the
memory pointed to by data.
This routine is not used for server sockets.
Unless there is an error, or the connection is closed, the buffer will
read maxlen bytes. If you read more than is sent from the other end, then
it will wait until the full requested length is sent, or until the
connection is closed from the other end.

This makes it sound like it will block until the buffer you give it is
full. I had to start digging in the source to realize that it will read UP
TO maxlen bytes, but will still return how much was read if the buffer
isn’t full.

I think it means if you call recv and nothing is there to be read, it will
block until there is.

Which makes complete sense. Blocking until a buffer is filled doesn’t seem
entirely useful to me.

Hello,

SDLNet_TCP_Recv() and SDLNet_UDP_Recv() do exactly that.

Well, UDP, sure, but I actually want guaranteed and in-order delivery,
so I’d like to use TCP.

Well, the documentation is confusing I think. From the
SDLNet_TCP_Recv() docs…

Receive data of exactly length maxlen bytes from the socket sock, into
the memory pointed to by data.
This routine is not used for server sockets.
Unless there is an error, or the connection is closed, the buffer will
read maxlen bytes. If you read more than is sent from the other end,
then it will wait until the full requested length is sent, or until the
connection is closed from the other end.

This makes it sound like it will block until the buffer you give it is
full. I had to start digging in the source to realize that it will read
UP TO maxlen bytes, but will still return how much was read if the
buffer isn’t full.

This does not merely make it sound like it, it describes the “block til
full” behaviour precisely. I must confess that I now see I had misread
the code, probably due to reading the docs just before.

I think it means if you call recv and nothing is there to be read, it
will block until there is.

There’s that, plus sending will still block until everything is sent.

Blocking until a buffer is filled doesn’t seem entirely useful to me.

Actually, it is useful (provided you know the length of the “message”,
which is often the case) in the context of the simple “receive request,
then send reply” server model. You know the one, where every new
connecting client spawns a new thread or fork.

In fact, the “block until fully completed” model is exactly what someone
new to networking will expect, and will eventually trip over if it’s
missing. That’s why I assumed the docs were correct, to make networking
"just work".

I seem to have not made it clear what my requirements were, and why the
present code is still not sufficient. Here’s what I want:

  • I’d like to not have to use threads or any callback or event model.
    Bob had pointed me towards his NET2 code, and it looks very good, but an
    early design choice of mine (for code readability) was to not use
    threads or callbacks for my current project.
  • SDLNet_TCP_Send, as it is, will block until everything is sent. With
    CheckSockets, I can check whether the first (internal) send will block
    or not, but not the whole Send. I’d like Send to return the number of
    bytes sent, including a value lower than len if not all could be sent on
    the first try, or 0 if the call would block in any case.
  • Likewise, SDLNet_TCP_Recv will still block until it can return that it
    read more than 0 bytes. I’d like it to return 0 instead of blocking.
    Yes, CheckSockets can help here, but it encumbers the interface too much
    for my liking.

So I think I’ll try adapting SDL_Net myself. It shouldn’t take more than
a “blocking” flag, adding “O_NONBLOCK” to all sockets, and changing the
do {
send_or_read();
} while (!sent_or_read_enough)
parts, for Linux anyway. I’ll let you know how it turned out.

Thanks everyone!

Benjamin

SDLNet_TCP_Recv() and SDLNet_UDP_Recv() do exactly that.

Do you have a copy of the SDL_net documentation? You can find it at
http://www.libsdl.org/projects/SDL_net/ All of the questions you
have
asked so far are covered in there.

            Bob Pendleton

Well, the documentation is confusing I think. From the
SDLNet_TCP_Recv() docs…

Receive data of exactly length maxlen bytes from the socket sock, into
the memory pointed to by data.
This routine is not used for server sockets.
Unless there is an error, or the connection is closed, the buffer will
read maxlen bytes. If you read more than is sent from the other end,
then it will wait until the full requested length is sent, or until
the connection is closed from the other end.

This makes it sound like it will block until the buffer you give it is
full. I had to start digging in the source to realize that it will
read UP TO maxlen bytes, but will still return how much was read if
the buffer isn’t full.

I think it means if you call recv and nothing is there to be read, it
will block until there is.

You are absolutely right. The documentation is confusing. I had to go
look at my code and see how I used it. I do not try to read from a
socket until checksockets says it is ready. Then, I read it and expect
it to give me what it can, just like we both want it to work. If the
socket is marked ready, but has zero data it is dead.

Which makes complete sense. Blocking until a buffer is filled doesn’t
seem entirely useful to me.

No, not much use at all.

Oh well, take a look at net2. It works, does all the network IO in a
worker thread and is “mostly” non-blocking. It can block on writing to
the network. Also, it contains thread safe wrappers for a large part of
SDL_net. SDL_net by itself is not thread safe.

	Bob PendletonOn Fri, 2004-04-16 at 12:52, Brian wrote:

_______________________________________________ SDL mailing list
SDL at libsdl.org http://www.libsdl.org/mailman/listinfo/sdl

±--------------------------------------+

Oh well, take a look at net2. It works, does all the network IO in a
worker thread and is “mostly” non-blocking. It can block on writing to
the network. Also, it contains thread safe wrappers for a large part of
SDL_net. SDL_net by itself is not thread safe.

            Bob Pendleton

I did look into NET2 quite a bit, and even implemented it into my
project. But something with the way the fast events library works broke
the update events mechanism in aedGUI. So if you had something like a
progress bar that should smoothly go left and right, it wouldn’t update
until I moused over things. So I had to revert to SDL_net and put all the
networking stuff in its own thread. Works well enough for a client
app. Kind of unfortunate, NET2 looked like a really nice library. I
wonder how hard it’d be to make it use the sdl_event queue for apps that
don’t need fast events.

Oh well, take a look at net2. It works, does all the network IO in a
worker thread and is “mostly” non-blocking. It can block on writing to
the network. Also, it contains thread safe wrappers for a large part of
SDL_net. SDL_net by itself is not thread safe.

            Bob Pendleton

I did look into NET2 quite a bit, and even implemented it into my
project. But something with the way the fast events library works broke
the update events mechanism in aedGUI.

I’m sorry to hear that. Unfortunately that is the way it works. I’m sure
that aedGUI use the normal SDL event functions and those do not mix with
fastevents.

So if you had something like a
progress bar that should smoothly go left and right, it wouldn’t update
until I moused over things. So I had to revert to SDL_net and put all the
networking stuff in its own thread. Works well enough for a client
app. Kind of unfortunate, NET2 looked like a really nice library. I
wonder how hard it’d be to make it use the sdl_event queue for apps that
don’t need fast events.

Not very hard. Should take about 10 minutes… which means less than a
week :slight_smile: There are exactly two calls to the fastevents library in net2.
The call to FE_pushevents should be replaced with a call to
SDL_PushEvents() and the call to FE_PollEvents() should just be removed.
It is only needed to play nice with code that may be blocked waiting to
put things in the event queue, but since SDL_PushEvents() doesn’t block
it isn’t a problem.

Doing that would make it use the SDL event system. For many applications
that would work just fine.

	Bob PendletonOn Fri, 2004-04-16 at 15:20, brian wrote:

SDL mailing list
SDL at libsdl.org
http://www.libsdl.org/mailman/listinfo/sdl

±--------------------------------------+