通过TCP套接字发送和接收压缩数据
本文关键字:压缩 数据 TCP 套接字 通过 | 更新日期: 2023-09-27 18:06:53
需要帮助通过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);
有没有人知道为什么读取()操作被跳过时发送的字节被压缩?
编辑
在向API提供程序展示了上面的示例代码之后,我收到了一条来自API提供程序的消息。他们是这么说的:乍一看,我猜标题不见了。输入必须开始用'c'后跟输入的长度(在我们的示例中,sprintf(length,"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);
}
}
您需要检查您在TCP流上进行的Read()调用的返回值:它是有效读取的字节数。
MSDN显示:
读取到缓冲区的总字节数。如果没有那么多字节,这个值可以小于请求的字节数当前可用,如果流的末尾为0,则为零(0)达成。
- 如果套接字已关闭,调用将立即返回0(这就是这里可能发生的情况)。
- 如果不是0,那么你必须检查你实际接收了多少字节,如果它少于
client.ReceiveBufferSize
,你将需要额外调用Read
来检索剩余的字节。
在调用read之前,检查套接字上是否有数据可用:
while(client.Available == 0)
// wait ...
http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.available%28v=vs.110%29.aspx 我想你可能已经看到文件的结尾了。在读取流
之前,您可以尝试设置流位置吗?stream.position = 0;
http://msdn.microsoft.com/en-us/library/vstudio/system.io.stream.read Encoding.UTF8。GetString不应该在任意字节数组上使用。例如:压缩字节可能包含NULL字符,这在UTF-8编码的文本中是不允许的,除非用作结束符。
如果你想打印接收到的字节用于调试,也许你应该把它们打印成整数。