gpt4 book ai didi

c# - 通过 TCP 套接字发送和接收压缩数据

转载 作者:可可西里 更新时间:2023-11-01 02:49:07 25 4
gpt4 key购买 nike

在通过 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 提供商的消息。他们是这样说的:

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.

之前他们提供了一些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);
}
}

最佳答案

您需要检查 return value of the Read() calls you are making on the TCP stream : 有效读取的字节数。

MSDN 说:

Return Value

The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached.

  • 如果套接字已关闭,调用将立即返回 0(这可能是此处发生的情况)。
  • 如果不为 0,则您必须检查您实际收到了多少字节,如果它小于 client.ReceiveBufferSize,您将需要额外调用 Read 以检索剩余的字节。

在调用 read 之前,检查一些数据实际上是 available在套接字上:

while(client.Available == 0)
// wait ...

http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.available%28v=vs.110%29.aspx

关于c# - 通过 TCP 套接字发送和接收压缩数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24051610/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com