How to send files via tcp using TcpListener / Client? Problem with SocketException

I am developing a simple application for sending files over TCP using the TCPListener and TCPClient classes. Here is the code that sends the file.

Stop is a volatile boolean that helps stop the process at any time, and WRITE_BUFFER_SIZE can be changed at runtime (another mutable)

while (remaining > 0 && !stop) { DateTime current = DateTime.Now; int bufferSize = WRITTE_BUFFER_SIZE; buffer = new byte[bufferSize]; int readed = fileStream.Read(buffer, 0, bufferSize); stream.Write(buffer, 0, readed); stream.Flush(); remaining -= readed; // Wait in order to guarantee send speed TimeSpan difference = DateTime.Now.Subtract(current); double seconds = (bufferSize / Speed); int wait = (int)Math.Floor(seconds * 1000); wait -= difference.Milliseconds; if (wait > 10) Thread.Sleep(wait); } stream.Close(); 

and this is the code that handles the receiver side:

 do { readed = stream.Read(buffer, 0, READ_BUFFER_SIZE); // write to .part file and flush to disk outputStream.Write(buffer, 0, readed); outputStream.Flush(); offset += readed; } while (!stop && readed > 0); 

Now that the speed is low (around 5 Kbit / s), everything works fine, but by increasing the speed, the size of the receiver becomes more likely to raise a SocketException when reading from the stream. I assume this is due to closing the remote socket before all the data can be read, but what is the right way to do this? When should the sending client close?

I have not found good examples of file transfers on google, and the ones I found have a similar implementation of what I'm doing, so I think I'm missing something.

Edit: I get this error "Unable to read data from transport connection." This is an IOException whose internal exception is a SocketException.

I added this to the sender function, but still getting the same error, the code never reaches stream.close (), and of course tcpclient never closes ... so I'm completely lost.

 buffer = new byte[1]; client.Client.Receive(buffer); stream.Close(); 
+4
source share
1 answer

Usually you want to set the LINGER option to the slot. In C ++, it will be SO_LINGER, but under windows it does not work properly. Do you really want to do this:

  • Stop sending data.
  • Turn off the call () with the parameter set to 1.
  • Loop on recv () until it returns 0.
  • Call closesocket ().

Taken from: http://tangentsoft.net/wskfaq/newbie.html#howclose

C # sharp can fix this in its libraries, but I doubt it, since they are built on top of the winsock API.

Edit:

Looking at your code in more detail. I see that you are not sending the header at all, so on the receiving side you have no idea how many bytes you should read. Knowing the number of bytes to read a socket makes this task much easier to debug. Keep in mind that turning off a socket can still trim the last bit of data if you don't close it properly.

Also, your buffer size will be volatile is not thread safe and really will not buy you anything. Using a stop as volatile is safe, but don't expect it to be instantaneous. In other words, the loop can run several more times before it receives the updated stop value. This is especially true for multiprocessor machines.

Edit_02:

For TCPClientClass, you want to do the following (as far as I can tell, without access to C # at the moment).

 // write all the bytes // Then do the following client.client.Shutdown(Shutdown.Send) // This assumes you have access to this protected member while (stream.read(buffer, 0, READ_BUFFER_SIZE) != 0); client.close() 
+1
source

Source: https://habr.com/ru/post/1286419/


All Articles