序列化对象准备通过TCPClient Stream发送

我已经使用TcpListenerTcpClient设置了服务器和客户端。

我想将一个对象发送到我的服务器应用程序进行处理。

我已经发现了using System.Runtime.Serialization和以下文档 ,但我不想发现我正在以漫长的方式做这件事。

问题:通过TCP流处理和发送对象的最佳方法是什么?

发送和接收。

这是我的对象的一个​​例子:

 // Create a new house to send house newHouse = new house(); // Set variables newHouse.street = "Mill Lane"; newHouse.postcode = "LO1 BT5"; newHouse.house_number = 11; newHouse.house_id = 1; newHouse.house_town = "London"; 

假设您有一个类House (在您的连接的两侧都可用),如下所示:

 [Serializable] public class House { public string Street { get; set; } public string ZipCode { get; set; } public int Number { get; set; } public int Id { get; set; } public string Town { get; set; } } 

您可以将类序列化为MemoryStream 。 然后,您可以在TcpClient连接中使用,如下所示:

 // Create a new house to send house and set values. var newHouse = new House { Street = "Mill Lane", ZipCode = "LO1 BT5", Number = 11, Id = 1, Town = "London" }; var xmlSerializer = new XmlSerializer(typeof(House)); var networkStream = tcpClient.GetStream(); if (networkStream.CanWrite) { xmlSerializer.Serialize(networkStream, newHouse); } 

当然,你必须做一些调查才能让程序毫无例外地运行。 (例如,检查memoryStream.Length不要大于int,aso),但我希望我给你正确的建议,以帮助你的方式;-)

您的答案意味着以下对象(通常的做法是使用camel case命名类):

 [Serializable] class House:ISerializable { public string Street {get; set;} public string PostalCode {get; set;} public int HouseNumber {get; set;} public int HouseID {get; set;} public string City {get; set;} public House() { } protected House(SerializationInfo info, StreamingContext context) { if (info == null) throw new System.ArgumentNullException("info"); Street = (string)info.GetValue("Street ", typeof(string)); PostalCode = (string)info.GetValue("PostalCode", typeof(string)); HouseNumber = (int)info.GetValue("HouseNumber", typeof(int)); HouseID = (int)info.GetValue("HouseID", typeof(int)); City = (string)info.GetValue("City", typeof(string)); } [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)] void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { if (info == null) throw new System.ArgumentNullException("info"); info.AddValue("Street ", Street); info.AddValue("PostalCode", PostalCode); info.AddValue("HouseNumber", HouseNumber); info.AddValue("HouseID", HouseID ); info.AddValue("City", City); } } 

现在您可以序列化您的对象:

 void Send(Stream stream) { BinaryFormatter binaryFmt = new BinaryFormatter(); House h = new House() { Street = "Mill Lane", PostalCode = "LO1 BT5", HouseNumber = 11, HouseID = 1, City = "London" }; binaryFmt.Serialize(stream, h); } 

您可以使用[Serializable]属性简单地装饰您的House类。 (您不需要定义其他答案中公布的所有其他内容)

然后,您可以通过使用BinaryFormatter类对其进行序列化来在线上发送此对象。

您是否考虑过设置WCF服务而不是使用TcpListener和TcpClient? 让生活更轻松。

例如,您可以定义返回房屋的服务

 [ServiceContract] public interface IService { [OperationContract] House GetHouse(int houseId); } 

看到这个真实世界的例子。

您如何将xml House流反序列化回接收端的House对象? 我正在参考Fischermaen的回答中给出的解决方案。

在我的接收结束时,我可以使用以下内容在“输出”窗口中看到字符串表示:

 ASCIIEncoding encoder = new ASCIIEncoding(); System.Diagnostics.Debug.WriteLine(encoder.GetString(message, 0, bytesRead)); 

先感谢您。

编辑*

好的,这个解决方案对我有用。 可能需要一些整理。

这是一个反序列化字符串的方法:

 public static T DeserializeFromXml(string xml) { T result; XmlSerializer ser = new XmlSerializer(typeof(T)); using (TextReader tr = new StringReader(xml)) { result = (T)ser.Deserialize(tr); } return result; } 

