Re: Socket weirdness



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]

"Dave Sexton" <dave@jwa[remove.this]online.com> wrote in message
news:%23iRZwny2GHA.3516@xxxxxxxxxxxxxxxxxxxxxxx
| 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/default.asp?url=/library/en-us/wcecomm5/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
|
|


.



Relevant Pages

  • Re: recv blocks although socket is ready
    ... of the members of the interface in my network layer have blocking ... Only one has non-blocking semantics. ... call any socket operation and rely on the socket to block. ... Now I have to implement blocking myself in all other ...
    (microsoft.public.win32.programmer.networks)
  • Re: Async socket & active connections
    ... The "blocking = true" in the disconnect phase seems to solve the ... Socket and TcpClient, ... blocking connection somewhere down the line. ... 300K connections, enough to start worrying... ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Socket weirdness
    ... Server accepts socket, ... Using blocking Sends - The first send returns 10, ... Reverse the order in which you call them, i.e. async before blocking, and you'll see the ...
    (microsoft.public.dotnet.framework)
  • Re: recv blocks although socket is ready
    ... The problem is, that in blocking mode ... select sometimes reports the socket readable and then the following ... following call to recv() blocks. ...
    (microsoft.public.win32.programmer.networks)
  • Re: Non-blocking and semi-blocking Sockets class.
    ... There is an issues with sockets blocking and how to handle it. ... that could mean the server closed a connection for whatever reason. ... The loop uses a separate timer from the socket timeout timer. ... Anyone can suggest a good state machine design in Java? ...
    (comp.lang.java.programmer)