我正在编写一个基于客户端/服务器的应用程序,它在本地网络上工作,在客户端和服务器之间交换数据,我创建了一个非常简单的NetworkCommand
对象,转换为byte[]
并发送使用TCP
或UDP
。
问题是正确标记end-of-packed
,
现在我使用了byte[] {0, 0, 0}
和数据包结束标记,但在整个数据包本身中似乎重复了这么多次。
那么,我如何安全地标记 end-of-packet
?
NetworkCommand.cs
using System;
using System.IO;
namespace Cybotech.Common
{
public enum CommandType
{
NeedIP = 1,
IPData = 2,
}
public class NetworkCommand
{
public NetworkCommand(CommandType type, byte[] data)
{
Command = type;
Data = data;
}
public int Length
{
get { return Data.Length; }
}
public byte[] Data { get; set; }
public CommandType Command { get; set; }
public byte[] ToBytes()
{
MemoryStream stream = new MemoryStream();
//write the command type
byte[] data = BitConverter.GetBytes((int) Command);
stream.Write(data, 0, data.Length);
//append the length of the data
data = BitConverter.GetBytes(Length);
stream.Write(data, 0, data.Length);
//write the data
stream.Write(Data, 0, Data.Length);
//end of packer marker
data = new byte[] {0, 0, 0};
stream.Write(data, 0, 3);
data = stream.ToArray();
stream.Close();
stream.Dispose();
return data;
}
public static NetworkCommand CreateNetworkCommand(byte[] bytes)
{
MemoryStream stream = new MemoryStream(bytes);
BinaryReader reader = new BinaryReader(stream);
CommandType type = (CommandType) reader.ReadInt32();
int length = reader.ReadInt32();
byte[] data = reader.ReadBytes(length);
byte[] endMarker = reader.ReadBytes(3);
NetworkCommand cmd = new NetworkCommand(type, data);
reader.Close();
stream.Close();
stream.Dispose();
return cmd;
}
}
}
答案 0 :(得分:2)
一种策略是开始数据包,例如,一个表示数据包大小的4字节数字,并使用适当数量的有效负载数据字节跟随它。然后,您确切地知道接收端需要读取多少数据。
TCP是一种可靠的协议,因此您无需过于关注同步。另一方面,它是面向流的,并且由于您使用的是基于数据包的应用程序层,您可能会发现使用UDP是更容易的,这是面向消息的。
如果使用UDP,则可以使用4字节长度,后跟任意“开始”字符(如[
),然后使用有效负载,最后使用“停止”字符(如{{1 }})。如果您读取的数据包不以停止字符结尾,则可以将其丢弃,并继续通过下一个停止字符丢弃数据。但是,您需要一种方法来要求发送方重新传输丢失的数据。
一个好的协议利用底层,因此您不需要复制它们的功能。