Search code examples
c#read-writesslstream

SslStream EndRead gets first 1 Byte


I've written a TcpClient and Server which are communicating via an SslStream. The communication works, but when i send a message from the Client to the Server, first the Server reads 1 Byte, and in the next step the rest. Example: I want to send "test" via Client, and the Server receives first "t", and then "est"

Here is the code for the Client to send

    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) {

    }

And here the code the Server uses to read

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

Did i miss something? Thanks for your help


Solution

  • As Lasse explained streaming APIs do not promise you to return a specific number of bytes per read.

    The best fix for this is to not use sockets. Use a higher level API such as WCF, SignalR, HTTP, ...

    If you insist you probably should use BinaryReader/Writer to send your data. That makes it quite easy. For example, it has string sending built-in. You also can manually length-prefix easily with those classes.

    Probably, you don't need async IO and should not use it. If you insist you can at least get rid of the callbacks by using await.