即使有可用数据,仍要从端口读取信息 [英] Reading information from a port waits even though data available

查看:53
本文介绍了即使有可用数据,仍要从端口读取信息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在通过套接字发送信息并接收响应时遇到问题.我有一个演示程序可以正常执行,所以我知道另一端的客户端没有问题.

requestData已发送,并且客户端可以正确执行操作并做出响应,但是我的代码从未在读取响应中退出循环.

在我收听之前,客户可以回应吗?如何确保我不会错过任何收到的消息?

  networkStream = tcpClient.GetStream();StreamWriter clientStreamWriter = new StreamWriter();clientStreamWriter.WriteLine(requestData);clientStreamWriter.Flush();//连续读取套接字上的数据,如果不仅仅是ping,请读取响应.StringBuilder sbReadBuffer = new StringBuilder();一会儿(true){字符串响应= readresponse(timeoutOn30Seconds);if(response.Length> 1&&(!response.Contains("\ r \ n")|| response.Contains(,")))){休息;}}sbReadBuffer.Append(received);返回sbReadBuffer.ToString(); 

readResponse:

 私有字符串readresponse(布尔timeoutOn30Seconds){//获取网络流.DateTime lastConTime = DateTime.Now;Int32 i = 0;//开始收听流.而(!networkStream.DataAvailable){Log.W(.");//仅每10毫秒检查一次.Thread.Sleep(10);//如果在30分钟内没有响应,请停止收听并发出离线警告.如果((DateTime.Now-lastConTime).TotalSeconds> tcpClient.ReceiveTimeout){收到=找不到客户";收到退货;}//仅每隔1s检查一次应用程序是否在线.如果(i> 100){如果(Process.GetProcessesByName(ConfigurationManager.AppSettings ["ClientName"]).FirstOrDefault()== null&& Convert.ToInt32(ConfigurationManager.AppSettings ["Device"])!= 680){收到=找不到客户";收到退货;}i = 0;}i ++;}//如果数据已写入缓冲区,则将其读出并分配输出变量,然后返回该字符串以进行长度比较.byte [] receiveBuffer =新的byte [tcpClient.ReceiveBufferSize];Int32 receiveCount = networkStream.Read(receiveBuffer,0,receiveBuffer.Length);接收=新的ASCIIEncoding().GetString(receiveBuffer,0,receiveCount);收到退货;} 

解决方案

DataAvailable并不是了解数据是否到来的好方法,特别是在肯定比网络通信快的while循环中.

更好的方法是在定时循环中使用Read方法(读取的字节)来了解可用数据.因此以这种方式更改您的while条件(然后调整其他部分)

  while(networkStream.Read(receiveBuffer,0,receiveBuffer.Length)> 0){Log.W(.");//仅每10毫秒检查一次.Thread.Sleep(10); 

但我更喜欢一种异步方法,因此,在传入数据时会通知您的客户端.

请参见此答案使用这种方法.

基本上设置了一个异步回调,它将在数据传入时触发

  public void StartListening(){IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());IPEndPoint localEP =新IPEndPoint(ipHostInfo.AddressList [0],11000);Console.WriteLine(本地地址和端口:{0}",localEP.ToString());套接字侦听器=新套接字(localEP.Address.AddressFamily,SocketType.Stream,ProtocolType.Tcp);尝试 {listener.Bind(localEP);listener.Listen(10);而(true){allDone.Reset();Console.WriteLine(正在等待连接...");listener.BeginAccept(新的AsyncCallback(SocketListener.acceptCallback),听众);allDone.WaitOne();}} catch(Exception e){Console.WriteLine(e.ToString());}Console.WriteLine(关闭监听器...");} 

在那里您可以读取数据

 公共静态void acceptCallback(IAsyncResult ar){//获取处理客户端请求的套接字.套接字侦听器=(Socket)ar.AsyncState;套接字处理程序= listener.EndAccept(ar);//通知主线程继续.allDone.Set();//创建状态对象.StateObject状态=新的StateObject();state.workSocket =处理程序;handler.BeginReceive(state.buffer,0,StateObject.BufferSize,0,新的AsyncCallback(AsynchronousSocketListener.readCallback),状态);} 

这里有完整的MSDN文档

I am having a problem sending information down a socket and receiving a response. I have a demo program which is performing correctly so I know it is not an issue with the client on the other end.

The requestData is sent and the client acts correctly and responds, but my code never exits the loop in read response.

Could the client be responding before I am listening? How can I make sure I never miss an incoming message?

            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();

readResponse:

    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;
    }

解决方案

DataAvailable isn't a good method to know if data are coming, especially in a while loop that is surely faster than network communications.

A better way could be to use the Read method (bytes read) to know where data are available, into a timed loop; so change your while condition in this manner (and then adjust the other parts)

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

but I prefer, if possible, an async approach, so your client will be notified when data are incoming.

See this answer that use this kind of approach.

Basically set an async callback that will be fired when data are coming

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...");
}

and there you can read your data

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

这篇关于即使有可用数据,仍要从端口读取信息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