c# - 服务器和客户端之间通过TCP异步传输数据

标签 c# tcp async-await client-server

我有一个问题:服务器没有从客户端接收到任何数据。

这是服务器初始化:

public void Start()
{
    var listener = new TcpListener(IPAddress.Any, Port);
    listener.Start();
    Task.Run(
        async () =>
        {
            while (!this.cancellationToken.IsCancellationRequested)
            {
                var client = await listener.AcceptTcpClientAsync();
                var stream = client.GetStream();
                string request = await ReceiveRequestAsync(stream);
                await RequestHandlerAsync(request, stream);
            }

            listener.Stop();
        }, this.cancellationToken);
}

这里是请求客户端代码(它来自单元测试,所以服务器在这里初始化):

var server = new SimpleFtpServer();
server.Start();
using (TcpClient client = new TcpClient(RequestUri, Port))
{
        NetworkStream stream = client.GetStream();
        StreamWriter writer = new StreamWriter(stream)
        {
            AutoFlush = true,
        };
        writer.Write("zapros");

        using (StreamReader reader = new StreamReader(stream))
        {
            Console.Writeline(reader.ReadToEnd());
        }
}

server.Stop();

值得一提的是,我最近才真正开始在 C# 中学习 async/await,所以问题可能出在它们的使用上。

提前致谢!

最佳答案

它可能并不完美,但我和你处于同样的情况,并创建了一个异步 TCP 客户端/服务器来进行练习和实验。

下面是我的实现的摘录,它有效

服务器:

public class AsyncServerDemo
{
    private CancellationTokenSource cancel;
    private readonly TcpListenerEx listener;

    private Task WaitingForConnections;

    private Timer timerCallAcceptClients;

    public bool IsRunning { get; private set; }

    public AsyncServerDemo(int port)
    {
        cancel = new CancellationTokenSource();
        listener = new TcpListenerEx(IPAddress.Any, port);
    }
    private Task<string> WaitForMessageAsync(TcpClient client, CancellationToken token)
    {
        return Task.Run(() =>
        {
            StringBuilder sb = new StringBuilder();
            bool dataAvailable = false;
            while (!token.IsCancellationRequested)
            {
                while (client.Client.Available > 0)
                {
                    dataAvailable = true;
                    int buffered = client.Client.Available;
                    byte[] buffer = new byte[buffered];
                    client.Client.Receive(buffer);
                    sb.Append(Encoding.ASCII.GetString(buffer));
                }

                if (dataAvailable)
                {
                    dataAvailable = false;
                    return sb.ToString();
                }
            };
            return string.Empty; //timeout
        });
    }
    private Task AcceptClientAsync()
    {
        return Task.Factory.StartNew(async () =>
        {
            IsRunning = true && !cancel.IsCancellationRequested;
            while (!cancel.IsCancellationRequested)
            {
                if (!listener.Pending())
                {
                    continue;
                }

                TcpClient newClient = await listener.AcceptTcpClientAsync().ConfigureAwait(false);
                Stopwatch timeout = new Stopwatch();
                timeout.Restart();
                string message = await WaitForMessageAsync(newClient, new CancellationTokenSource(TimeSpan.FromSeconds(5)).Token);
                if (message != null)
                {
                    //TODO: Message recieved
                }
                timeout.Stop();
            }
        });
    }

    public void Start()
    {
        listener.Start();
        timerCallAcceptClients = new Timer(new TimerCallback((state) =>
        {
            AcceptClientAsync();
        }), null, 0, (int)TimeSpan.FromSeconds(1).TotalMilliseconds);
    }
    public async void Stop()
    {
        if (!IsRunning) return;


        using (cancel)
            cancel.Cancel();

        timerCallAcceptClients.Dispose();
        if (WaitingForConnections != null)
            await WaitingForConnections;

        cancel = null;

        listener.Stop();
        IsRunning = false;
        cancel = new CancellationTokenSource();
    }

}

客户:

public class ClientExDemo
{
    private Task<string> WaitForMessage;
    private NetworkStream currentStream;
    private CancellationTokenSource messageToken;
    public EventHandler<ClientEx> OnServerFound;


    public TcpClient Connection;
    public EventHandler<string> OnMessage;


    public async Task StartListenAsync(CancellationTokenSource token = null)
    {
        if (token == null)
            messageToken = new CancellationTokenSource();
        else
            messageToken = token;

        currentStream = Connection.GetStream();
        string message = "";


        if (message.Length > 0)
            OnMessage?.Invoke(this, message);

        if (!messageToken.IsCancellationRequested)
        {
            await StartListenAsync(token);
        }

        Timeout();
    }
    protected virtual void Timeout()
    {

    }
    public async Task WaitForServerAsync(string ip, int port)
    {
        do
        {
            try
            {
                await Connection.ConnectAsync(ip, port);
            }
            catch (SocketException x)
            {

            }
            await Task.Delay(50);
        } while (!Connection.Connected);

    }

    public void StopListen()
    {
        using (messageToken)
        {
            messageToken.Cancel();
        }

        try
        {

            WaitForMessage.GetAwaiter().GetResult();
        }
        catch (AggregateException)
        {

        }


        currentStream.Close();

        messageToken = null;
        currentStream = null;
        WaitForMessage = null;
    }

    public ClientExDemo()
    {
        Connection = new TcpClient();

        OnServerFound += ServerFound;
    }
    private void ServerFound(object sender, ClientEx args)
    {

    }
    public void Send(string message)
    {
        Connection.Client.Send(Encoding.ASCII.GetBytes(message));
    }


}

您可以在一个简单的控制台应用程序中从客户端发送消息:

        ClientEx client= new ClientEx();

        await client.WaitForServerAsync(ip, port);


        string msg = string.Empty;

        do
        {
            Console.Write("Send Message: ");
            msg = Console.ReadLine();
            shell.Send(msg);
        } while (msg != "q");

        Console.WriteLine();
        Console.WriteLine("BYE");
        Console.ReadKey();

关于c# - 服务器和客户端之间通过TCP异步传输数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53250404/

相关文章:

c# - 从 RowDataBound 事件的 gridview 的单元格中获取值

c# - 使用托管内存进行注册 I/O RIOSend 函数调用

c# - 为什么我收到 DocumentElement 不存在的错误?

java - 如何在 Windows 和 Java 11 上调试 "Software caused connection abort: recv failed"?

javascript - 等待最后指令有用吗

c# - 异步等待一个简单的包装方法

c# - FTP上传结束时不一定总能获得226 Transfer OK

http - 为什么我们在 websocket 握手响应中使用\n\r?

tcp - 高频交易 - TCP > UDP?

c# - 异步/等待 vs BeginRead、EndRead