Socket weirdness

  • Thread starter William Stacey [MVP]
  • Start date
W

William Stacey [MVP]

See some strange results on Send and peer with a closed Receive. Setup a
test harness. Server accepts socket, then just does a Shutdown.Receive
right away and waits. The client socket does both blocking Sends and
BeginSends to see the difference in behavior.

Results:
1) Using blocking Sends - The first send returns 10, which is the buffer
size. Future Sends, return 0 and no exception. This behavior seems not to
fly with the doco. The send should block until 10 bytes are sent to kernel
mode or throw an exception, *not return 0. Note the socket is in blocking
mode (default setting).

2) Using async BeginSend gives completly different results. The first
EndSend returns 10 as above. The second BeginSend returns a null
IAsyncResult and sets SocketError to "ConnectionReset". I find this
behavior very strange. BeginSend should never return a null IAsyncResult as
that FooBars the async pattern (it should always return IAsync or
exception). It should save the exception for the EndSend call. Second, why
does it set SocketError to ConnectionReset, when blocking Send does not seem
to care. The two behaviors should be consistent.

3) Also, what is the point of SocketError being an out parm? It should just
be included in the SocketException and thrown - no?

TIA
 
W

William Stacey [MVP]

Should have included the test code:

// Server.
TcpListener l = new TcpListener(IPAddress.Any, 9001);
l.Start();
new Thread(
delegate()
{
using (NetPortNew srvClient = new
NetPortNew(l.AcceptSocket(), "srvClient"))
{
srvClient.Shutdown(SocketShutdown.Receive);
Thread.Sleep(2000);
}
l.Stop();
}).Start();

// Client.
byte[] buf = new byte[10];
using (Socket s = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp))
{
Console.WriteLine("Blocking mode:{0}", s.Blocking);
s.Connect(IPAddress.Loopback, 9001);
Thread.Sleep(2000);
SocketError se = SocketError.Success;
int read = 0;

for (int i = 0; i < 3; i++)
{
read = s.Send(buf, 0, buf.Length, SocketFlags.Partial,
out se);
Console.WriteLine("Bytes written to kernel:{0}", read);
Thread.Sleep(100);
}
// Note the different results with async send.
IAsyncResult ar = s.BeginSend(buf, 0, buf.Length,
SocketFlags.None, out se, null, null);
Console.WriteLine("BeginSend.");
read = s.EndSend(ar); // ar is null.
Console.WriteLine("Bytes written to kernel:{0}", read);
}

--
William Stacey [MVP]

| See some strange results on Send and peer with a closed Receive. Setup a
| test harness. Server accepts socket, then just does a Shutdown.Receive
| right away and waits. The client socket does both blocking Sends and
| BeginSends to see the difference in behavior.
|
| Results:
| 1) Using blocking Sends - The first send returns 10, which is the buffer
| size. Future Sends, return 0 and no exception. This behavior seems not
to
| fly with the doco. The send should block until 10 bytes are sent to
kernel
| mode or throw an exception, *not return 0. Note the socket is in blocking
| mode (default setting).
|
| 2) Using async BeginSend gives completly different results. The first
| EndSend returns 10 as above. The second BeginSend returns a null
| IAsyncResult and sets SocketError to "ConnectionReset". I find this
| behavior very strange. BeginSend should never return a null IAsyncResult
as
| that FooBars the async pattern (it should always return IAsync or
| exception). It should save the exception for the EndSend call. Second,
why
| does it set SocketError to ConnectionReset, when blocking Send does not
seem
| to care. The two behaviors should be consistent.
|
| 3) Also, what is the point of SocketError being an out parm? It should
just
| be included in the SocketException and thrown - no?
|
| TIA
|
| --
| William Stacey [MVP]
|
|
|
 
V

Vadym Stetsyak

Hello, William!

[skipped]

WSM> 3) Also, what is the point of SocketError being an out parm?

When you use method with SocketError, you do not receive an exception, instead you
have to check return value of SecketError param.
Actually you may receive exceptions, but it is unlikely to happen ::cool:.
Maybe this was done for perfomance reasons?

WSM> It should just be included in the SocketException and thrown - no?

When getting socket exception there is ErrorCode that describes the error.
What the point of SocketError there?

--
Regards, Vadym Stetsyak
www: http://vadmyst.blogspot.com
 
D

Dave Sexton

Hi William,
See some strange results on Send and peer with a closed Receive. Setup a
test harness. Server accepts socket, then just does a Shutdown.Receive
right away and waits. The client socket does both blocking Sends and
BeginSends to see the difference in behavior.

Results:
1) Using blocking Sends - The first send returns 10, which is the buffer
size. Future Sends, return 0 and no exception. This behavior seems not to
fly with the doco. The send should block until 10 bytes are sent to kernel
mode or throw an exception, *not return 0. Note the socket is in blocking
mode (default setting).

Has nothing to do with blocking sends. Reverse the order in which you call them, i.e. async before blocking, and you'll see the
same results. Also, the docs say that when the send method succeeds it is not an indication that the data was actually received.
About Send returning zero, see #3.

http://msdn.microsoft.com/library/d...mm5/html/wce50lrfsetsockoptWindowsSockets.asp
2) Using async BeginSend gives completely different results. The first
EndSend returns 10 as above. The second BeginSend returns a null
IAsyncResult and sets SocketError to "ConnectionReset". I find this
behavior very strange. BeginSend should never return a null IAsyncResult as
that FooBars the async pattern (it should always return IAsync or
exception). It should save the exception for the EndSend call. Second, why
does it set SocketError to ConnectionReset, when blocking Send does not seem
to care. The two behaviors should be consistent.

I agree about the null IAsyncResult being poorly designed, but you can simply check that it's not null before calling EndSend. A
null IAsyncResult indicates that something went wrong and that you should check the SocketError. Also, they are consistent. In my
testing both async and blocking Send use the ConnectionReset constant to indicate the same failure.

Both blocking Send and Async Send will return SocketError.ConnectionReset after the connection has been reset. In other words, it
doesn't matter which of the Sends, async or blocking, is executed first. Since the server has shutdown receiving on that socket the
first call to Send (async or blocking) will reset the connection. Subsequent Sends will fail, as you've witnessed. As the docs
stated, the first succeeding call to Send (either async or blocking) does not indicate that the server actually received the data.
For this reason you should design software that acknowledges transmission on a higher level, such as in a custom communications
protocol.
3) Also, what is the point of SocketError being an out parm? It should just
be included in the SocketException and thrown - no?

You have the choice of not using a SocketError argument by using an overload of Send that doesn't accept the out parameter. A
SocketException will be thrown for these overloads instead. Use the SocketException.SocketErrorCode property to retrieve the
SocketError from the exception.


The bottom line is that you must perform some operation on the Socket so that it can determine the state of the connection. The
state is not dynamic so that an action on one end point automatically affects the other. By shutting down Receive on the server end
point you are basically setting up a wall. Only by attempting to Send data will the socket update its internal state so that
subsequent calls will fail. It would be nice, however, if the first send failed as well but I see that from the docs this "design"
was by choice.

Here's your code revised in a manner that will hopefully illustrate what I've written above:

private static readonly EventWaitHandle waitForAsyncSend = new EventWaitHandle(false, EventResetMode.AutoReset);

private static void SocketTest()
{
// Server.
TcpListener l = new TcpListener(IPAddress.Any, 9001);
l.Start();
new Thread(
delegate()
{
using (Socket socket = l.AcceptSocket())
{
socket.Shutdown(SocketShutdown.Receive);

WriteLine("Server shutdown receive.");

waitForAsyncSend.WaitOne();

// expecting 4 blocks of 10 bytes each
WriteLine("Server about to poll for data");

// examine first batch
if (socket.Poll(8000000, SelectMode.SelectRead))
{
byte[] buffer = new byte[10];

try
{
int read = socket.Receive(buffer);

WriteLine("Server read bytes: " + read);
}
catch (SocketException ex)
{
if (ex.ErrorCode == 10053)
{
WriteLine("Server read error: " + ex.SocketErrorCode.ToString());
}
else
throw ex;
}
}

WriteLine("Closing client connection");
}

WriteLine("Server stopping");
l.Stop();
}).Start();

// Client.
byte[] buf = new byte[10];

using (Socket s = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp))
{
WriteLine("Blocking mode:{0}", s.Blocking);
s.Connect(IPAddress.Loopback, 9001);
Thread.Sleep(2000);
SocketError se = SocketError.Success;
int read = 0;

// Note the different results with async send.
IAsyncResult ar = s.BeginSend(buf, 0, buf.Length, SocketFlags.None, out se, null, null);
WriteLine("Non-blocking SocketError: " + se.ToString());

if (ar != null)
read = s.EndSend(ar); // ar is null.

WriteLine("Non-blocking bytes written to kernel:{0}", read);

waitForAsyncSend.Set();

Thread.Sleep(2000);

for (int i = 0; i < 3; i++)
{
read = s.Send(buf, 0, buf.Length, SocketFlags.None, out se);
WriteLine("Blocking bytes written to kernel:{0}\r\nSocketError:{1}", read, se);
Thread.Sleep(500);
}

Console.WriteLine("Click 'Enter' to exit");
Console.ReadLine();
}
}

