Как я могу судить, когда NetWorkStream заканчивается, используя .net TcpClient для связи - PullRequest
1 голос
/ 18 марта 2010

Я пытаюсь использовать stream.DataAvailable, чтобы судить, закончено ли оно, но иногда значение ложно, но через некоторое время оно снова становится истинным, я должен установить счетчик и оценить конец по символу '>' это

int connectCounter = 0;

while (connectCounter < 1200)
{
    if (stream.DataAvailable)
    {
        while (stream.DataAvailable)
        {
            byte[] buffer = new byte[bufferSize];
            int flag = stream.Read(buffer, 0, buffer.Length);
            string strReadXML_t = System.Text.Encoding.Default.GetString(buffer);
            strReadXML = strReadXML + strReadXML_t.Replace("\0", string.Empty);       
        }

        if (strReadXML.Substring(strReadXML.Length - 1, 1).Equals(">"))
        {
            break;
        }
    }
    Thread.Sleep(100);
    connectCounter++;
}

есть ли хороший меторд для борьбы с этим? Спасибо!

Ответы [ 3 ]

1 голос
/ 18 марта 2010

У вас есть пара вариантов. Вы можете использовать синхронное, блокирующее чтение или асинхронный шаблон ввода-вывода.

Если вы просто вызовите stream.Read (), вызов заблокируется и будет ждать бесконечно (до истечения времени ожидания TCP), пока данные не станут доступны. Кажется, ты не хочешь этого делать. Вы хотите подождать максимум 120 секунд (1200 мс * 100), чтобы данные полностью прочитались.

Примерно так:

private class AsyncState
{
    public NetworkStream ns;
    public ManualResetEvent e;
    public byte[] b;
    public String strReadXML;
}

public void Run()
{
    TcpClient client ;//= ...
    NetworkStream networkStream = client.GetStream();
    byte[] buffer = new byte[1024];

    var completedEvent = new ManualResetEvent(false);

    networkStream.BeginRead(buffer, 0, buffer.Length,
                            AsyncRead,
                            new AsyncState
                            {
                                b = buffer,
                                ns = networkStream,
                                e = completedEvent,
                                strReadXML = ""
                            });

    // do other stuff here. ...

    // finally, wait 120s for the reading to complete
    bool success = completedEvent.WaitOne(1200*100, false);
    if (!success)
    {
        client.Close();
    }
}


private void AsyncRead(IAsyncResult ar)
{
    AsyncState state = ar as AsyncState;
    int n = state.ns.EndRead(ar);
    if (n == 0)
    {
        // no more bytes to read
        // signal completion
        state.e.Set();
        return;
    }

    // state.buffer now contains the bytes read

    string s = System.Text.Encoding.Default.GetString(state.b);
    state.strReadXML = state.strReadXML + s.Replace("\0", string.Empty);

    if (state.strReadXML.EndsWith(">"))
    {
        // got the "end".  signal completion
        state.e.Set();
        return;
    }

    // read again
    state.ns.BeginRead(state.b, 0, state.b.Length, AsyncRead, state);
}
0 голосов
/ 18 марта 2010

У вас есть контроль над отправкой заявки? Если вы это сделаете, вы можете изменить отправляющее приложение, чтобы обернуть NetworkStream в BinaryWriter и использовать .Write( string ), который отправит длину строки, а затем и саму строку. В получающем приложении (как указано выше) вы можете обернуть NetworkStream в BinaryReader и вызвать .ReadString(), который прочитает длину из потока, а затем прочитает правильную строку длины для вас.

Если у вас нет контроля над отправляющим приложением, вы можете проверить возврат от вызова stream.Read(), так как он возвращает 0 в конце потока - хотя для этого потребуется, чтобы отправляющее приложение закрыло сокет.

Кроме того, stream.Read() не гарантирует возвращение количества запрошенных вами байтов, оно может вернуть меньше. Ваша переменная flag должна быть действительно bytesread, и вам следует передать эту переменную bytesread в метод .GetString.

0 голосов
/ 18 марта 2010

Попробуйте Асинхронное чтение .
Когда ваш обратный вызов вызван, вы можете прочитать существующий буфер данных и затем вызвать BeginRead снова. Так что, когда будет получено больше данных, вам будет вызван обратный вызов.

Что-то вроде:

void DataReceived(IAsyncResult result) ///I am not sure about the parameters.
{
   ///read data from  buffer
   networkstream.BeginRead(
                 buffer, 0, buffer.Length,
                 new AsyncCallback(DataReceived),
                 null);
}

Я думаю, что это довольно приличный подход.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...