C# 通过TCP套接字发送和接收压缩数据
需要通过TCP套接字发送和接收压缩数据的帮助 如果我不使用压缩,代码可以很好地工作,但是当我使用压缩时,会发生一些非常奇怪的事情。。基本上,问题是stream.Read()操作被跳过,我不知道为什么 我的代码:C# 通过TCP套接字发送和接收压缩数据,c#,sockets,tcp,compression,C#,Sockets,Tcp,Compression,需要通过TCP套接字发送和接收压缩数据的帮助 如果我不使用压缩,代码可以很好地工作,但是当我使用压缩时,会发生一些非常奇怪的事情。。基本上,问题是stream.Read()操作被跳过,我不知道为什么 我的代码: using (var client = new TcpClient()) { client.Connect("xxx.xxx.xx.xx", 6100); using (var stream = client.GetStream()) { // S
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提供者展示了上面的示例代码之后,我收到了一条来自API提供者的消息。他们说:
乍一看,我想标题不见了。输入必须启动
输入的长度后面跟一个“c”
(在我们的示例中,sprintf(cLength,“c%09d”,hres)。我们需要这个是因为
在找到二进制0以识别结尾之前,我们无法读取
他们之前在C
中提供了一些示例代码,我不完全理解,如下所示:
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
您需要检查:它是有效读取的字节数
MSDN说:
返回值
读入缓冲区的总字节数。如果不需要那么多字节,则该值可以小于请求的字节数
当前可用,如果流的结尾已被删除,则为零(0)
达到
- 如果套接字关闭,调用将立即返回0(这里可能会发生这种情况)
- 如果不是0,则必须检查实际接收的字节数,如果小于
,则需要额外调用client.ReceiveBufferSize
来检索剩余字节Read
while(client.Available == 0)
// wait ...
我想你大概有文件的结尾了。您能在读取流之前尝试设置流位置吗
stream.position = 0;
Encoding.UTF8.GetString不应在任意字节数组上使用。 e、 g:压缩字节可能包含空字符,UTF-8编码文本中不允许包含空字符,除非用作终止符
如果要打印接收到的字节以进行调试,可能只需将它们打印为整数。跳过是什么意思?调用后接收到的字节长度是多少?我所说的跳过是指它在任何时候都只执行那一行,然后移动到下一行。如果我不使用压缩,应用程序将在
stream.Read()
处等待大约60秒,直到有数据后再继续。在继续之前,您应该验证Read()调用的返回值。另外,您考虑过异步客户机吗?谢谢@quantdev,但是使用while(client.Available==0)
似乎只会让它进入无限循环。我等了大约3分钟才放弃……是的,因为没有人向你的插座发送任何东西。这就是您需要检查它的原因:)(而且为了避免这些轮询循环,请使用异步Sockeets)谢谢-如果数据被压缩,API提供程序似乎没有发送任何内容,而且我似乎需要在请求中发送一些输入长度。请参阅上面的主要帖子中的我的编辑,如果您能提供帮助,那就太好了。@Matt,在bytessenterray前面加上'c'字符,后跟bytesSent
(在前面加上前缀)的长度(作为无符号长)。这基本上就是他们问你的问题。顺便说一句,我对你的第一个问题的第一个回答最终是正确的,不是吗关于你的第一个答案,我不确定它是否正确,因为没有压缩,它工作得很好。。发生的情况是(因为它是同步的),它只是等待一个响应(通常大约60秒),然后继续。我不需要特别告诉它等待。但无论如何,我已经实施了这个建议。。但就像我说的,我不知道它是否正确,因为当我用压缩数据测试它时,我并没有得到任何响应,最终会永远等待。稍后我也将实现异步套接字,但我想先让一个简单的示例开始工作。问题在前一行。正如我也说过的,如果数据没有被压缩,代码工作得非常好。
stream.position = 0;