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);
9
  • 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. Commented Nov 24, 2021 at 17:16
  • But i don't close the connection for each chunk Commented Nov 24, 2021 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. Commented Nov 24, 2021 at 18:21
  • 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. Commented Nov 25, 2021 at 10:09
  • 1
    @jdweng you also definitely need to Accept() in a loop, otherwise your server will handle one connection during its lifetime. Commented Nov 25, 2021 at 10:11

1 Answer 1

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?

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, I will try to change the implementation of the protocol and come back later with the result. What's wrong with IEnumerable<byte> data, data.Any(), new ArraySegment<byte>(data.ToArray())?
If packetService.CreatePacket() returns a byte array, make its return type a byte array. Now you claim it's an IEnumerable<byte> 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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.