Чтение информации из порта ожидает, даже если данные доступны

1

У меня возникла проблема с отправкой информации по сокету и получением ответа. У меня есть демо-программа, которая работает правильно, поэтому я знаю, что это не проблема с клиентом на другом конце.

RequestData отправляется, и клиент действует правильно и отвечает, но мой код никогда не выходит из цикла в ответе на чтение.

Может ли клиент отвечать, прежде чем я буду слушать? Как я могу удостовериться, что никогда не пропущу входящее сообщение?

            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;
    }
Теги:
sockets
tcpclient
networkstream

2 ответа

2
Лучший ответ

DataAvailable - не лучший способ узнать, поступают ли данные, особенно в цикле while, который, безусловно, быстрее, чем сетевые коммуникации.

Лучшим способом может быть использование метода Read (чтение в байтах), чтобы знать, где данные доступны, в тайм-петле; поэтому измените свое состояние таким образом (а затем отрегулируйте другие части)

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

но я предпочитаю, если возможно, асинхронный подход, поэтому ваш клиент будет уведомлен о поступлении данных.

См. Этот ответ, который использует такой подход.

В основном устанавливается асинхронный обратный вызов, который будет запущен при поступлении данных

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

Здесь полная документация MSDN

  • 0
    К сожалению, я не могу переписать основную структуру приложения из-за бизнес-ограничений. Есть ли способ настроить текущие настройки на работу?
  • 0
    Я редактирую свой предыдущий ответ с другим вариантом
0

Вы не читаете цикл while. Чтобы очистить флаг DataAvailable, вы должны читать из networkStream. Пример использования: http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.dataavailable%28v=vs.100%29.aspx

Ещё вопросы

Сообщество Overcoder
Наверх
Меню