private static readonly object sync = new object();

private static void WriteLine(string message)
{
lock (sync)
{
Console.WriteLine(message);
Console.WriteLine();
}
}

private static void WriteLine(string format, params object[] args)
{
lock (sync)
{
Console.WriteLine(format, args);
Console.WriteLine();
}
}
 
W

William Stacey [MVP]

| - after send returning 0 do you check returned SocketError? Is it
SocketError.Success?
Yes, SocketError is ConnectionReset.

- why Send and BeginSend have different flags? ( Send has
SocketFlags.Partial )
I was just trying stuff and did not change it back - result the same.
Here is the updated code, just put in in a button block to test.

private void button6_Click(object sender, EventArgs e)
{
// Server.
TcpListener l = new TcpListener(IPAddress.Any, 9001);
l.Start();
new Thread(
delegate()
{
using (NetPortNew srvClient = new
NetPortNew(l.AcceptSocket(), "srvClient"))
{
srvClient.Shutdown(SocketShutdown.Receive);
Thread.Sleep(2000);
}
l.Stop();
}).Start();

// Client.
byte[] buf = new byte[10];
using (Socket s = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp))
{
Console.WriteLine("Blocking mode:{0}", s.Blocking);
s.Connect(IPAddress.Parse("192.168.1.1"), 9001);
Thread.Sleep(2000);
SocketError se = SocketError.Success;
int read = 0;

for (int i = 0; i < 3; i++)
{
read = s.Send(buf, 0, buf.Length, SocketFlags.None, out
se);
Console.WriteLine("Bytes written to kernel:{0} SE:{1}",
read, se);
Thread.Sleep(100);
}
// Note the different results with async send.
IAsyncResult ar = s.BeginSend(buf, 0, buf.Length,
SocketFlags.None, out se, null, null);
Console.WriteLine("BeginSend.");
read = s.EndSend(ar); // ar is null.
Console.WriteLine("Bytes written to kernel:{0}", read);
}
}

--
William Stacey [MVP]

