SslStream EndRead получает первый 1 байт

Я написал TcpClient и сервер, которые общаются через SslStream. Связь работает, но когда я отправляю сообщение от клиента на сервер, сначала сервер читает 1 байт, а на следующем шаге все остальное. Пример: я хочу отправить "test" через Клиент, а Сервер получает сначала "t", а потом "est"

Вот код, который клиент должен отправить

    public void Send(string text) {
        byte[] message = Encoding.UTF8.GetBytes(text);
        SecureStream.BeginWrite(message, 0, message.Length, new AsyncCallback(WriteCallback), null);
    }

    private void WriteCallback(IAsyncResult AR) {

    }

А вот код, который Сервер использует для чтения

    private SslStream CryptedStream = ...;
    private byte[] buffer = new byte[1024];

    public void BeginReadCallback(IAsyncResult AsyncCall) {

        // initialize variables
        int bytesRead = 0;

        try {
            // retrieve packet
            bytesRead = CryptedStream.EndRead(AsyncCall);

            // check if client has disconnected
            if (bytesRead > 0) {
                // copy buffer to a temporary one
                var temporaryBuffer = buffer;
                Array.Resize(ref temporaryBuffer, bytesRead);

                string read = Encoding.ASCII.GetString(temporaryBuffer);
                SetText(read);

                // read more data
                CryptedStream.BeginRead(buffer, 0, 1024, new AsyncCallback(BeginReadCallback), null);

                // client is still connected, read data from buffer
                //ProcessPacket(temporaryBuffer, temporaryBuffer.Length, helper);
            } else {
                // client disconnected, do everything to disconnect the client
                //DisconnectClient(helper);
            }
        } catch (Exception e) {
            // encountered an error, closing connection
            // Program.log.Add(e.ToString(), Logger.LogLevel.Error);
            // DisconnectClient(helper);
        }
    }

Я что-то пропустил? Спасибо за вашу помощь


person Daniel DirtyNative Martin    schedule 02.05.2016    source источник
comment
В чем тут вопрос? потоковое соединение никоим образом не отправляет пакеты байтов, оно отправляет поток байтов, при чтении вы должны быть готовы к получению меньших фрагментов того, что вы считаете пакет, а затем собрать его в связный пакет, если это необходимо.   -  person Lasse V. Karlsen    schedule 02.05.2016
comment
Я не знаком с потоками, так что простите мне мою неопытность. Так может ли это означать, что если сервер будет намного быстрее, я получу тест?   -  person Daniel DirtyNative Martin    schedule 02.05.2016
comment
Вы могли получить это или могли получить tes, а затем t, или t, а затем est или te, а затем st. Это зависит от многих вещей, скорости, буферов на оборудовании (ваш компьютер, маршрутизаторы и коммутаторы между двумя конечными точками и т. д.) и программного обеспечения. Короче говоря, ваш код должен быть в состоянии справиться с этим.   -  person Lasse V. Karlsen    schedule 02.05.2016
comment
Ах я вижу. поэтому лучше всего было бы сохранить полученные байты во временном массиве, а после достижения конца вернуть этот массив. Но поскольку я использую асинхронные обратные вызовы, каждый раз, когда что-либо было получено, вызывается метод. Итак, как мне обнаружить конец? Или я должен закрывать поток после каждой отправки и получения?   -  person Daniel DirtyNative Martin    schedule 02.05.2016
comment
Вам нужно знать, когда вы достигли конца, как вы узнаете, что не видите следующий пакет? Это означает, что если вы сначала отправите test, а затем otherTest, что, если ваше первое чтение даст вам testoth? Вам нужно создать что-то поверх потока для обработки вашего протокола и ваших пакетов.   -  person Lasse V. Karlsen    schedule 02.05.2016
comment
Так, может быть, первые 4 байта указывают длину отправляемых байтов?   -  person Daniel DirtyNative Martin    schedule 02.05.2016


Ответы (1)


Как объяснил Лассе, потоковые API не обещают вам возвращать определенное количество байтов за чтение.

Лучшее решение для этого — не использовать сокеты. Используйте API более высокого уровня, например WCF, SignalR, HTTP,...

Если вы настаиваете, вам, вероятно, следует использовать BinaryReader/Writer для отправки ваших данных. Это делает это довольно легко. Например, он имеет встроенную отправку строк. Вы также можете легко вручную префикс длины с этими классами.

Вероятно, вам не нужен асинхронный ввод-вывод и не стоит его использовать. Если вы настаиваете, вы можете по крайней мере избавиться от обратных вызовов, используя await.

person usr    schedule 02.05.2016