TCP application - Synchronization issue??

  • Thread starter Thread starter Amit
  • Start date Start date
A

Amit

Hi

I am developing an application in C#. The application creates a
TCPListener object and listens to (incoming) data on a particular
port. A simulator hardware writes data to this port. My application
reads the data and process it and generates some results for display.

The TCPListener object waits for incoming data in a background thread.
The amount of data that is being written is large (around 100 KBytes
in one go). The thread listening for incoming data does not do much
processing. It allocates a buffer of large enough size and waits for
some data to be written on the port (TCPListener.Read() ). Once the
data arrives, it resizes the buffer to the size of the data written
and enqueues it in a Queue object. It then sets an AutoResetEvent to
which other thread is waiting. (That thread then dequeues the data and
processes it).

The hardware is expected to write data in multiple of 4 bytes. If the
number of bytes written to the port is not multiple of 4 then it is
error condition. I am observing that sometimes the application does
not recieve the data of size which is multipe of 4. I am believing
that the hardware is producing correct application data. However,
there is a synchronisation issue for the software application. Before
the previous read is complete, the hardware seems to write new data.
Is this possible? If yes, then how does windows socket mechanism
handle it? Does it buffer the new data internally and then make it
available to the application once the previous read is over? I need
some clarity here. Can anyone explain how the underlying windows
socket mechanism work when there is a simultaneous read/write to an
application port?

Thanks in advance
Best regards
Amit Dedhia
 
Amit said:
Hi

I am developing an application in C#. The application creates a
TCPListener object and listens to (incoming) data on a particular
port. A simulator hardware writes data to this port. My application
reads the data and process it and generates some results for display.
...
The hardware is expected to write data in multiple of 4 bytes. If the
number of bytes written to the port is not multiple of 4 then it is
error condition. I am observing that sometimes the application does
not recieve the data of size which is multipe of 4. I am believing
that the hardware is producing correct application data. However,
there is a synchronisation issue for the software application. Before
the previous read is complete, the hardware seems to write new data.
Is this possible? If yes, then how does windows socket mechanism
handle it? Does it buffer the new data internally and then make it
....

Hi,
You should not count on sockets preserving packet sizes that you write. When
you write to socket, it is buffered by OS, then break into packet by TCP/IP
stack. Bottom line, if you send 100 bytes, don't count you'll receive
exactly 100 byte is one receive call on the other side. It can be 25, 40,
35, or even > 100 if sender does multiple send calls fast (it will be joined
in one packet and sent to other side). No gurantees except that byte order
is preserved.

Regards,
Goran
 
Amit said:
Once the
data arrives, it resizes the buffer to the size of the data written
and enqueues it in a Queue object.

Is access to the Queue synchronized (i.e. mutually exclusive)?
It then sets an AutoResetEvent to
which other thread is waiting. (That thread then dequeues the data and
processes it).

I wouldn't use an AutoResetEvent if I were you. If the dequeue thread
hasn't finished processing the last bit of data and hasn't yet waited on
the AutoResetEvent, then it will miss the notification and deadlock.

Consider using Monitor.Pulse and Monitor.Wait instead, very roughly like
this:

// Dequeue thread
for (;;)
{
for (;;)
lock (_queue)
{
if (_queue.Count > 0)
{
data = _queue.Dequeue();
break;
}
Monitor.Wait(_queue);
}
// process data
}

Consider using an "end of data" item in the queue to communicate thread
shutdown.

// Enqueue thread, received data
lock (_queue)
{
_queue.Enqueue(data);
Monitor.Pulse(_queue);
}
The hardware is expected to write data in multiple of 4 bytes. If the
number of bytes written to the port is not multiple of 4 then it is
error condition.

Note that TCP is a stream protocol, not a packet protocol, so you aren't
guaranteed to receive multiples of 4 bytes, or the same sized buffers as
the sending side. For robust behaviour, you should consider processing
Length / 4 packets at a time, saving the sundry for the next receive.
I am observing that sometimes the application does
not recieve the data of size which is multipe of 4. I am believing
that the hardware is producing correct application data. However,
there is a synchronisation issue for the software application. Before
the previous read is complete, the hardware seems to write new data.

TCP & networking can have buffers anywhere along the stack. The sender
is only blocked if it's out of buffer space or has run up against the
limit of the TCP window. It does not have to wait for the receiver to
read what it just sent.
If yes, then how does windows socket mechanism
handle it? Does it buffer the new data internally and then make it
available to the application once the previous read is over?

Assuming blocking sockets:

The sender can continue to send until something in the stack can't take
it, at which point it will block. By "something can't take it", I mean
either there isn't buffer space, or (more likely, if the receiver is
slow) the TCP window limit is hit. The TCP window is basically the
amount of IP packets the sender can send to the receiver before
receiving acknowledgement of sent packets.

The receiver will continue to receive data in the order it was sent. If
no data is ready, it will block. If the connection is closed by either
end, a call to receive will return with 0 bytes read.

-- Barry
 
Hi,

Amit said:
The TCPListener object waits for incoming data in a background thread.