| Hello, William!
|
| WSM> // Server.
| WSM> TcpListener l = new TcpListener(IPAddress.Any, 9001);
| WSM> l.Start();
| WSM> new Thread(
| WSM> delegate()
| WSM> {
| WSM> using (NetPortNew srvClient = new
| WSM> NetPortNew(l.AcceptSocket(), "srvClient"))
| WSM> {
| WSM> srvClient.Shutdown(SocketShutdown.Receive);
| WSM> Thread.Sleep(2000);
| WSM> }
| WSM> l.Stop();
| WSM> }).Start();
|
| WSM> // Client.
| WSM> byte[] buf = new byte[10];
| WSM> using (Socket s = new Socket(AddressFamily.InterNetwork,
| WSM> SocketType.Stream, ProtocolType.Tcp))
| WSM> {
| WSM> Console.WriteLine("Blocking mode:{0}", s.Blocking);
| WSM> s.Connect(IPAddress.Loopback, 9001);
| WSM> Thread.Sleep(2000);
| WSM> SocketError se = SocketError.Success;
| WSM> int read = 0;
|
| WSM> for (int i = 0; i < 3; i++)
| WSM> {
| WSM> read = s.Send(buf, 0, buf.Length,
SocketFlags.Partial,
| WSM> out se);
| WSM> Console.WriteLine("Bytes written to kernel:{0}",
read);
| WSM> Thread.Sleep(100);
| WSM> }
| WSM> // Note the different results with async send.
| WSM> IAsyncResult ar = s.BeginSend(buf, 0, buf.Length,
| WSM> SocketFlags.None, out se, null, null);
| WSM> Console.WriteLine("BeginSend.");
| WSM> read = s.EndSend(ar); // ar is null.
| WSM> Console.WriteLine("Bytes written to kernel:{0}",
| WSM> read);
| WSM> }
|
| I have some comments on the code...
|
| - after send returning 0 do you check returned SocketError? Is it
SocketError.Success?
| - why Send and BeginSend have different flags? ( Send has
SocketFlags.Partial )
|
| - Indeed, docs say nothing about BeginSend returning null. But, using
Reflector, we can see
| such code, where "result1" is returned as IAsyncResult.
| if ((errorCode != SocketError.Success) && (errorCode !=
SocketError.IOPending)) {
| result1 = null;
| }
| else {
| result1.FinishPostingAsyncOp(ref this.Caches.SendClosureCache);
| }
|
| - about those sent 10 bytes... Sender at first has no clue about what's
going on the server.
| Then it sends 10 bytes and with ack packet from the server it has to
receive server's status ( via tcp flags ).
| For e.g. if server closed connection then ConnectionReset can be set.
BeginSend seems to behave well (
| first send - ok, second one - error ). About Send(... ) do you check "se"
returned?
|
| --
| Regards, Vadym Stetsyak
| www: http://vadmyst.blogspot.com
 
W

William Stacey [MVP]

I see what they did with the two version of send now. Send with the "out"
error overload should probably be changed to "bool TrySend(...)" to match
with current standards. The null IAsyncResult thing still bugs me. The
other thing we discover here via imperitive evidence is that
shutdown.receive will never be sent by server unless it can piggyback on an
ACK reply or an outgoing message. Something I must remember. Cheers.

--
William Stacey [MVP]

