即使数据可用,从端口读取信息也会等待

Reading information from a port waits even though data available

我在通过套接字发送信息和接收响应时遇到问题。我有一个运行正常的演示程序,所以我知道这不是另一端客户端的问题。

请求数据已发送,客户端正确操作并响应,但我的代码从未退出读取响应中的循环。

客户会不会在我倾听之前做出回应?我怎样才能确保我不会错过任何收到的消息?

            networkStream = tcpClient.GetStream();
            StreamWriter clientStreamWriter = new StreamWriter();
            clientStreamWriter.WriteLine(requestData);
            clientStreamWriter.Flush();

            // Continuously read data on the socket and if it is more than just a ping, read the response.
            StringBuilder sbReadBuffer = new StringBuilder();

            while (true)
            {
                String response = readresponse(timeoutOn30Seconds);

                if (response.Length > 1 && (!response.Contains("\r\n") || response.Contains(",")))
                {
                    break;
                }
            }

            sbReadBuffer.Append(received);

            return sbReadBuffer.ToString();

读取响应:

    private string readresponse(Boolean timeoutOn30Seconds)
    {
        // Get network stream.
        DateTime lastConTime = DateTime.Now;
        Int32 i = 0;

        // Start listening to stream.
        while (!networkStream.DataAvailable)
        {
            Log.W(".");
            // Only check every 10ms.
            Thread.Sleep(10);

            // If no response in 30mins stop listening and give an offline warning.
            if ((DateTime.Now - lastConTime).TotalSeconds > tcpClient.ReceiveTimeout)
            {
                received = "CLIENT NOT FOUND";

                return received;
            }

            // Only check if application online every 1s.
            if (i > 100)
            {
                if (Process.GetProcessesByName(ConfigurationManager.AppSettings["ClientName"]).FirstOrDefault() == null && Convert.ToInt32(ConfigurationManager.AppSettings["Device"]) != 680)
                {
                    received = "CLIENT NOT FOUND";

                    return received;
                }

                i = 0;
            }

            i++;
        }

        // If data has been writted to the buffer, read it out and assign output variable and return that string for length comparison.
        byte[] receiveBuffer = new byte[tcpClient.ReceiveBufferSize];
        Int32 receiveCount = networkStream.Read(receiveBuffer, 0, receiveBuffer.Length);
        received = new ASCIIEncoding().GetString(receiveBuffer, 0, receiveCount);

        return received;
    }

你没有读入 while 循环。要清除 DataAvailable 标志,您必须从 networkStream 中读取。 示例用法: http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.dataavailable%28v=vs.100%29.aspx

DataAvailable 不是了解数据是否到来的好方法,尤其是在肯定比网络通信更快的 while 循环中。

一个更好的方法可能是使用Read方法(读取字节)来知道哪里有数据可用,进入一个定时循环;所以以这种方式改变你的while条件(然后调整其他部分)

while (networkStream.Read(receiveBuffer, 0, receiveBuffer.Length) > 0)
    {
        Log.W(".");
        // Only check every 10ms.
        Thread.Sleep(10);

但如果可能的话,我更喜欢异步方法,这样您的客户会在数据传入时收到通知。

参见 this answer 使用这种方法。

基本上设置一个异步回调,当数据到来时触发

public void StartListening() {
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPEndPoint localEP = new IPEndPoint(ipHostInfo.AddressList[0],11000);

Console.WriteLine("Local address and port : {0}",localEP.ToString());

Socket listener = new Socket( localEP.Address.AddressFamily,
    SocketType.Stream, ProtocolType.Tcp );

try {
    listener.Bind(localEP);
    listener.Listen(10);

    while (true) {
        allDone.Reset();

        Console.WriteLine("Waiting for a connection...");
        listener.BeginAccept(
            new AsyncCallback(SocketListener.acceptCallback), 
            listener );

        allDone.WaitOne();
    }
} catch (Exception e) {
    Console.WriteLine(e.ToString());
}

Console.WriteLine( "Closing the listener...");
}

在那里你可以阅读你的数据

public static void acceptCallback(IAsyncResult ar) {
    // Get the socket that handles the client request.
    Socket listener = (Socket) ar.AsyncState;
    Socket handler = listener.EndAccept(ar);

    // Signal the main thread to continue.
    allDone.Set();

    // Create the state object.
    StateObject state = new StateObject();
    state.workSocket = handler;
    handler.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0,
        new AsyncCallback(AsynchronousSocketListener.readCallback), state);
}

Here full MSDN documentation