C# 如何通过TCP流发送对象?
我正在尝试设置一个接口,以便使用TCP连接在客户端和服务器之间发送序列化对象 我使用以下类和扩展方法从流中读取和写入这些对象:C# 如何通过TCP流发送对象?,c#,tcp,C#,Tcp,我正在尝试设置一个接口,以便使用TCP连接在客户端和服务器之间发送序列化对象 我使用以下类和扩展方法从流中读取和写入这些对象: public class NetworkTransmittedUpdate { /// <summary> /// The type of update that is being sent /// </summary> public UpdateType UpdateType { get; init; }
public class NetworkTransmittedUpdate
{
/// <summary>
/// The type of update that is being sent
/// </summary>
public UpdateType UpdateType { get; init; }
/// <summary>
/// The type that UpdateObject should be deserialized as. Should match one of the types in SerializedTypes
/// </summary>
public string UpdateObjectType { get; init; } = string.Empty;
/// <summary>
/// Any information that accompanies the update. Each update type has an associated UpdateObject type, which is
/// usually but not always the same for both frontend and backend. UpdateObject may be null if only the event
/// happening must be conveyed.
/// </summary>
public object? UpdateObject { get; init; }
}
public static class StreamExtensions
{
/// <summary>
/// Attempts to read a serialized object from the stream, convert it, and return it
/// </summary>
/// <param name="stream">The stream to read from</param>
/// <typeparam name="T">The type of object to deserialize</typeparam>
/// <returns>An instance of the object, or null if it could not be created</returns>
public static T? ReadObject<T>(this Stream stream) where T : class
{
// Get length of incoming object
var sizeBuffer = new byte[sizeof(int)];
var bytesRead = 0;
Debug.Assert(stream.CanRead);
while (bytesRead < sizeBuffer.Length)
bytesRead += stream.Read(sizeBuffer, bytesRead, sizeBuffer.Length - bytesRead);
// Create a buffer for serialized data
var serializationLength = BitConverter.ToInt32(sizeBuffer);
var serializedDataBuffer = new byte[serializationLength];
// Get data from the stream
bytesRead = 0;
while (bytesRead < serializationLength)
bytesRead += stream.Read(serializedDataBuffer, bytesRead, serializationLength - bytesRead);
// Deserialize data into an object
var json = Encoding.UTF8.GetString(serializedDataBuffer);
// Deserialize the wrapped type correctly using reflection
var deserializedObject = JsonSerializer.Deserialize<T>(json);
if (deserializedObject is NetworkTransmittedUpdate {UpdateObject: { }} dynamicUpdateWrapper)
{
// In this block, we know we are wrapping data. The deserializer doesn't choose the write type by default, so we need to create a new
var innerData = dynamicUpdateWrapper.UpdateObject!.ToString();
var innerDataType = Type.GetType(dynamicUpdateWrapper.UpdateObjectType);
return new NetworkTransmittedUpdate
{
UpdateType = dynamicUpdateWrapper.UpdateType,
UpdateObjectType = dynamicUpdateWrapper.UpdateObjectType,
UpdateObject = JsonSerializer.Deserialize(innerData ?? string.Empty, innerDataType!)
} as T;
}
return deserializedObject;
}
/// <summary>
/// Serializes and writes an object to a stream
/// </summary>
/// <param name="stream">The stream to write UTF-8 data to</param>
/// <param name="value">An object to serialize and write</param>
/// <typeparam name="T">A serializable type</typeparam>
public static void WriteObject<T>(this Stream stream, T value)
{
var json = JsonSerializer.Serialize(value);
var bytes = Encoding.UTF8.GetBytes(json);
// Always send a number of bytes ahead, so the other side knows how much to read
stream.Write(BitConverter.GetBytes(bytes.Length));
// Send serialized data
stream.Write(bytes);
stream.Flush();
}
}
公共类网络传输数据
{
///
///正在发送的更新的类型
///
public UpdateType UpdateType{get;init;}
///
///UpdateObject应反序列化为的类型。应与SerializedTypes中的一种类型匹配
///
公共字符串UpdateObjectType{get;init;}=string.Empty;
///
///随更新而来的任何信息。每个更新类型都有一个关联的UpdateObject类型,即
///对于前端和后端,通常是相同的,但并不总是相同的。如果只有
///必须传达发生的事情。
///
公共对象?更新对象{get;init;}
}
公共静态类StreamExtensions
{
///
///尝试从流中读取序列化对象,将其转换并返回
///
///要读取的流
///要反序列化的对象的类型
///对象的实例,如果无法创建,则为null
公共静态T?ReadObject(此流),其中T:class
{
//获取传入对象的长度
var sizeBuffer=新字节[sizeof(int)];
var bytesRead=0;
Assert(stream.CanRead);
while(字节读取
由于某种原因,下面的测试在读取要发送的对象的长度时被卡住
[Fact]
public void TestChatMessageNetworkPackets()
{
// Setup
var listener = new TcpListener(IPAddress.Any, 12321);
listener.Start();
using var client = new TcpClient("localhost", 12321);
using var server = listener.AcceptTcpClient();
using var clientStream = client.GetStream();
using var serverStream = server.GetStream();
// Send and receive chat message
clientStream.WriteObject(new NetworkTransmittedUpdate()
{
UpdateObject = new string("Test message"),
UpdateType = UpdateType.ChatMessage,
UpdateObjectType = typeof(string).FullName!
});
var update = clientStream.ReadObject<NetworkTransmittedUpdate>();
}
[事实]
public void TestChatMessageNetworkPackets()
{
//设置
var listener=newtcplistener(IPAddress.Any,12321);
listener.Start();
使用var client=newtcpclient(“localhost”,12321);
使用var server=listener.AcceptTcpClient();
使用var clientStream=client.GetStream();
使用var serverStream=server.GetStream();
//发送和接收聊天信息
clientStream.WriteObject(新的NetworkTransmittedDupDate()
{
UpdateObject=新字符串(“测试消息”),
UpdateType=UpdateType.ChatMessage,
UpdateObjectType=typeof(string).FullName!
});
var update=clientStream.ReadObject();
}
更改此选项:
var update = clientStream.ReadObject<NetworkTransmittedUpdate>();
var update=clientStream.ReadObject();
为此:
var update = serverStream.ReadObject<NetworkTransmittedUpdate>();
var update=serverStream.ReadObject();
你想在客户端流上写,然后在服务器流上读,因为服务器流在围栏的另一端。你将它们序列化为字节,发送它们并在另一端反序列化。与其发明自己的第7层网络协议,为什么不使用现成的东西,比如HTTP?