| Hi William,
|
| > See some strange results on Send and peer with a closed Receive. Setup
a
| > test harness. Server accepts socket, then just does a Shutdown.Receive
| > right away and waits. The client socket does both blocking Sends and
| > BeginSends to see the difference in behavior.
| >
| > Results:
| > 1) Using blocking Sends - The first send returns 10, which is the buffer
| > size. Future Sends, return 0 and no exception. This behavior seems not
to
| > fly with the doco. The send should block until 10 bytes are sent to
kernel
| > mode or throw an exception, *not return 0. Note the socket is in
blocking
| > mode (default setting).
|
| Has nothing to do with blocking sends. Reverse the order in which you
call them, i.e. async before blocking, and you'll see the
| same results. Also, the docs say that when the send method succeeds it is
not an indication that the data was actually received.
| About Send returning zero, see #3.
|
|
http://msdn.microsoft.com/library/d...mm5/html/wce50lrfsetsockoptWindowsSockets.asp
|
| > 2) Using async BeginSend gives completely different results. The first
| > EndSend returns 10 as above. The second BeginSend returns a null
| > IAsyncResult and sets SocketError to "ConnectionReset". I find this
| > behavior very strange. BeginSend should never return a null
IAsyncResult as
| > that FooBars the async pattern (it should always return IAsync or
| > exception). It should save the exception for the EndSend call. Second,
why
| > does it set SocketError to ConnectionReset, when blocking Send does not
seem
| > to care. The two behaviors should be consistent.
|
| I agree about the null IAsyncResult being poorly designed, but you can
simply check that it's not null before calling EndSend. A
| null IAsyncResult indicates that something went wrong and that you should
check the SocketError. Also, they are consistent. In my
| testing both async and blocking Send use the ConnectionReset constant to
indicate the same failure.
|
| Both blocking Send and Async Send will return SocketError.ConnectionReset
after the connection has been reset. In other words, it
| doesn't matter which of the Sends, async or blocking, is executed first.
Since the server has shutdown receiving on that socket the
| first call to Send (async or blocking) will reset the connection.
Subsequent Sends will fail, as you've witnessed. As the docs
| stated, the first succeeding call to Send (either async or blocking) does
not indicate that the server actually received the data.
| For this reason you should design software that acknowledges transmission
on a higher level, such as in a custom communications
| protocol.
|
| > 3) Also, what is the point of SocketError being an out parm? It should
just
| > be included in the SocketException and thrown - no?
|
| You have the choice of not using a SocketError argument by using an
overload of Send that doesn't accept the out parameter. A
| SocketException will be thrown for these overloads instead. Use the
SocketException.SocketErrorCode property to retrieve the
| SocketError from the exception.
|
|
| The bottom line is that you must perform some operation on the Socket so
that it can determine the state of the connection. The
| state is not dynamic so that an action on one end point automatically
affects the other. By shutting down Receive on the server end
| point you are basically setting up a wall. Only by attempting to Send
data will the socket update its internal state so that
| subsequent calls will fail. It would be nice, however, if the first send
failed as well but I see that from the docs this "design"
| was by choice.
|
| Here's your code revised in a manner that will hopefully illustrate what
I've written above:
|
| private static readonly EventWaitHandle waitForAsyncSend = new
EventWaitHandle(false, EventResetMode.AutoReset);
|
| private static void SocketTest()
| {
| // Server.
| TcpListener l = new TcpListener(IPAddress.Any, 9001);
| l.Start();
| new Thread(
| delegate()
| {
| using (Socket socket = l.AcceptSocket())
| {
| socket.Shutdown(SocketShutdown.Receive);
|
| WriteLine("Server shutdown receive.");
|
| waitForAsyncSend.WaitOne();
|
| // expecting 4 blocks of 10 bytes each
| WriteLine("Server about to poll for data");
|
| // examine first batch
| if (socket.Poll(8000000, SelectMode.SelectRead))
| {
| byte[] buffer = new byte[10];
|
| try
| {
| int read = socket.Receive(buffer);
|
| WriteLine("Server read bytes: " + read);
| }
| catch (SocketException ex)
| {
| if (ex.ErrorCode == 10053)
| {
| WriteLine("Server read error: " + ex.SocketErrorCode.ToString());
| }
| else
| throw ex;
| }
| }
|
| WriteLine("Closing client connection");
| }
|
| WriteLine("Server stopping");
| l.Stop();
| }).Start();
|
| // Client.
| byte[] buf = new byte[10];
|
| using (Socket s = new Socket(AddressFamily.InterNetwork,
| SocketType.Stream, ProtocolType.Tcp))
| {
| WriteLine("Blocking mode:{0}", s.Blocking);
| s.Connect(IPAddress.Loopback, 9001);
| Thread.Sleep(2000);
| SocketError se = SocketError.Success;
| int read = 0;
|
| // Note the different results with async send.
| IAsyncResult ar = s.BeginSend(buf, 0, buf.Length, SocketFlags.None, out
se, null, null);
| WriteLine("Non-blocking SocketError: " + se.ToString());
|
| if (ar != null)
| read = s.EndSend(ar); // ar is null.
|
| WriteLine("Non-blocking bytes written to kernel:{0}", read);
|
| waitForAsyncSend.Set();
|
| Thread.Sleep(2000);
|
| for (int i = 0; i < 3; i++)
| {
| read = s.Send(buf, 0, buf.Length, SocketFlags.None, out se);
| WriteLine("Blocking bytes written to kernel:{0}\r\nSocketError:{1}",
read, se);
| Thread.Sleep(500);
| }
|
| Console.WriteLine("Click 'Enter' to exit");
| Console.ReadLine();
| }
| }
|
| private static readonly object sync = new object();
|
| private static void WriteLine(string message)
| {
| lock (sync)
| {
| Console.WriteLine(message);
| Console.WriteLine();
| }
| }
|
| private static void WriteLine(string format, params object[] args)
| {
| lock (sync)
| {
| Console.WriteLine(format, args);
| Console.WriteLine();
| }
| }
|
| --
| Dave Sexton
|
|
 
D

Dave Sexton

Hi William,
I see what they did with the two version of send now. Send with the "out"
error overload should probably be changed to "bool TrySend(...)" to match
with current standards. The null IAsyncResult thing still bugs me
Agreed.

