3

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

DirtyNative
  • 2,553
  • 2
  • 33
  • 58
  • 1
    What is the question here? A *streaming connection* does not in any way send packets of bytes, it sends a stream of bytes, when reading you have to be prepared for getting smaller pieces of what *you* consider a package and then reassemble this into a coherent package if needs be. – Lasse V. Karlsen May 02 '16 at 12:32
  • I am not familiar with streams, so forgive me my inexperience. So could that mean that if the server is much faster, i would receive "t" "e" "s" "t"? – DirtyNative May 02 '16 at 12:36
  • 1
    You *could* receive that, or you could receive `tes` and then `t`, or `t` and then `est` or `te` and then `st`. It depends on a lot of things, speed, buffers on hardware (your computer, routers and switches between the two endpoints, etc.) and software. In short, your code need to be able to handle this. – Lasse V. Karlsen May 02 '16 at 12:38
  • Ah i see. so best would be to store the received bytes in an temporary array, and after the end was reached, return that array. But because i use async callbacks, everytime anything was received, the method is called. So how do i detect the end? Or should i close the stream after each sending and receiving? – DirtyNative May 02 '16 at 12:43
  • You need to know when you've reached "the end", how do you know you're not seeing the next packet? Meaning, if you first send `test` and then `otherTest`, what if your first read gives you `testoth` ? You need to build something on top of the stream to handle your protocol and your packets. – Lasse V. Karlsen May 02 '16 at 12:44
  • So maybe the first 4 bytes are indicating the length of the sending bytes? – DirtyNative May 02 '16 at 12:47

1 Answers1

1

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.

usr
  • 168,620
  • 35
  • 240
  • 369