title: Sending and receiving compressed data over a TCP socket
body: <p>Need help with sending and receiving compressed data over TCP socket.</p>
  
  <p>The code works perfectly fine if I don't use compression, but something very strange happens when I do use compression.. Basically, the problem is that the stream.Read() operation gets skipped and I don't know why..</p>
  
  <p>My code:</p>
  
  <pre><code>using (var client = new TcpClient())
  {
      client.Connect("xxx.xxx.xx.xx", 6100);
      using (var stream = client.GetStream())
      {
          // SEND REQUEST
          byte[] bytesSent = Encoding.UTF8.GetBytes(xml);
  
          // send compressed bytes (if this is used, then stream.Read() below doesn't work.
          //var compressedBytes = bytesSent.ToStream().GZipCompress();
          //stream.Write(compressedBytes, 0, compressedBytes.Length);
  
          // send normal bytes (uncompressed)
          stream.Write(bytesSent, 0, bytesSent.Length);
  
          // GET RESPONSE
          byte[] bytesReceived = new byte[client.ReceiveBufferSize];
          // PROBLEM HERE: when using compression, this line just gets skipped over very quickly
          stream.Read(bytesReceived, 0, client.ReceiveBufferSize);
  
          //var decompressedBytes = bytesReceived.ToStream().GZipDecompress();
          //string response = Encoding.UTF8.GetString(decompressedBytes);
  
          string response = Encoding.UTF8.GetString(bytesReceived);
  
          Console.WriteLine(response);
      }
  }
  </code></pre>
  
  <p>You will notice some extension methods above. Here is the code in case you are wondering if something is wrong there.</p>
  
  <pre><code>public static MemoryStream ToStream(this byte[] bytes)
  {
      return new MemoryStream(bytes);
  }
  
  
  public static byte[] GZipCompress(this Stream stream)
  {
      using (var memoryStream = new MemoryStream())
      {
          using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Compress))
          {
              stream.CopyTo(gZipStream);
          }
          return memoryStream.ToArray();
      }
  }
  
  public static byte[] GZipDecompress(this Stream stream)
  {
      using (var memoryStream = new MemoryStream())
      {
          using (var gZipStream = new GZipStream(stream, CompressionMode.Decompress))
          {
              gZipStream.CopyTo(memoryStream);
          }
          return memoryStream.ToArray();
      }
  }
  </code></pre>
  
  <p>The extensions work quite well in the following, so I'm sure they're not the problem:</p>
  
  <pre><code>string original = "the quick brown fox jumped over the lazy dog";
  byte[] compressedBytes = Encoding.UTF8.GetBytes(original).ToStream().GZipCompress();
  byte[] decompressedBytes = compressedBytes.ToStream().GZipDecompress();
  string result = Encoding.UTF8.GetString(decompressedBytes);
  Console.WriteLine(result);
  </code></pre>
  
  <p>Does anyone have any idea why the Read() operation is being skipped when the bytes being sent are compressed?</p>
  
  <p><strong>EDIT</strong></p>
  
  <p>I received a message from the API provider after showing them the above sample code. They had this to say:</p>
  
  <blockquote>
    <p>at a first glance I guess the header is missing. The input must start
    with a 'c' followed by the length of the input
    (sprintf(cLength,"c%09d",hres) in our example). We need this because
    we can't read until we find a binary 0 to recognize the end.</p>
  </blockquote>
  
  <p>They previously provided some sample code in <code>C</code>, which I don't fully understand 100%, as follows:</p>
  
  <pre><code>example in C:
  
  #include &lt;zlib.h&gt;
  
  uLongf hres;
  char cLength[COMPRESS_HEADER_LEN + 1] = {'\0'};
  
  n = read(socket,buffer,10);
  // check if input is compressed
  if(msg[0]=='c') {
       compressed = 1;
  }
  
  n = atoi(msg+1);
  read.....
  
  
  hres = 64000;
  res = uncompress((Bytef *)msg,   &amp;hres, (const Bytef*) 
  buffer/*compressed*/, n);
  if(res == Z_OK &amp;&amp; hres &gt; 0 ){
       msg[hres]=0; //original
  }
  else // errorhandling
  
  hres = 64000;
  
  if (compressed){
  res = compress((Bytef *)buffer,   &amp;hres, (const Bytef *)msg, strlen(msg));
       if(res == Z_OK &amp;&amp; hres &gt; 0 ) {
           sprintf(cLength,"c%09d",hres);
           write(socket,cLength,10);
           write(socket, buffer, hres);
       }
       else // errorhandling
  
  makefile: add "-lz" to the libs
  </code></pre>
  
  <p>They're using zlib. I don't suspect that to make any difference, but I did try using zlib.net and I still get no response anyway.</p>
  
  <p>Can someone give me an example of how exactly I'm supposed to send this input length in C#?</p>
  
  <p><strong>EDIT 2</strong></p>
  
  <p>In response to @quantdev, here is what I am trying now for the length prefix:</p>
  
  <pre><code>using (var client = new TcpClient())
  {
      client.Connect("xxx.xxx.xx.xx", 6100);
      using (var stream = client.GetStream())
      {
          // SEND REQUEST
          byte[] bytes = Encoding.UTF8.GetBytes(xml);
          byte[] compressedBytes = ZLibCompressor.Compress(bytes);
  
          byte[] prefix = Encoding.UTF8.GetBytes("c" + compressedBytes.Length);
  
          byte[] bytesToSend = new byte[prefix.Length + compressedBytes.Length];
          Array.Copy(prefix, bytesToSend, prefix.Length);
          Array.Copy(compressedBytes, 0, bytesToSend, prefix.Length, compressedBytes.Length);
  
          stream.Write(bytesToSend, 0, bytesToSend.Length);
  
          // WAIT
          while (client.Available == 0)
          {
              Thread.Sleep(1000);
          }
  
          // GET RESPONSE
          byte[] bytesReceived = new byte[client.ReceiveBufferSize];
          stream.Read(bytesReceived, 0, client.ReceiveBufferSize);
  
          byte[] decompressedBytes = ZLibCompressor.DeCompress(bytesReceived);
          string response = Encoding.UTF8.GetString(decompressedBytes);
  
          Console.WriteLine(response);
      }
  }
  </code></pre>