The other thing we discover here via imperitive evidence is that
shutdown.receive will never be sent by server unless it can piggyback on an
ACK reply or an outgoing message. Something I must remember. Cheers.

I haven't tried using an outgoing message. Did you test that?
 
W

William Stacey [MVP]

I guess the bit is not set in a send either - only the ACK. So I guess that
means you must always do at least two sends (at the client) before you will
notice a shutdown receive at server.

--
William Stacey [MVP]

| Hi William,
|
| >I see what they did with the two version of send now. Send with the
"out"
| > error overload should probably be changed to "bool TrySend(...)" to
match
| > with current standards. The null IAsyncResult thing still bugs me
|
| Agreed.
|
| > The other thing we discover here via imperitive evidence is that
| > shutdown.receive will never be sent by server unless it can piggyback on
an
| > ACK reply or an outgoing message. Something I must remember. Cheers.
|
| I haven't tried using an outgoing message. Did you test that?
|
| --
| Dave Sexton
|
|
 
V

Vadym Stetsyak

Hello, William!

WSM> I guess the bit is not set in a send either - only the ACK. So I
WSM> guess that means you must always do at least two sends (at the client)
WSM> before you will notice a shutdown receive at server.

There is an interesting API in the winsock - WSASendDisconnect/WSARecvDisconnect.
The result is virtually the same as with shutdown, but results in one call...
--
Regards, Vadym Stetsyak
www: http://vadmyst.blogspot.com
 
A

Alan J. McFarlane

I guess the bit is not set in a send either - only the ACK. So I
guess that means you must always do at least two sends (at the
client) before you will notice a shutdown receive at server.
What "bit"? There is *no* flag for Receive_Closed! There are two
relevant flags: the FIN flag which means Finished_Sending, and RST,
which means Reset: in general means 'I've no such connection, please
delete that connection from your list'. The flags SYN, ACK, PSH, and
URG have no part to play here.

So when the server does "socket.Shutdown(SocketShutdown.Receive);", it
can't do anything based on that. It just sits dumb waiting for another
action. Then eventually a packet comes from the peer, and that will
contain data, so the server responds RST: 'I can't handle that'. This
is I presume what Dave meant when he said "you are basically setting up
a wall": no signal, just that any data received will crash into the
wall. However he wasn't quite correct in saying 'It would be nice,
however, if the first send failed as well but I see that from the docs
this "design" was by choice.' The software writers have _no_ choice in
this, the TCP protocol doesn't allow such a behaviour.


So, remembering that the server has sent nothing after the local
application did SocketShutdown.Receive. Lets look now at what happens
from the aspect of the client side. Remember that TCP makes no
guarantee of maintaining send boundaries etc. So the client could
buffer up multiple send before deciding to send a packet, that packet
then works its way across the network, meanwhile the client application
could be doing more sends, which are likely buffered up, and maybe sent
at some point, and again the client application could be doing more
sends, and even blocking or non-blocking :-,) on a receive.

And at some point the first send now reaches the server, who responds
with a packet with the RST flag set. That then makes its way back
across the network. Again the client application can be doing sends,
and maybe some packets are sent too. Then the RST reaches the client
device, and works its way up through the stack. Boom! Now and only now
is ConnectionReset returned on every subsequent send or receive that the
client application makes.


So two things about TCP, firstly SocketShutdown.Receive cannot be
signalled. That's a very rare and odd case that there's no need to
cover it: 'I've more to send, but I don't want to hear any error
responses from you'! Odd, whereas the opposite is common: 'I've now
finished sending all I have, but I'm still listening for any feedback
you wish to send me.'

Secondly, that *errors* on the connection can only be signalled on later
send/receive calls. Errors are only apparent after buffered data has
been sent and a error response has been received from the server across
the network, or if the network is down for instance that 'I've had to
retry sending data five (say) times and I've now given up'.


Note that SocketShutdown.Send, is signalled with flag FIN, which is
'data' so it is sent in a packet with or after the last byte in the send
buffer has been sent. To get an error earlier some protocols send
regular packets to say 'are you alive?' (for instance HDLC, IrDA, SNA,
SPX (?my memory is fading)). But due to the philosophy of TCP, that, to
try and ride over network failure do not send any packets unless there's
data to be sent, no such packets are sent.