然后从我的TPC / IP接收结束我调用这样的方法:

 TcpClient tcpClient = (TcpClient)client; NetworkStream clientStream = tcpClient.GetStream(); byte[] message = new byte[4096]; int bytesRead; while (true) { bytesRead = 0; try { //blocks until a client sends a message bytesRead = clientStream.Read(message, 0, 4096); } catch { //a socket error has occured break; } if (bytesRead == 0) { //the client has disconnected from the server break; } //message has successfully been received ASCIIEncoding encoder = new ASCIIEncoding(); System.Diagnostics.Debug.WriteLine(encoder.GetString(message, 0, bytesRead)); House house = DeserializeFromXml(encoder.GetString(message, 0, bytesRead)); //Send Message Back byte[] buffer = encoder.GetBytes("Hello Client - " + DateTime.Now.ToLongTimeString()); clientStream.Write(buffer, 0, buffer.Length); clientStream.Flush(); } tcpClient.Close(); } 

首先创建一个空的ServerApplication和ClientApplication作为控制台应用程序来简化示例。

然后,将可序列化对象的定义放入单独的程序集中,然后将共享程序集的引用添加到每个项目(服务器和客户端)。 必要的是共享相同的对象,而不仅仅是相同的类副本。

解决方案资源管理器>添加新项目中解决方案’ServerApplication’生成DLL >右clic … – >选择类库(例如,将此项目命名为MySharedHouse )将默认Class1重命名为House并完成它

 [Serializable] public class House { public string Street { get; set; } public string ZipCode { get; set; } public int Number { get; set; } public int Id { get; set; } public string Town { get; set; } } 

在此处输入图像描述

在MySharedHouse和Build中正确的clic。

现在构建了dll,我们需要在Server Project和Client Project中添加它。 对于此示例,在ServerApplication> Add Reference> Browse中找到正确的clic并找到dll

项目\ ServerApplication \ MySharedHouse \ BIN \调试\ MySharedHouse.dll

使用相同的dll(相同路径)在ClientApplication中重复此过程。

现在,您可以将ServerApplication和ClientApplication中的House类实例用作单个对象,只需在顶部添加“使用MySharedHouse”这一句子即可

服务器代码

 using System; using System.Net; using System.Net.Sockets; using System.Runtime.Serialization.Formatters.Binary; using System.Threading; using MySharedHouse; namespace ServerApplication { class Program { static void Main(string[] args) { MessageServer s = new MessageServer(515); s.Start(); } } public class MessageServer { private int _port; private TcpListener _tcpListener; private bool _running; private TcpClient connectedTcpClient; private BinaryFormatter _bFormatter; private Thread _connectionThread; public MessageServer(int port) { this._port = port; this._tcpListener = new TcpListener(IPAddress.Loopback, port); this._bFormatter = new BinaryFormatter(); } public void Start() { if (!_running) { this._tcpListener.Start(); Console.WriteLine("Waiting for a connection... "); this._running = true; this._connectionThread = new Thread (new ThreadStart(ListenForClientConnections)); this._connectionThread.Start(); } } public void Stop() { if (this._running) { this._tcpListener.Stop(); this._running = false; } } private void ListenForClientConnections() { while (this._running) { this.connectedTcpClient = this._tcpListener.AcceptTcpClient(); Console.WriteLine("Connected!"); House house = new House(); house.Street = "Evergreen Terrace"; house.ZipCode = "71474"; house.Number = 742; house.Id = 34527; house.Town = "Springfield"; _bFormatter.Serialize(this.connectedTcpClient.GetStream(), house); Console.WriteLine("send House!"); } } } } 

客户代码

 using System; using System.Net.Sockets; using System.Runtime.Serialization.Formatters.Binary; using System.Threading; using MySharedHouse; namespace ClientApplication { class Program { static void Main(string[] args) { MessageClient client = new MessageClient(515); client.StartListening(); } } public class MessageClient { private int _port; private TcpClient _tcpClient; private BinaryFormatter _bFormatter; private Thread _listenThread; private bool _running; private House house; public MessageClient(int port) { this._port = port; this._tcpClient = new TcpClient("127.0.0.1", port); this._bFormatter = new BinaryFormatter(); this._running = false; } public void StartListening() { lock (this) { if (!_running) { this._running = true; this._listenThread = new Thread (new ThreadStart(ListenForMessage)); this._listenThread.Start(); } else { this._running = true; this._listenThread = new Thread (new ThreadStart(ListenForMessage)); this._listenThread.Start(); } } } private void ListenForMessage() { Console.WriteLine("Reading..."); try { while (this._running) { this.house = (House)this._bFormatter.Deserialize(this._tcpClient.GetStream()); Console.WriteLine(this.house.Street); Console.WriteLine(this.house.ZipCode); Console.WriteLine(this.house.Number); Console.WriteLine(this.house.Id); Console.WriteLine(this.house.Town); } } catch (Exception e) { Console.WriteLine(e); Console.ReadLine(); } } } } 

Wooala! 第一个通过TCP / IP发送的房子