NetworkStream.Write asynchronous issue - c#

I have a problem with writing to a NetworkStream in C#. From MSDN i read:
The Write method blocks until the requested number of bytes is sent or
a SocketException is thrown
Well - in my case, it behaves like an asynchronous method. Thread is not being blocked.
Here is a code sample, to enlighten situation a bit:
TcpClient tcpcl = new TcpClient("192.168.1.128", 1337);
NetworkStream netst = tcpcl.GetStream();
byte[] will_send = File.ReadAllBytes(#"large_file_120_MB.mp4");
Console.WriteLine("Starting transmission...");
netst.Write(will_send, 0, will_send.Length);
Console.WriteLine("File has been sent !");
(... later instructions ...)
Result from console after 1 second of execution:
Starting transmission...
File has been sent !
Second message shows immediately. Later instructions are being executed.
Meanwhile server still receives the file and on its side everything works well. It gets better - if i kill sending program, during transmission, receiving won't stop. Degugger shows clearly that app has ended entirely. However few more megabytes will still be transmitted, until receiving stops completely.
So my question - is there a way to block main thread, until Write method is finished ?

The MSDN description should perhaps be better read as
The Write method blocks until the requested number of bytes is
written to the local network buffer or a SocketException is thrown
i.e. The write will return before the entire file has been successfully received at the other end.
This also means when you close your application anything currently in the network buffer may continue to be sent.
The only way to block the main thread until the entire file has been succesfully received is to potentially use asynchronous sockets and once the send is complete wait until some sort of confirmation is sent by the receiving end, which you would have to implement.

Related

Exception when writing to socket: Unable to write data to transport connection

I am developing a client server application using sockets in C#, It is a multi Threading application for sure, the strange thing is the following:
The connection is closed from one thread when the remote client asks, in this exact moment the write operation throws this exception:
unable to write data to transport connection: a blocking operation was interrupted by a call to WSACancelblockingcall
Actually I am writing 64 byte each 20 minutes, but the strange thing is that the above exception is thrown each time the connection is closed, that means the write operation is taking very very long time to complete to the extend that the operation is always stopped by the connection close, is this a problem in the network stack?, The more strange thing is that this problem happens only with one client, and still happening for more than a week,so it is not temporary.
Any suggestions? is this a hardware problem? is this a TCP protocol problem? any one had a similar problem and had found a solution?
EDIT:
pseudo code to illustrate the issue:
First thread:
while(true)
{
if (some condition)
close connection;
}
second thread:
while(true)
{
sleep for 20 minutes
write(array of 64 bytes) //blocks for a very long period of time
}
Actually I have found the problem:
The write method of NetwrokStream blocks until it can successfully write data to the underlying socket buffer (although many people disagree with this but the experiment proves that it is correct). When the buffer gets full the write method blocks until some data is sent and there is a room for the data to be written to the buffer, but when the network connection is slow and has issues or when the reader reads data slowly the buffer gets full and write method blocks for a long period of time.

What conditions cause NetworkStream.Write to block?

Will NetworkStream.Write block only until it places the data to be sent into the TCP send buffer, or will it block until the data is actually ACK'd by the receiving host?
Note: The socket is configured for blocking I/O.
Edit: Whoops, there's no such thing as TcpClient.Write of course! We all understood we were talking about TcpClient.GetStream().Write, which is actually NetworkStream.Write!
Unless .net is using something other than winsock, then according to the winsock reference:
The successful completion of a send function does not indicate that the data was successfully delivered and received to the recipient. This function only indicates the data was successfully sent.
If no buffer space is available within the transport system to hold the data to be transmitted, send will block unless the socket has been placed in nonblocking mode. On nonblocking stream oriented sockets, the number of bytes written can be between 1 and the requested length, depending on buffer availability on both the client and server computers.
Assuming that write is calling send underneath, then a strict interpretation of the winsock documentation would indicate that there is no gurantee that the data made it to the other end of the pipe when it returns.
Here is the link to the winsock docs I am quoting from:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms741416(v=VS.85).aspx
I disagree with both answers [that state it blocks]. Writing to TCP/IP socket does not block unless the underlying buffer is already full of unacknowledge data. Generally, it doesn't block but just gets handed off to the TCP implementation. But of course now I have to go track down some references to back this up :)
From SO
TcpClient.Write will block until the packet buffer has been flushed to the network and the appropriate ACK(s) have been received. You'll notice that a dropped connection will usually end up throwing an exception on the Write operation, since it waits for the ACK but doesn't get one within the defined timeout period.

How to wait until stream write is done

I have a server app that listens for connections on port 8888. I am also creating the client application. It is a simple application the only hard thing about it is managing multiple connections. so I just need to send files between computers so the way I do that, I don't know if it is wright but it works maybe you guys can correct me. here is my algorithm when sending the file:
NetworkStream stream = \\ initialize it
while(someCondition)
{
// first I open the file for reading and read chunks of it
byte[] chunk = fileRead(file, indexStart, indexEnd) // I have a similar method this is just to illustate my point
stream.Write(chunk, \\other params)
// since I often send large files it will be nice if I can wait here
// until the stream.Write is done. when debuging this the while loop
// executes several times then it waits.
}
and on the other side I read bytes from that stream and write it to a file.
I also need to wait sometimes because I send multiple files and I want to make sure that the first file has been sent before moving to the next. I know I can solve this by using the stream.Read method once the transfer has been done. and sending data back from the client. but sometimes I believe it will be helpful to know when the stream.write is done.
Edit
ok so based on your answers I can for example send to the client the number of bytes that I am planing to send. and once the client recives that many bytes it means it is done. But my question is if this is efficient. I mean doing something like
on the server:
writing data "sending the file length"
read data "check to see if the client received the length" (expecting a string ok for example)
write data "tel the client the name of the file"
read data "check to see if the client recived the name of the file"
write data "start sending chuncks of the file"
read data "wait until client replies with the string ok for example"
The write is complete when the line
stream.Write(chunk, \\other params)
completes. It's worth noting that this does not imply that the other end has received anything. In fact, immediately subsequent to that line, the data is likely to be in some buffer on the sending machine. That means that it's now out of your control. If you want receipt confirmation, the remote end will have to let you know.
Stream.Write is synchronous, so it will always block your thread until the writing finishes.

Callbacks using asynchronous sockets

My asking is quite simple and is about asynchronous sockets, working with TCP protocol.
When I send some data with the "BeginSend" method, when will the callback be called?
Will it be called when the data is just sent out to the network, or when we are ensured that the data as reached its destination (like it should be regarding to TCP specification) ?
Thanks for your answers.
KiTe.
ps : I'm sorry if my english is a bit bad ^^.
From MSDN:
"When your application calls BeginSend, the system will use a separate thread to execute the specified callback method, and will block on EndSend until the Socket sends the number of bytes requested or throws an exception."
"The successful completion of a send does not indicate that the data was successfully delivered. If no buffer space is available within the transport system to hold the data to be transmitted, send will block unless the socket has been placed in nonblocking mode."
http://msdn.microsoft.com/en-us/library/38dxf7kt.aspx
When the callback is called you can be sure that the data has been cleared from the output buffer (the asynchronous operation uses a separate thread to ensure that your calling thread is not blocked in case there is no room in the transmit buffer and it has to wait to send the date) and that it will reach it's destination - but not that it has reached it yet.
Because of the TCP protocol's nature however, you can be sure (well, I guess almost sure) that it will get to the destination, eventually.
However, for timing purposes you should not consider the time of the callback as being the same as the time the data reaches the other party.

NetworkStream.Write returns immediately - how can I tell when it has finished sending data?

Despite the documentation, NetworkStream.Write does not appear to wait until the data has been sent. Instead, it waits until the data has been copied to a buffer and then returns. That buffer is transmitted in the background.
This is the code I have at the moment. Whether I use ns.Write or ns.BeginWrite doesn't matter - both return immediately. The EndWrite also returns immediately (which makes sense since it is writing to the send buffer, not writing to the network).
bool done;
void SendData(TcpClient tcp, byte[] data)
{
NetworkStream ns = tcp.GetStream();
done = false;
ns.BeginWrite(bytWriteBuffer, 0, data.Length, myWriteCallBack, ns);
while (done == false) Thread.Sleep(10);
}
 
public void myWriteCallBack(IAsyncResult ar)
{
NetworkStream ns = (NetworkStream)ar.AsyncState;
ns.EndWrite(ar);
done = true;
}
How can I tell when the data has actually been sent to the client?
I want to wait for 10 seconds(for example) for a response from the server after sending my data otherwise I'll assume something was wrong. If it takes 15 seconds to send my data, then it will always timeout since I can only start counting from when NetworkStream.Write returns - which is before the data has been sent. I want to start counting 10 seconds from when the data has left my network card.
The amount of data and the time to send it could vary - it could take 1 second to send it, it could take 10 seconds to send it, it could take a minute to send it. The server does send an response when it has received the data (it's a smtp server), but I don't want to wait forever if my data was malformed and the response will never come, which is why I need to know if I'm waiting for the data to be sent, or if I'm waiting for the server to respond.
I might want to show the status to the user - I'd like to show "sending data to server", and "waiting for response from server" - how could I do that?
I'm not a C# programmer, but the way you've asked this question is slightly misleading. The only way to know when your data has been "received", for any useful definition of "received", is to have a specific acknowledgment message in your protocol which indicates the data has been fully processed.
The data does not "leave" your network card, exactly. The best way to think of your program's relationship to the network is:
your program -> lots of confusing stuff -> the peer program
A list of things that might be in the "lots of confusing stuff":
the CLR
the operating system kernel
a virtualized network interface
a switch
a software firewall
a hardware firewall
a router performing network address translation
a router on the peer's end performing network address translation
So, if you are on a virtual machine, which is hosted under a different operating system, that has a software firewall which is controlling the virtual machine's network behavior - when has the data "really" left your network card? Even in the best case scenario, many of these components may drop a packet, which your network card will need to re-transmit. Has it "left" your network card when the first (unsuccessful) attempt has been made? Most networking APIs would say no, it hasn't been "sent" until the other end has sent a TCP acknowledgement.
That said, the documentation for NetworkStream.Write seems to indicate that it will not return until it has at least initiated the 'send' operation:
The Write method blocks until the requested number of bytes is sent or a SocketException is thrown.
Of course, "is sent" is somewhat vague for the reasons I gave above. There's also the possibility that the data will be "really" sent by your program and received by the peer program, but the peer will crash or otherwise not actually process the data. So you should do a Write followed by a Read of a message that will only be emitted by your peer when it has actually processed the message.
TCP is a "reliable" protocol, which means the data will be received at the other end if there are no socket errors. I have seen numerous efforts at second-guessing TCP with a higher level application confirmation, but IMHO this is usually a waste of time and bandwidth.
Typically the problem you describe is handled through normal client/server design, which in its simplest form goes like this...
The client sends a request to the server and does a blocking read on the socket waiting for some kind of response. If there is a problem with the TCP connection then that read will abort. The client should also use a timeout to detect any non-network related issue with the server. If the request fails or times out then the client can retry, report an error, etc.
Once the server has processed the request and sent the response it usually no longer cares what happens - even if the socket goes away during the transaction - because it is up to the client to initiate any further interaction. Personally, I find it very comforting to be the server. :-)
In general, I would recommend sending an acknowledgment from the client anyway. That way you can be 100% sure the data was received, and received correctly.
If I had to guess, the NetworkStream considers the data to have been sent once it hands the buffer off to the Windows Socket. So, I'm not sure there's a way to accomplish what you want via TcpClient.
I can not think of a scenario where NetworkStream.Write wouldn't send the data to the server as soon as possible. Barring massive network congestion or disconnection, it should end up on the other end within a reasonable time. Is it possible that you have a protocol issue? For instance, with HTTP the request headers must end with a blank line, and the server will not send any response until one occurs -- does the protocol in use have a similar end-of-message characteristic?
Here's some cleaner code than your original version, removing the delegate, field, and Thread.Sleep. It preforms the exact same way functionally.
void SendData(TcpClient tcp, byte[] data) {
NetworkStream ns = tcp.GetStream();
// BUG?: should bytWriteBuffer == data?
IAsyncResult r = ns.BeginWrite(bytWriteBuffer, 0, data.Length, null, null);
r.AsyncWaitHandle.WaitOne();
ns.EndWrite(r);
}
Looks like the question was modified while I wrote the above. The .WaitOne() may help your timeout issue. It can be passed a timeout parameter. This is a lazy wait -- the thread will not be scheduled again until the result is finished, or the timeout expires.
I try to understand the intent of .NET NetworkStream designers, and they must design it this way. After Write, the data to send are no longer handled by .NET. Therefore, it is reasonable that Write returns immediately (and the data will be sent out from NIC some time soon).
So in your application design, you should follow this pattern other than trying to make it working your way. For example, use a longer time out before received any data from the NetworkStream can compensate the time consumed before your command leaving the NIC.
In all, it is bad practice to hard code a timeout value inside source files. If the timeout value is configurable at runtime, everything should work fine.
How about using the Flush() method.
ns.Flush()
That should ensure the data is written before continuing.
Bellow .net is windows sockets which use TCP.
TCP uses ACK packets to notify the sender the data has been transferred successfully.
So the sender machine knows when data has been transferred but there is no way (that I am aware of) to get that information in .net.
edit:
Just an idea, never tried:
Write() blocks only if sockets buffer is full. So if we lower that buffers size (SendBufferSize) to a very low value (8? 1? 0?) we may get what we want :)
Perhaps try setting
tcp.NoDelay = true

Categories

Resources