需要有关通过TCP套接字发送和接收压缩数据的帮助。
如果我不使用压缩,代码可以正常工作,但是当我使用压缩时会发生一些非常奇怪的事情。基本上,问题是stream.Read()操作被跳过了,我不会&#39不知道为什么......
我的代码:
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);
}
}
答案 0 :(得分:1)
您需要检查return value of the Read() calls you are making on the TCP stream:它是有效读取的字节数。
MSDN说:
返回值
读入缓冲区的总字节数。如果没有多个字节,这可能小于请求的字节数 当前可用,如果流结束,则为零(0) 达到。
client.ReceiveBufferSize
,则需要额外调用Read
来检索剩余的字节。在您致电阅读之前,请检查套接字上的某些数据是否为available:
while(client.Available == 0)
// wait ...
http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.available%28v=vs.110%29.aspx
答案 1 :(得分:1)
我想你可能有文件结尾了。您可以在读取流之前尝试设置流位置
stream.position = 0;
http://msdn.microsoft.com/en-us/library/vstudio/system.io.stream.read
答案 2 :(得分:0)
Encoding.UTF8.GetString不应该用在任意字节数组上。 例如:压缩字节可能包含NULL字符,UTF-8编码文本中不允许使用该字符,除非用作终结符。
如果要打印接收的字节以进行调试,可能只需将它们打印为整数即可。