I recommend that you put your server and client on different machines
and look at the traffic between then with a network analyser. What's
happening below the APIs can then be seen.
 
D

Dave Sexton

Hi Alan,
This is I presume what Dave meant when he said "you are basically setting up a wall"

That is what I meant. I was just speaking from experience, so I didn't want to make any technical assumptions using terminology
that I didn't fully understand.
However he wasn't quite correct in saying 'It would be nice, however, if the first send failed as well but I see that from the
docs this "design" was by choice.' The software writers have _no_ choice in this, the TCP protocol doesn't allow such a behaviour

I understand that this limitation is indeed in the TCP protocol itself. What I don't understand is why. I still think it would be
nice if the first send would fail since the RST flag is in the stack anyway. If you look at William's example with my revisions,
you'll see that each Send, including the call to BeginSend, is executed sequentially. If RST is at the top of the stack before the
next call to Send then why can't the first call to Send (or BeginSend) just fail instead of returning to the caller? And what kind
of "connected" protocol is TCP anyway if it acts "disconnected" in so many ways? And if shutting down Send behaves in some manner
shouldn't shutting down Receive behave in a similar manner if just to preserve consistency in the protocol?

You've posted some interesting stuff. I'm going to have to read about the protocol itself now to fully appreciate it. Thanks a
lot!

I'm thinking about starting here:

TCP on Wikipedia.org
http://en.wikipedia.org/wiki/Transmission_Control_Protocol

Any suggestions on other reading material for this weekend?
 
W

William Stacey [MVP]

| I understand that this limitation is indeed in the TCP protocol itself.
What I don't understand is why. I still think it would be
| nice if the first send would fail since the RST flag is in the stack
anyway. If you look at William's example with my revisions,
| you'll see that each Send, including the call to BeginSend, is executed
sequentially. If RST is at the top of the stack before the
| next call to Send then why can't the first call to Send (or BeginSend)
just fail instead of returning to the caller?

AFAICT, RST is not "seen" by the client until the first ACK to client *after
a Shutdown.Receive by the server. So I assume you may not even see the RST
until the 3rd send depending on speed, etc. Thing I don't understand yet is
why RST is not set in the header of outgoing data if the server does a send
after Receive is closed? Or why the server even lets you do a send after a
Shutdown.Receive if ultimately it forces both sides of the client down
anyway?

Note: I have no compelling reason I want to do this, other then experiments
and noting behavior and exceptions. However it would seem like a use for
closing receive on server would be a stock ticker app. The client sends a
single request message to server. The server verifies and closes Receive -
as if to say "I do not expect any more "data" messages (i.e. not control
packets) from client and will be error.". And then server just streams data
to client one-way and then closes send after requested number of stocks or
some N factor of stocks or time and closes socket. The client reads until
0, then just closes socket. Naturally, it is easy to refactor this to do
normal shutdown behavior.

--wjs
 
D

Dave Sexton

Hi William,

[To summarize: we are discussing the mechanisms used by the TCP protocol when an end point shuts down receiving on the socket and
how that action affects its counterpart with regards to immediate changes in state and future changes in state]
AFAICT, RST is not "seen" by the client until the first ACK to client *after
a Shutdown.Receive by the server. So I assume you may not even see the RST
until the 3rd send depending on speed, etc.

Your explanation seems to be accurate with respect to my test results and previous experience with sockets, however Alan's
explanation led me to believe that a different mechanism was in place. I am referring specifically to the following statement of
Alan's:

In your test case there was no concurrent sending, so I assumed that on a blocking send with no concurrent activity that the RST
flag would "make its way back across the network" immediately from Alan's statements.

Interesting that the RST made it back into the client stack but ConnectionReset is returned only on every subsequent request. My
previous statements were referring to this particular statement of Alan's. Why not just fail the initial send if the RST flag has
already been received, if in fact it is received?
Thing I don't understand yet is
why RST is not set in the header of outgoing data if the server does a send
after Receive is closed? Or why the server even lets you do a send after a
Shutdown.Receive if ultimately it forces both sides of the client down
anyway?
Note: I have no compelling reason I want to do this, other then experiments
and noting behavior and exceptions. However it would seem like a use for
closing receive on server would be a stock ticker app. The client sends a
single request message to server. The server verifies and closes Receive -
as if to say "I do not expect any more "data" messages (i.e. not control
packets) from client and will be error.". And then server just streams data
to client one-way and then closes send after requested number of stocks or
some N factor of stocks or time and closes socket. The client reads until
0, then just closes socket. Naturally, it is easy to refactor this to do
normal shutdown behavior.

