【问题标题】:Attempting to create an asynchronous tcp server尝试创建异步 tcp 服务器
【发布时间】:2014-02-21 05:18:22
【问题描述】:

我正在尝试学习如何在 C# 中创建异步 tcp 服务器,但我的代码遇到了一个小问题。

I tried to modify this code

这就是我所做的:

public class ClientContext 
{
    public TcpClient client { get; set; }
    public NetworkStream stream { get; set; }
    public byte[] buffer { get; set; }
    public string message { get; set; }
    // public MemoryStream message = new MemoryStream ();

    public ClientContext () 
    {
        buffer = new byte[14];
        message = "";
    }
}

public class TCPServer
{

    public TCPServer ()
    {
        // Setup the server side
        TcpListener listener = new TcpListener (new IPEndPoint (IPAddress.Parse("127.0.0.1"), 14000));
        listener.Start ();
        // Server side ok, wait for client to connect
        listener.BeginAcceptTcpClient (OnClientAccepted, listener);

        Console.WriteLine ("Press enter to exit...");
        Console.ReadLine ();
        listener.Stop ();
    }

    private void OnClientAccepted (IAsyncResult ar)
    {
        // A client connected
        TcpListener listener = (TcpListener)ar.AsyncState;

        if (listener == null)
            return;

        try {
            // Create a new client context to store connection infos about dat client
            ClientContext context = new ClientContext ();
            context.client = listener.EndAcceptTcpClient (ar);
            context.stream = context.client.GetStream ();
            // The client is now ready, read what it has to say
            context.stream.BeginRead (context.buffer, 0, context.buffer.Length, OnClientRead, context);
        } finally {
            listener.BeginAcceptTcpClient (OnClientAccepted, listener);
        }
    }

    private void OnClientRead (IAsyncResult ar)
    {
        // The client wants to say something
        ClientContext context = (ClientContext)ar.AsyncState;
        context.message = "";

        if (context == null)
            return;

        try {
            // Read what it says
            if(context.stream.CanRead) {

                do {

                    context.stream.Read (context.buffer, 0, context.buffer.Length);
                    context.message += Encoding.ASCII.GetString (context.buffer);
                    //length -= context.message.Length;

                } while (context.stream.DataAvailable); //  && length < readBuffer.Length

                OnMessageReceived(context);
            }   

        } catch (Exception) {
            context.client.Close ();
            context.stream.Close ();
            context = null;
        } finally {
            // If we are still connected to the client, read what it has to say...
            if (context != null)
                context.stream.BeginRead (context.buffer, 0, context.buffer.Length, OnClientRead, context);
        }

    }

    private void OnMessageReceived (ClientContext context)
    {
        // Display what the client said
        Console.WriteLine ("Message reçue : " + context.message);
    }
}

问题是:我有一个发送 50 个“hello world !!”的客户端向服务器发送消息,服务器仅打印 25 / 26 "hello world !!"在控制台中。我查看了使用 SocketSniff 的套接字,我看到服务器套接字收到 50 个“hello world !!”,所以我的代码一定是失败了,但是什么?

你们有什么想法吗?

【问题讨论】:

    标签: c# asynchronous tcplistener networkstream


    【解决方案1】:
    context.stream.Read (context.buffer, 0, context.buffer.Length);
    context.message += Encoding.ASCII.GetString (context.buffer);
    

    这里您没有检查来自Stream.Read 的返回。 Read 本来可以在缓冲区中放入一个字节,但您随后将解码 整个 缓冲区,其中包含来自先前读取调用的剩余字节。这必须是:

    int bytesRead = context.stream.Read (context.buffer, 0, context.buffer.Length);
    context.message += Encoding.ASCII.GetString (context.buffer, 0, bytesRead);
    

    但是你遇到的问题是不同的。你正在做一个危险的同步和异步混合......不稳定的结果。 您不应在 BeginRead 回调中发出同步读取!您必须调用 EndRead

    int bytesRead = context.stream.EndRead(ar);
    context.message += Encoding.ASCII.GetString (context.buffer, 0, bytesRead);
    OnMessageReceived(context);
    context.stream.BeginRead (context.buffer, 0, context.buffer.Length, OnClientRead, context);
    

    无需检查DataAvailableCanRead

    【讨论】:

    • 首先感谢您的快速回答。我根据您所说的更改了我的代码,并修复了它。非常感谢。
    猜你喜欢
    • 2013-04-06
    • 2010-10-22
    • 1970-01-01
    • 2014-05-18
    • 2014-12-22
    • 2019-01-04
    • 2021-07-24
    • 2021-07-15
    相关资源
    最近更新 更多