Jump to content

Does socket_write() block until all data is sent?


DWilliams

Recommended Posts

Say I have a server written in PHP (don't ask :D). Let's say I have 10 users connected to my script and one of those users, for the sake of the example, needs 10MB of data sent to them. If I send that data via socket_write(), does my program execution stop (therefor locking up every other user) until the data has gone through, or is the actual task of sending data over the tubes passed on to some lower level OS function so my program can get on with its flow?

Link to comment
Share on other sites

What sort of server? In general, the server will lock unless it is written to accept multiple connections/requests.

 

A "simple" multiplayer game server using php/web sockets as the server and JS as the client. My 10MB example was a bit on the large side, nothing that large will likely ever be sent by the server, but still, if the server is locked while sending data then it will become locked up more the more users are connected, especially if their connections are bad.

 

Might you have a link to something that explains how to better engineer a server?

Link to comment
Share on other sites

I meant what protocol is the server? Web sockets are implemented using HTTP.

 

Sorry, I don't really collect links but you should be able to find something on Google.

 

You would probably be better implementing this in a language more specific to the task though. JavaScripts Node.js comes to mind, it's perfect for such things.

Link to comment
Share on other sites

If I send that data via socket_write(), does my program execution stop (therefor locking up every other user) until the data has gone through, or is the actual task of sending data over the tubes passed on to some lower level OS function so my program can get on with its flow?

 

Sockets can operate in two different modes:

1) Blocking (default)

2) Non-blocking

 

If in blocking mode, then yes, execution will stop until all the data is sent, and all your other clients will be left waiting.

 

If in non-blocking mode, the function will send what it can then return.  However, the OS does not keep the unsent data and slowly send it as it is able.  This is something you have to manage yourself.  socket_write returns the number of bytes successfully sent.  If that is less than what you attempted to send, you need to store the excess bytes somewhere and try again later.

 

Link to comment
Share on other sites

If I send that data via socket_write(), does my program execution stop (therefor locking up every other user) until the data has gone through, or is the actual task of sending data over the tubes passed on to some lower level OS function so my program can get on with its flow?

 

Sockets can operate in two different modes:

1) Blocking (default)

2) Non-blocking

 

If in blocking mode, then yes, execution will stop until all the data is sent, and all your other clients will be left waiting.

 

If in non-blocking mode, the function will send what it can then return.  However, the OS does not keep the unsent data and slowly send it as it is able.  This is something you have to manage yourself.  socket_write returns the number of bytes successfully sent.  If that is less than what you attempted to send, you need to store the excess bytes somewhere and try again later.

 

Hmm, I'd previously been just calling socket_write and assuming magical network fairies took care of everything from that point on and carried my data from server to client.

 

I'm a bit confused as to how TCP comes into effect here, though. I know that TCP is supposed to ensure that my packets arrive at their destination all intact and orderly, but if I send a chunk of data with socket_write over my TCP socket and it doesn't all get to the other side, isn't that contrary to TCP's guarantees or am I thinking about this on the wrong level?

 

Given this knowledge, allow me to think out loud (and probably incorrectly) for how this should be done properly:

 

I call socket_set_nonblock() on a user's socket as soon as they connect. Instead of having a send method that simply passes data on through socket_write, I should have it add data to a buffer. I should have some other code somewhere (where?) that routinely checks buffers and writes what it can, subtracting what went through until all data is sent.

 

I don't know if I'm massively overthinking this of massively underthinking it  :shrug: I'm beginning to think all of this cannot be accomplished in a timely manner with only one thread?

Link to comment
Share on other sites

I'm a bit confused as to how TCP comes into effect here, though. I know that TCP is supposed to ensure that my packets arrive at their destination all intact and orderly, but if I send a chunk of data with socket_write over my TCP socket and it doesn't all get to the other side, isn't that contrary to TCP's guarantees or am I thinking about this on the wrong level?

 

TCP guarantees that the packets arrive intact and in order, yes.  TCP doesn't take over until the OS's networking stack actually accepts the data.  sockets have both a receive and a send buffer.  If either of these buffers is full, the OS will reject any new data.  So if an application is not reading the data and the read buffer fills up, then the OS will stop accepting new packets (and will tell the remote server this so it stops transmitting). This will cause the remote OS's write buffer to fill up.  The write buffer could also fill up if a network condition is preventing packets from being delivered, or they are being delivered too slowly.  Once full, the remote OS will stop accepting data for writing.

 

The blocking mode determines what actually happens in the event these buffers are full.  If you have blocking enabled, your read/write calls will block execution until the request can be satisfied.  For reading that means until enough data is received, and for writing that is until all the given data can be successfully sent (or in either case until an error occurs).

 

In non-blocking mode the read/write calls will give up, and return control back to you.  Their return values indicate how much data was successfully read/written so you can take action accordingly.

 

I call socket_set_nonblock() on a user's socket as soon as they connect. Instead of having a send method that simply passes data on through socket_write, I should have it add data to a buffer. I should have some other code somewhere (where?) that routinely checks buffers and writes what it can, subtracting what went through until all data is sent.

 

Yes, that is pretty much correct.  You will want a separate application buffer for reading and writing data.  You'll also have to code your application with the understanding that a read or a write may not complete all at once.  For instance, if your reading a packet off the wire, you need to be able to "abort" that read and try again later if the packet is not complete because the data has not all come through yet.  The way I handle this typically is by reading data into the read buffer, then using some parsing techniques to run through the buffer til I have a full packet.  If I get a full one, I chop the buffer at that point, otherwise it is left intact until the read is tried again.

 

I don't know if I'm massively overthinking this of massively underthinking it  :shrug: I'm beginning to think all of this cannot be accomplished in a timely manner with only one thread?

 

socket_select() is the key to everything.  it will inform you when a socket is ready to be read from or written to.  Your application should be centered around a loop on the socket_select call.  Something like:

do {
   $r=/* add sockets */
   $w=/* add sockets  */
   $e=null;
   $n = socket_select($r, $w, $e, null, null);
   if ($n > 0){
       foreach ($w as $s){
          ///write these sockets
       }
        foreach ($r as $s){ 
           //read these sockets
       }
   }
} while (/* you have sockets available */);

 

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.