I can see how that might be useful to reduce the amount of network traffic since the client doesn't expect any responses anyway.
Unfortunately, the server has to send something at least once to find out that it shouldn't send anything again. Therefore, if you
design a protocol on top of TCP as such, your choices are then limited to either "all clients accept data" or "all clients do not
accept data" unless an error on the server is acceptable when trying to respond with data.

I was thinking that a forward-only connection could be useful to circumvent potential errors on a network topology that prevents
responses from being received by the counterpart. By shutting down the receive functionality the end point is saying, "Don't even
try to send any data 'cause I know that it won't get to me". Although I guess this won't work in TCP since the counterpart has to
Send data anyway in order to find out that little bit of information. And the sender won't know whether the first Send actually
succeeded or was just sucked up by the RST mechanism without a higher-level protocol in place to respond with an acknowledgement.

Does anybody know what the intended purpose was of the shutdown-receive flag when it was designed? i.e., What usage scenarios did
the designers have in mind?

I guess the usefulness of my participation in this discussion is moot without having read a substantial amount of the technical
specification for TCP. I'm just trying to understand what I've already experienced by means of a more technical explanation. If
I'm not making any sense please let me know.

Thanks for the link in your other response - I'll take a look.
 
D

Dave Sexton

Hi William,

Thanks.

Interesting document but I'm looking for information about TCP specifically. I already have knowledge and experience with Sockets
but I'm unclear as to the underlying mechanisms causing the behavior that I've witnessed.

I'm not looking for just protocol specs either, of course. Real-world examples and explanations of the different messages would be
nice.

The Wikipedia article I posted seems excellent.

I found this link in that article:
http://condor.depaul.edu/~jkristof/technotes/tcp.html

Strangely enough, neither article even mentions the term "shutdown", so I'll have to search harder for documentation that will apply
to our discussion.
 
W

William Stacey [MVP]

Well if your really into it the TCP books I, II, III are great and worth
getting. I read these years ago and forgot most of this stuff - need to
re-read. One of best books I have on this subject is "Windows Sockets
Network Programming" by Bob Quinn/Dave Shute. It also has tons of threading
related stuff and patterns. Samples in C, but still good down and dirty
stuff that you can apply to any program and very readable. This book
converted to .Net would be great.

--
William Stacey [MVP]

| Hi William,
|
| Thanks.
|
| Interesting document but I'm looking for information about TCP
specifically. I already have knowledge and experience with Sockets
| but I'm unclear as to the underlying mechanisms causing the behavior that
I've witnessed.
|
| I'm not looking for just protocol specs either, of course. Real-world
examples and explanations of the different messages would be
| nice.
|
| The Wikipedia article I posted seems excellent.
|
| I found this link in that article:
| http://condor.depaul.edu/~jkristof/technotes/tcp.html
|
| Strangely enough, neither article even mentions the term "shutdown", so
I'll have to search harder for documentation that will apply
| to our discussion.
|
| --
| Dave Sexton
|
| >| Any suggestions on other reading material for this weekend?
| >
| > http://tangentsoft.net/wskfaq/
| >
| >
|
|
 
D

Dave Sexton

Hi William,

I am "into it"!

Is this TCP book I?
http://search.barnesandnoble.com/booksearch/isbnInquiry.asp?z=y&EAN=9780201633467&itm=2

It was published in '93. I was hoping for something in this millenium. :)
(Has much changed in TCP/IP over the last decade and a half?)

I found "Windows Sockets Network Programming" (1995) at Barnes & Nobel, in case anyone is interested.

I'll put that book on my reading wish list, although I feel like I'm going about this backwards. I should have read that book a
while ago too :)

Thanks.
 
W

William Stacey [MVP]

| I found "Windows Sockets Network Programming" (1995) at Barnes & Nobel, in
case anyone is interested.

Sorry, after looking at it again, it is probably not right and a bit dated.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top