0

In this MSDN Magazine August 2005 article Daryn Kiely explains three ways to build a TCP Server.

The third model, the async one, is the one that best fit my needs, but I'm having some throuble understanding some details of its internal working.

Question 1 - About number of Threads accepting connections

In the example, when the server is started by calling Start(), the code creates ten ThreadPools accepting connections:

public void Start()
{
    SetupServerSocket();
    for (int i = 0; i < 10; i++)
        _serverSocket.BeginAccept(AsyncCallback(AcceptCallback), _serverSocket);
}

I didn’t understand why you can’t use just one _serverSocket.BeginAccept, and why the number ten.

Question 2 – About zero bytes received

In ReceiveCallback(), if we receive zero bytes we close the connection. Why? When zero bytes are received is always considered that the client closed the connection? In the tests I’ve made here, when my client closes the connection I get an exception that is catched in SocketException. Am I missing something here?

Question 3 – About the need to BeginReceive again

After something is received in socket it's put back to BeginReceive. Why do we need to start receiving again? Shouldn’t this be automatically?

Question 4 – About buffer size

A buffer of 255 bytes is used. I understand that if a message has greater length than buffer size it gets fragmented in multiple receives. Should I set a buffer size big enough to guarantee that no message will get fragmented, or I must provide code to deal with message fragmentation (to join multiples receives in a single buffer)?

Community
  • 1
  • 1
RHaguiuda
  • 3,207
  • 9
  • 37
  • 55
  • Re: Question 4 - There's no guarantee on any matching up between sends on one side and receives on the other side, even if you use large buffers. The only safe way to code is to assume that *any* message, no matter how small, may be fragmented. and/or that any `Receive` may fill the buffer with parts from multiple messages – Damien_The_Unbeliever Nov 06 '12 at 13:43

2 Answers2

3

Question 1 - About number of Threads accepting connections

In the example, when the server is started by calling Start(), the code creates ten ThreadPools accepting connections:

public void Start()
{
    SetupServerSocket();
    for (int i = 0; i < 10; i++)
        _serverSocket.BeginAccept(AsyncCallback(AcceptCallback), _serverSocket);
}

I didn’t understand why you can’t use just one _serverSocket.BeginAccept, and why the number ten.

There is no reason to spawn several BeginAccept like that. Just invoke a new BeginAccept in the AcceptCallback instead.

Question 2 – About zero bytes received

In ReceiveCallback(), if we receive zero bytes we close the connection. Why? When zero bytes are received is always considered that the client closed the connection? In the tests I’ve made here, when my client closes the connection I get an exception that is catched in SocketException. Am I missing something here?

Yes. 0 bytes means a graceful disconnect. i.e. the other side first uses Shutdown and then Close instead of close directly.

Any other kind of disconnects will generate exceptions.

Question 3 – About the need to BeginReceive again

After something is received in socket it's put back to BeginReceive. Why do we need to start receiving again? Shouldn’t this be automatically?

No. For instance when you are closing your server you do not want to read again. Other clients may only want to receive once, process the data and then disconnect.

Question 4 – About buffer size

A buffer of 255 bytes is used. I understand that if a message has greater length than buffer size it gets fragmented in multiple receives. Should I set a buffer size big enough to guarantee that no message will get fragmented, or I must provide code to deal with message fragmentation (to join multiples receives in a single buffer)?

One sent byte[] can ALWAYS be framgented into multiple receives. A single receive could also contain two sent byte[] buffers. It's how TCP works.

You typically use one receive buffer and then another one to build the message. Or use a larger buffer and tell Receive to complete the message by using a larger offset in the method invocation

jgauffin
  • 99,844
  • 45
  • 235
  • 372
  • 1
    I object to saying that TCP might fragment or coalesce messages because there *are no messages*. This word does not makes sense in relation to TCP. – usr Nov 06 '12 at 13:43
  • I referred to an application level message, but changed into `byte[]` to clarify that. – jgauffin Nov 06 '12 at 14:06
  • A single receive could also contain *fragments of* two *or more* buffers (you could receive end of send 1, all of send 2, start of send 3, for example) – Damien_The_Unbeliever Nov 06 '12 at 14:13
  • Read an old answer of mine: http://stackoverflow.com/questions/6178883/problem-reading-from-a-tcpclient – jgauffin Nov 06 '12 at 14:16
  • For question 3 .. `BeginReceive()` doesn't mean "Begin your receiving loop" it's just the first hald of the asynchronous version of the synchronous `Receive()`. I got the sense from the OP that the terminology was misleading him. – Jason Kleban Nov 06 '12 at 18:08
2

Alright I'll have a go:

1) A single BeginAccept in there would mean that your server socket won't be accepting connection until the next BeginAccept is called in the AcceptCallback, which is not called immediately but rather after some work is done. The number 10 I suppose is arbitrary - it's like spooling 10 accepts or in essence being able to take up to 10 incoming connection requests simultaneously. If you don't need to handle a lot of clients I suppose a single BeginAccept will still work.

2) I don't know what client have you used, but I've used socket connection with browsers, and when they close connection they do like to send and empty segment (or that is what I see debugging anyway) as a notice for closure. Someone can correct me if this is no longer true, however seems like a good practice to check for that.

3) Well it kind of isn't automatic. And it's good to loop it to make sure you don't miss something.

4) As far as I'm aware Windows doesn't have a maximum for TCP buffer size, unless specified by admin. So you could increase it suppose, but perhaps take a look at: What is a good buffer size for socket programming? - says there in the comments you should't try to get all of the message in a single receive as it is a streaming protocol after all.

halfer
  • 19,824
  • 17
  • 99
  • 186
Damyan Petev
  • 1,585
  • 7
  • 10
  • TCP does not have messages so the browser cannot send an empty one. Socket.Receive never returns a valid 0 byte chunk. – usr Nov 06 '12 at 13:42
  • Edited to segment, but really not a stickler for words, it's potentially just a FIN control flag but there's no way browsers can't send that for Http connection because they deffinately do for WebSocket ones, and both are just glorified TCP. – Damyan Petev Nov 06 '12 at 14:34