简体   繁体   中英

Asynchronous TCP Socket Issue

Well, I need to connect to a TCP socket, however, it only accepts one connection at a time and has a 60 second timeout.

The problem is that in the process of sending information and receiving a response, the application is not performative.

I would like to know, if in this case, it is possible to do something asynchronous/parallel.

Below is my socket client class.

public class TcpSocketClient
{
    public TcpClient TCPConnection { get; private set; }

    private int BUFFER_SIZE = 259;

    public TcpSocketClient Connect(IPEndPoint endpoint)
    {
        try
        {
            this.TCPConnection = new TcpClient(endpoint);
            return this;
        }
        catch (SocketException ex)
        {
            throw new Exception($"{ex.Message} - {ex.StackTrace}");
        }
        catch (Exception ex)
        {
            throw new Exception($"Err: {ex.Message} - {ex.StackTrace}");
        }
    }

    public T SendRequest<T>(IFrame request) where T : IFrame, new()
    {
        var data = request.ToByteArray();

        var stream = this.TCPConnection.GetStream();
        stream.Write(data, 0, data.Length);

        data = new byte[this.BUFFER_SIZE];
        var quantityBytes = stream.Read(data, 0, data.Length);

        var frameResponse = data.Take(quantityBytes).ToArray();

        var response = new T
        {
            FrameHeader = frameResponse[0],
            Lenght = frameResponse[1],
            FunctionCode = frameResponse[2],
            Data = (frameResponse[1] == 0) ? null : data.ToDataField(quantityBytes),
            Checksum = frameResponse[frameResponse.Length - 1]
        };

        (response.Checksum != response.VerifyChecksum()) { throw new Exception("Err in Checksum!"); }

        return response;
    }

    public void Disconnect()
    {
        this.TCPConnection.Dispose();
    }
}

You can modify your code to be async:

public async Task<T> SendRequest<T>(IFrame request) where T : IFrame, new()
{
    var data = request.ToByteArray();

    var stream = this.TCPConnection.GetStream();
    await stream.WriteAsync(data, 0, data.Length);

    data = new byte[this.BUFFER_SIZE];
    var quantityBytes = await stream.ReadAsync(data, 0, data.Length);

    var frameResponse = data.Take(quantityBytes).ToArray();

    var response = new T
    {
        FrameHeader = frameResponse[0],
        Lenght = frameResponse[1],
        FunctionCode = frameResponse[2],
        Data = (frameResponse[1] == 0) ? null : data.ToDataField(quantityBytes),
        Checksum = frameResponse[frameResponse.Length - 1]
    };

    if(response.Checksum != response.VerifyChecksum())
        throw new Exception("Err in Checksum!");

    return response;
}

To call it use:

MyFrameResponseType response = await SendRequest(yourRequest);

Also, as a note, that code assumes you will receive a response with only one read, that will fail on a future, if the network is slow or the sent response is big enough it will be received in multiple read operations, you should have some mechanism to detect a frame start/end and read until you have received a full frame.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM