如何在C#中通过TCP连接发送整数数组

4

我已经在Windows应用程序中建立了两台计算机之间的TCP连接,以便来回发送和接收数据。我要发送的消息是一组整数,转换为字符串并用“,”分隔。因此,为了发送数据,我会使用以下代码:

if (dataSend.Length > 0)
{
    m_writer.WriteLine(dataSend);
    m_writer.Flush();
}

这里,dataSend是我以字符串形式编写的消息,m_writer 是一个StreamWriter对象。

但是,现在我想将其作为整数数组通过同一网络连接发送,但找不到任何相关信息。我看到很多人使用字节数组,但是我不明白,在读取时,接收方如何知道如何将字节分割为相应的整数。

我意识到writeline方法也允许Int作为其参数,但我该如何发送数组?
对于字符串,它很清楚,因为我可以基于“,”分隔数据,所以我知道每个元素的结束位置。那么整数数组的分隔标准是什么?

如果有人能向我解释一下,那就太好了,因为我对C#的网络方面也还很陌生。

后续问题:StreamReader不停止读取C#

5个回答

4
你正在询问一个问题,通常情况下会使用序列化和/或数据帧来回答。也就是说,“如何通过网络发送一些结构体?”
你可以使用诸如XmlSerializer或JSON.NET库之类的序列化程序将你的int[]序列化为字符串。然后在另一端进行反序列化。
int[] numbers = new [] { 0, 1, 2, 3};
XmlSerializer serializer = new XmlSerializer(typeof(int[]));
var myString = serializer.Serialize(numbers);

// Send your string over the wire
m_writer.WriteLine(myString);
m_writer.Flush();

// On the other end, deserialize the data
using(var memoryStream = new MemoryStream(data))
{
    XmlSerializer serializer = new XmlSerializer(typeof(int[]));
    var numbers = (int[])serializer.Deserialize(memoryStream);
}

1
这是一种不错的开放式方法,但会浪费传输带宽。然而,如果带宽不是问题,那么你应该考虑采用某种标准化序列化作为解决方案,以便在故障排除时能够更好地阅读线上内容。 - John Castleman
2
是的,使用现有的序列化器的优点在于不必编写和测试自己的序列化器(如果要发送任何不太原始的内容,则必须这样做),并且还可以用于传输其他更复杂的结构。 - Alex Wiese
@alexw 好的,为了明确起见,我使用XmlSerializer来序列化整数数组,然后将序列化数据转换为字节数组,然后通过连接发送字节数组?在接收端,我可以使用内存流简单地读取字节数组,反序列化将其转换为整数数组? - Sanketh. K. Jain
基本上,您需要将数据作为byte[]通过套接字发送,这可以是字符串的字节数组表示形式(例如在您的情况下)。只要您有一种在一端对数据进行编码并在另一端进行解码的可靠方式,那么您的问题就得到解决了。 - Alex Wiese
1
这是一个比你想象中更好的方法,因为在双方都同意并使用的序列化中,代表了双方传输所同意的共同“字典”,而不是必须发明自己的语言(正如我的答案所建议的那样...这曾经是套接字通信的“事实标准”技术,在带宽变得非常便宜之前)。 - John Castleman
显示剩余4条评论

2

好的,一个简单的建议是您可以使用以下方法:

  • 发送方首先发送整数数组的长度。

  • 接收方创建一个数组来接收这个数据。

  • 发送方在循环中使用 WriteLine() 来发送数组的每个元素(作为字符串或整数)。

  • 接收方在循环中使用 ReadLine() 来捕获每个元素,并将接收到的字符串转换为整数。

发送方:

m_writer.WriteLine(myarray.Length); // Sender sends the array length prior to data transmission

// Send all data
foreach(int item in myarray){
      m_writer.WriteLine(item.ToString());
}

接收器:

int Size =Convert.ToInt32( m_reader.ReadLine()); //receiver receives the Length of incoming array 

int i=0;
// Receive all data
while(i < Size){
     Console.WrilteLine(Convert.ToInt32(m_reader.ReadLine())); // Add this to array
     i++;
}

2
我将为您提供一个答案,假设您想要实际传输字节以保持协议的轻量级:如果不是,请接受alexw的答案,因为那也是一个相当好的答案。
您应该查看某种形式的消息帧,或者至少长度前缀。我处理TCP套接字协议已经十多年了,总是使用某种形式的这种方式(主要是消息帧)。然而,最近我开始使用WCF,它使用(.NET)序列化,所以如果有无限带宽(和一种共同的架构,或至少在双方都同意的序列化算法),我实际上会倾向于alexw的答案。
编辑:
以下是使用简单长度前缀的示例:
var myArray = new byte[10];
using (var stream = new MemoryStream())
using (var writer = new BinaryWriter(stream))
{
    writer.Write(myArray.Length);
    foreach (var b in myArray)
        writer.Write(b);
}

当然,使用这种技术,双方都必须知道它的存在:你正在建立一个基于TCP的应用层协议,两端必须使用相同的语言交流(例如,知道长度存储在一个字节中,知道我们只发送简单的字节数组,没有更多上下文...参见消息帧以了解"更多上下文"可能是什么样子)。

我真的很喜欢你的回答,我会在以后的参考中使用它,所以非常感谢你的专业知识和对其他答案的贡献。我需要学习消息框架来了解我将要涉及的内容,所以谢谢你。在那之前,我会使用XML序列化,因为我之前处理过XML格式。 - Sanketh. K. Jain
没问题:我一直在推动alexw的答案成为被接受的答案,因为从可维护性/可移植性的角度来看,它是最好的。但还是谢谢你的赞同!(假设那是你) - John Castleman

1
你可以将数据序列化为XML,但缺点是对于这样一组简单的数字,你最终会创建一个臃肿的字符串。相反,你应该利用发送原始字节的能力。
要发送整数数组,你需要循环遍历整数数组,并依次将每个整数写入流中。使用Write方法,该方法接受一个整数。但你还需要指示另一端将发送多少个整数。因此,首先发送一个表示整数数量的数字...
int[] values = new int[] { 1, 2, 3 };
m_writer.Write(values.Length);
foreach(int value in values)
    m_write.Write(value);

在接收方,您读取一个整数,然后这是您需要读取整数以重新创建数组的次数。
int count = m_reader.ReadInt32();
int[] values = new byte[count];
for(int i=0; i<values; i++)
    values[i] = m_reader.ReadInt32();

显然我跳过了任何错误检查,但我将其留给读者作为练习!

0
使用 Encoding.GetBytes(string) 方法将字符串转换为字节数组,使用 Encoding.GetString(byte[]) 方法将字节数组转换回字符串。
byte[] arrBytes = Encoding.Default.GetBytes(dataSend);

转换回字符串
string dataRecieved = Encoding.Default.GetString(arrBytes);

请注意,在此处您可以使用固定的编码格式,因为发送方和接收方机器上的默认编码可能不同。

我现在想使用整数。而且,我不明白如何知道数据在字节中的分离。 - Sanketh. K. Jain
你可以将整数转换为字符串,然后再将接收到的字符串解析回整数。 - Rohit Prakash
是的,我可以这样做,但有没有一种不转换为字符串的方法? - Sanketh. K. Jain
1
  1. 这个答案会使需要传输的数据量增加一倍(每个字节都被编码为两个字节的字符)。
  2. 这并没有帮助他确定数组何时结束。
- John Castleman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接