0

I am uploading a file to the server in chunks. If you break the connection between the client and the server for a while, and then restore, the server throws an error when trying to receive data from the client:

An attempt to establish a connection was unsuccessful because the desired response was not received from another computer within the required time, or an already established connection was terminated due to an incorrect response from an already connected computer

This happens in the following case: if I send another chunk to the server and waits for a response from the server, the server at this time processes the request, sends the response to the client and waits for the next request. If, after a request to the server, the connection is terminated, and after 15 seconds, it is restored, an error appears.

Chunk sending code from the client:

chunk = reader.ReadBytes(chunkSize);
bytesToRead -= chunkSize;

var packet = packetService.CreatePacket(new ServerPacket
{
  Command = CommandsNames.UploadDataCommand,
  ClientId = clientId,
  Payload = uploadingService.GetUploadDataPayload(
    chunk,
    uploadingHash),
  PayloadParts = new List<int>
    {
      Encoding.Unicode.GetByteCount(uploadingHash),
        chunk.Length
    }
});

await dataTransitService.SendDataAsync(_socket, packet);
var response = await dataTransitService
   .ReadDataAsync(
     _socket,
     chunkSize,
     p => packetService.ParsePacket(p));

SendDataAsync method:

public async Task SendDataAsync(
            Socket socket, 
            IEnumerable<byte> data)
        {
            if (data != null && data.Any())
            {
                await socket.SendAsync(
                    new ArraySegment<byte>(data.ToArray()),
                    SocketFlags.None);
            }
        }

ReadDataAsync method:

public async Task<T> ReadDataAsync<T>(
            Socket socket, 
            int chunkSize,
            Func<IEnumerable<byte>, T> parsePacket)
        {
            var data = new ArraySegment<byte>(new byte[chunkSize]);
            var receivedPacket = new List<byte>();

            do
            {
                var bytes = await socket.ReceiveAsync(data, SocketFlags.None);

                if (data.Array != null)
                {
                    receivedPacket.AddRange(data.Array);
                }
            }
            while (socket.Available > 0);

            return parsePacket(receivedPacket);
        }

Client Socket configuration:

var (port, address) = (
                    _configurationSection["port"],
                    _configurationSection["address"]);

            var ipPoint = new IPEndPoint(
                IPAddress.Parse(address),
                Int32.Parse(port));
            socket = new Socket(
                AddressFamily.InterNetwork, 
                SocketType.Stream, ProtocolType.Tcp);

Server socket configuration:

 var section = _configuration.GetSection("listener");
            var (address, port) = (section["address"], section["port"]);
            var listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            var ipPoint = new IPEndPoint(IPAddress.Parse(address), Int32.Parse(port));

            try
            {
                listenSocket.Bind(ipPoint);
                listenSocket.Listen(20);
               
                Console.WriteLine("Waiting for connections...");
             
                var socket = listenSocket.Accept();                
                await _serverProcess.ProcessAsync(socket, StopServer);
Lev Kostychenko
  • 147
  • 1
  • 10
  • A Socket is TCP protocol which only allows one connection with the same Source IP address, Destination IP address, and Port number. So you have to close a connection before opening up a new connection. In your case, you should not be closing the connection for each chunk. You can send multiple messages on same connection. You cannot restore a TCP connection. I must be anew connection after the old connection is closed. – jdweng Nov 24 '21 at 17:16
  • But i don't close the connection for each chunk – Lev Kostychenko Nov 24 '21 at 17:57
  • The accept should only be done once (var socket = listenSocket.Accept();) So it should be outside the loop. Make sure you are not stopping the server which will clos the conneciton. – jdweng Nov 24 '21 at 18:21
  • I removed the loop, but the error is still reproducible: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. – Lev Kostychenko Nov 24 '21 at 22:06
  • 1
    Good to see you're still up and trolling, @jdweng. Once again you're omitting that a socket has actually two ports, namely source and destination port. The tuple (source IP, source port, destination IP, destination port) needs to be unique, but this does not prevent a new connection to the same port from the same host; the only thing that needs to differ is the (ephemeral) source port, which the OS's network layer handles for you. One does not have to close a connection before starting a new one to the same destination host and port. – CodeCaster Nov 25 '21 at 10:09
  • 1
    @jdweng you also definitely need to `Accept()` in a loop, otherwise your server will handle one connection during its lifetime. – CodeCaster Nov 25 '21 at 10:11
  • @CodeCaster : You response is confusing. A listener can accept many connections and does not need a loop. Only if the connection closes to you need to perform a second accept, and then it probably will not work without closing the connection. – jdweng Nov 29 '21 at 10:39
  • @jdweng no, one Accept() call accepts one connection. If you want more than one connection, you need to keep calling Accept(). You can then gave multiple active simultaneous connections. If you believe otherwise, please show sources. – CodeCaster Nov 29 '21 at 11:15
  • @CodeCaster : A listener only listens at one port so the client has to send to the one port that the server is listening to. The ACCEPT is built into the Synchronous Listener and is not needed. – jdweng Nov 30 '21 at 10:26

1 Answers1

1

If, after a request to the server, the connection is terminated, and after 15 seconds, it is restored, an error appears.

If you unplug the network cable, Windows tells sockets over that NIC that they're disconnected. Otherwise (say your cable is still plugged in, but a cable, switch or router in between ceases to function), you need to send or receive on that socket in order for it to detect it's been disconnected.

See How to check if a socket is connected/disconnected in C#?.

Once disconnected, a socket cannot be restored. You need to detect this status, start a new connection and tell your server that you want to continue a prior transmission. We don't know whether your protocol understands that.

Also: IEnumerable<byte> data, data.Any(), new ArraySegment<byte>(data.ToArray()) - why?

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
  • Thanks, I will try to change the implementation of the protocol and come back later with the result. What's wrong with `IEnumerable data, data.Any(), new ArraySegment(data.ToArray())`? – Lev Kostychenko Nov 25 '21 at 10:26
  • If `packetService.CreatePacket()` returns a byte array, make its return type a byte array. Now you claim it's an `IEnumerable` and start enumerating it at least twice, once for `.Any()` and once for `.ToArray()`. If the underlying type actually is an array this doesn't do much. – CodeCaster Nov 25 '21 at 10:29