【发布时间】:2014-07-25 22:33:39
【问题描述】:
在通过 TCP 套接字发送和接收压缩数据方面需要帮助。
如果我不使用压缩,代码工作得非常好,但是当我使用压缩时会发生一些非常奇怪的事情。基本上,问题是 stream.Read() 操作被跳过,我不知道为什么..
我的代码:
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);
}
}
您会注意到上面的一些扩展方法。这是代码,以防您想知道那里是否有问题。
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();
}
}
这些扩展在以下情况下运行良好,所以我确信它们不是问题:
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);
有谁知道为什么在发送的字节被压缩时会跳过 Read() 操作?
编辑
在向 API 提供商展示上述示例代码后,我收到了一条消息。他们有话要说:
乍一看,我猜标题丢失了。输入必须开始 带有“c”,后跟输入的长度 (在我们的示例中为 sprintf(cLength,"c%09d",hres))。我们需要这个,因为 在我们找到一个二进制 0 来识别结尾之前,我们无法读取。
他们之前在C中提供了一些示例代码,我也不是100%完全看懂,如下:
example in C:
#include <zlib.h>
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, &hres, (const Bytef*)
buffer/*compressed*/, n);
if(res == Z_OK && hres > 0 ){
msg[hres]=0; //original
}
else // errorhandling
hres = 64000;
if (compressed){
res = compress((Bytef *)buffer, &hres, (const Bytef *)msg, strlen(msg));
if(res == Z_OK && hres > 0 ) {
sprintf(cLength,"c%09d",hres);
write(socket,cLength,10);
write(socket, buffer, hres);
}
else // errorhandling
makefile: add "-lz" to the libs
他们正在使用 zlib。我不怀疑这有什么不同,但我确实尝试过使用 zlib.net,但我仍然没有得到任何回应。
谁能给我一个例子,说明我应该如何在 C# 中发送这个输入长度?
编辑 2
作为对@quantdev 的回应,这是我现在正在尝试的长度前缀:
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);
}
}
【问题讨论】:
-
跳过是什么意思?调用后接收到的字节长度是多少?
-
我的意思是跳过是它只是立即执行该行并移动到下一行。如果我不使用压缩,应用会在
stream.Read()处等待大约 60 秒左右,直到有数据继续运行 -
您应该在继续之前验证 Read() 调用的返回值。另外,您是否考虑过异步客户端? msdn.microsoft.com/en-us/library/bbx2eya8.aspx
标签: c# sockets tcp compression