In this kind of app I would suggest you to make it async.
The amount of data that is being written is large (around 100 KBytes
in one go). The thread listening for incoming data does not do much
processing. It allocates a buffer of large enough size and waits for
some data to be written on the port (TCPListener.Read() ). Once the
data arrives, it resizes the buffer to the size of the data written
and enqueues it in a Queue object.

Why do you "reset" your buffer?
How did you set your original buffer size?
how do you know if the amount of data you received was the same amount of
data sent? (it may get splitted in the way)


The hardware is expected to write data in multiple of 4 bytes. If the
number of bytes written to the port is not multiple of 4 then it is
error condition.

How you know you got the entire sent data? and not just part of it
Can anyone explain how the underlying windows
socket mechanism work when there is a simultaneous read/write to an
application port?

The sending of data is not a sync'ed operation you read what is ready. It's
the protocol you define over the TCP connection the one that define how the
data is interpreted. Some protocols send a command like a ftp get. and then
it first receive the size of the file being downloaded, in this way the
client knows when to expect more data.
 
Is access to the Queue synchronized (i.e. mutually exclusive)?


I wouldn't use an AutoResetEvent if I were you. If the dequeue thread
hasn't finished processing the last bit of data and hasn't yet waited on
the AutoResetEvent, then it will miss the notification and deadlock.

Consider using Monitor.Pulse and Monitor.Wait instead, very roughly like
this:

// Dequeue thread
for (;;)
{
for (;;)
lock (_queue)
{
if (_queue.Count > 0)
{
data = _queue.Dequeue();
break;
}
Monitor.Wait(_queue);
}
// process data

}

Consider using an "end of data" item in the queue to communicate thread
shutdown.

// Enqueue thread, received data
lock (_queue)
{
_queue.Enqueue(data);
Monitor.Pulse(_queue);

}

Note thatTCPis a stream protocol, not a packet protocol, so you aren't
guaranteed to receive multiples of 4 bytes, or the same sized buffers as
the sending side. For robust behaviour, you should consider processing
Length / 4 packets at a time, saving the sundry for the next receive.


TCP& networking can have buffers anywhere along the stack. The sender
is only blocked if it's out of buffer space or has run up against the
limit of theTCPwindow. It does not have to wait for the receiver to
read what it just sent.


Assuming blocking sockets:

The sender can continue to send until something in the stack can't take
it, at which point it will block. By "something can't take it", I mean
either there isn't buffer space, or (more likely, if the receiver is
slow) theTCPwindow limit is hit. TheTCPwindow is basically the
amount ofIPpackets the sender can send to the receiver before
receiving acknowledgement of sent packets.

The receiver will continue to receive data in the order it was sent. If
no data is ready, it will block. If the connection is closed by either
end, a call to receive will return with 0 bytes read.

-- Barry

--http://barrkel.blogspot.com/

Thanks for all replies. I now understand that the number of bytes
received in the buffer can be anything and I need to handle '4 byte
long packet thing' inside my application. So if the number of packets
received are not multiple of 4, i need to cache additional bytes
locally and prepend to the the next lot of the data that I will
receive.

Now there is one issue of the buffer size. I dont know how much data
is going to be written in one shot. So how much buffer should I
allocate for receiving data? From what I understand from above, I
think I need not worry about this. If the the buffer space is not
sufficient, then the data write (from the hardware to my application
buffer) will be blocked and I will receive the data in next cycle. Is
this true?

Thanks and best regards
Amit Dedhia
 
[...]
Now there is one issue of the buffer size. I dont know how much data
is going to be written in one shot. So how much buffer should I
allocate for receiving data?

It depends, but typically 4K or 8K is a pretty decent size for your
receive buffer. That's large enough that assuming you can receive the
data fast enough, you should generally be able to clear out the network
driver buffer with each receive, without wasting too much space (of
course, these days you could probably make your buffer even larger without
it hurting things too much :) ).

For very low bandwidth applications, it may be sufficient to provide a
buffer no larger than the largest logical data group you expect to have,
even if that's just a hundred bytes (or even less). You won't read the
data from the network driver efficiently, but it will be good enough as
long as data isn't actually coming in very fast, and it can save you the
hassle of dealing with yet another buffer in your code (you can just
allocate a buffer for the logical data group itself, filling directly it
as you go along with calls to the receiving method).
From what I understand from above, I
think I need not worry about this. If the the buffer space is not
sufficient, then the data write (from the hardware to my application
buffer) will be blocked and I will receive the data in next cycle. Is
this true?

That is true. However, keep in mind that it will affect efficiency. The
more time you have to call the network driver (via .NET Socket class,
Winsock, whatever), the lower your maximum bandwidth. Also, if you don't
receive data fast enough, then it's a negative feedback loop because the
sender may wind up having to pause or resend data, which further slows
things down.

Again, for low bandwidth applications, this isn't a concern but if you
have a need for efficiency, you should buffer receives yourself into a
large enough buffer to ensure that the network driver is always able to
receive new data from any senders.

Pete
 
Back
Top