ReadAsync在异步TcpClient中只读取一次

时间:2017-12-02 21:58:12

标签: c#

我写了一个简单的异步TcpClient。这里是代码的相关部分:

data = [
    {u'Value': u'nine', u'Key': u'nine'}, {u'Value': u'six', u'Key': u'six'}, 
    {u'Value': u'four', u'Key': u'four'}, {u'Value': u'one', u'Key': u'one'}, 
    {u'Value': u'seven', u'Key': u'seven'}, {u'Value': u'ten', u'Key': u'ten'}, 
    {u'Value': u'two', u'Key': u'two'}, {u'Value': u'three', u'Key': u'three'}, 
    {u'Value': u'five', u'Key': u'five'}, {u'Value': u'eight', u'Key': u'eight'}
]

s = ''

for x in data:
    s += x['Value'] + ':' + x['Key'] + ' '

s = s[:-1] #this remove the last space from the string

print(s)

#output

nine:nine six:six four:four one:one seven:seven ten:ten two:two three:three five:five eight:eight

在另一个应用程序中,我有一个等待连接的TcpListener。 连接成功后,服务器会向客户端发送一些数据。从ReadAsync正确接收数据。然后,如果我尝试从服务器发送更多数据,客户端将在第二次调用ReadAsync时永远等待。

我非常确定服务器正在运行,因为我收到发送正确字节的SendCallback。

我是否错误地使用了ReadAsync?

更新

我在这里添加了我服务器的完整代码:

public class AsyncTcpClient : IDisposable
{
    private TcpClient tcpClient;
    private Stream stream;

    private int bufferSize = 8192;
    bool IsReceiving = false;

    public event EventHandler<string> OnDataReceived;
    public event EventHandler OnDisconnected;
    public event EventHandler OnConnected;
    public event EventHandler<Exception> OnError;

    public bool IsConnected
    {
        get
        {
            return tcpClient != null && tcpClient.Connected;
        }
    }

    public AsyncTcpClient() { }

    public async Task ConnectAsync(string host, int port, CancellationToken token = default(CancellationToken))
    {
        try
        {
            if (IsConnected) Close();
            tcpClient = new TcpClient();
            if (!tcpClient.ConnectAsync(host, port).Wait(250))
            {
                throw new TimeoutException();
            }
            stream = tcpClient.GetStream();
            OnConnected?.Invoke(this, EventArgs.Empty);
            await Receive();
        }
        catch (Exception)
        {
            OnDisconnected?.Invoke(this, EventArgs.Empty);
        }
    }

    public async Task Receive(CancellationToken token = default(CancellationToken))
    {
        try
        {
            if (!IsConnected || IsReceiving) throw new InvalidOperationException();
            IsReceiving = true;
            byte[] buffer = new byte[bufferSize];
            while (IsConnected)
            {
                token.ThrowIfCancellationRequested();

                // First time it reads the incoming data, then it hangs here forever
                int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, token);
                if (bytesRead > 0)
                {
                    byte[] data = new byte[bytesRead];
                    Array.Copy(buffer, data, bytesRead);
                    OnDataReceived?.Invoke(this, Encoding.ASCII.GetString(data));
                }
                buffer = new byte[bufferSize];
            }
        }
        catch (ObjectDisposedException) { }
        catch (IOException)
        {
            throw;
        }
        finally
        {
            IsReceiving = false;
        }
    }
}

1 个答案:

答案 0 :(得分:1)

我查看了您的服务器代码,并进行了一些修改。首先,有一个名为&#34; queue&#34;的变量。我没有理解它的目的,因为你并没有把它排在任何地方,你试图在BeginReceive方法中阻止它在无限范围内。 while语句阻塞主线程并阻止从客户端接收数据,防止接受其应完成的其他客户端和其他操作。如果你从某个地方将它排队并且想要将出列数据发送到tcp客户端,则可以在收到完成后执行此操作,并且不要为主线程使用无限while循环。我提供了这样的修改方法;

    public void AcceptCallback(IAsyncResult ar)
    {
        allDone.Set();

        if (Connected != null)
        {
            Connected.Invoke(this, new EventArgs());
        }
        Socket listener = (Socket)ar.AsyncState;
        Socket handler = listener.EndAccept(ar);

        BeginReceive(handler);

        //while (handler.Connected)
        //{
        //    if (queue.TryDequeue(out String data))
        //    {
        //        try
        //        {
        //            SendData(handler, data);
        //        }
        //        catch (Exception ex)
        //        {
        //            throw;
        //        }
        //    }
        //    Thread.Sleep(0);
        //}
    }

    public void BeginReceive(Socket handler)
    {
        StateObject state = new StateObject
        {
            workSocket = handler
        };
        handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
    }

    public void ReadCallback(IAsyncResult ar)
    {
        String content = String.Empty;

        StateObject state = (StateObject)ar.AsyncState;
        Socket handler = state.workSocket;

        int bytesRead = handler.EndReceive(ar);

        if (bytesRead > 0)
        {
            state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
            content = state.sb.ToString();
            if (queue.TryDequeue(out String data))
            {
                try
                {
                    SendData(handler, data);
                }
                catch (Exception ex)
                {
                    throw;
                }
            }
            //SendData(handler, content);
            Debug.WriteLine("Read {0} bytes from socket. \n Data : {1}", content.Length, content);
        }
        BeginReceive(handler);
    }