Как попросить сокет дождаться поступления новых данных - PullRequest
4 голосов
/ 10 ноября 2011

Я играю с проектом RserveCLI , который является клиентом .net, взаимодействующим со статистической средой R. Основная идея заключается в отправке данных / комментариев между этим клиентом .NET и сеансом R по протоколу TCP.

Одна ошибка, которую я и другие обнаружили, заключается в том, что магистраль больших данных, скажем, более 10 Кбайт, не может успешно передать передачу. Я нашел, но в следующем фрагменте кода:

        // send the commend to R, then R will do some computation and get the data ready to send back
        int toConsume = this.SubmitCommand(cmd, data); 
        var res = new List<object>();
        while (toConsume > 0)
        {
            var dhbuf = new byte[4];
            if (this.socket.Receive(dhbuf) != 4)
            {
                throw new WebException("Didn't receive a header.");
            }

            byte typ = dhbuf[0];

            // ReSharper disable RedundantCast
            int dlength = dhbuf[1] + (((int)dhbuf[2]) << 8) + (((int)dhbuf[3]) << 16);

            // ReSharper restore RedundantCast
            var dvbuf = new byte[dlength];

            // BUG: I added this sleep line, without this line, bug occures
            System.Threading.Thread.Sleep(500);

            // this line cannot receive the whole data at once
            var received = this.socket.Receive(dvbuf);
            // so the exception throws 
            if (received != dvbuf.Length)
            {
                var tempR = this.socket.Receive(dvbuf);
                throw new WebException("Expected " + dvbuf.Length + " bytes of data, but received " + received + ".");
            }

Причина в том, что код .NET работает слишком быстро, и сторона R не может отправить данные так быстро. Таким образом, строка приема после моего вставленного Thread.Sleep (500) не получает все данные. Если я подожду там некоторое время, тогда он сможет получить все данные. Но я не знаю, как долго.

У меня есть некоторая основная идея для решения этой проблемы, например, постоянно использовать this.socket.Receive () для получения данных, но если там нет данных. Receive будет блокироваться там.

У меня мало опыта в программировании сокетов, поэтому я прошу наилучшую практику для такого рода проблем. Спасибо!

Ответы [ 2 ]

1 голос
/ 10 ноября 2011

По определению, TCP является потоковым протоколом, тогда как UDP основан на сообщениях. Если данные, которые вы пытаетесь получить, не содержат количества байтов для всего сообщения или какого-либо индикатора конца сообщения, вам просто нужно будет выполнить цикл в socket.receive до истечения некоторого произвольного тайм-аута. В этот момент проверьте накопленные полученные данные на полноту.

1 голос
/ 10 ноября 2011

Согласно документам :

Если вы используете сокет, ориентированный на соединение, метод Receive будет считывать столько данных, сколько доступно, вплоть до размера буфера.

Таким образом, вы никогда не гарантированно получите все данные, запрошенные при получении вызова. Вам необходимо проверить, сколько байтов фактически было возвращено при получении, а затем выполнить еще один вызов приема для оставшихся байтов. Продолжайте этот цикл, пока не получите все байты, которые искали.

...