C# 序列化对象准备通过TCPClient流发送
我已经使用C# 序列化对象准备通过TCPClient流发送,c#,serialization,tcp,tcpclient,tcplistener,C#,Serialization,Tcp,Tcpclient,Tcplistener,我已经使用TcpListener和TcpClient设置了服务器和客户端 我想将一个对象发送到我的服务器应用程序进行处理 我使用System.Runtime.Serialization和下面的方法发现了,但我不想东拉西扯地发现我是在用冗长的方式做这件事 问题:通过TCP流处理和发送对象的最佳方式是什么 发送和接收 下面是我的对象的一个示例: // Create a new house to send house newHouse = new house(); // Set variables
TcpListener
和TcpClient
设置了服务器和客户端
我想将一个对象发送到我的服务器应用程序进行处理
我使用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";
您的答案暗示了以下对象(通常使用命名类):
现在,您可以序列化对象:
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]
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; }
}
// 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);
}
您可以将该类序列化为内存流
。然后,您可以在TcpClient
连接中这样使用:
[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; }
}
// 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,a.s.o.),但我希望我给了您正确的建议,以帮助您前进;-) 你可以简单地用[Serializable]
属性装饰你的房子
类。(您不需要定义其他答案中发布的所有其他内容)
然后,您可以通过使用BinaryFormatter
类对该对象进行序列化,从而在线发送该对象
您是否考虑过设置WCF服务而不是使用TcpListener和TcpClient?让生活变得容易多了
例如,您可以定义一个返回房屋的服务
[ServiceContract]
public interface IService
{
[OperationContract]
House GetHouse(int houseId);
}
请参阅实际示例。如何将xml房屋流反序列化回接收端的房屋对象?
我指的是Fischermaen回答中给出的解决方案
在我的接收端,我可以使用以下命令在我的输出窗口中看到字符串表示:
ASCIIEncoding encoder = new ASCIIEncoding();
System.Diagnostics.Debug.WriteLine(encoder.GetString(message, 0, bytesRead));
先谢谢你
编辑*
好吧,这个解决方案对我很有效。可能需要整理一下
下面是一个反序列化字符串的方法:
public static T DeserializeFromXml<T>(string xml)
{
T result;
XmlSerializer ser = new XmlSerializer(typeof(T));
using (TextReader tr = new StringReader(xml))
{
result = (T)ser.Deserialize(tr);
}
return result;
}
publicstatict反序列化fromXML(字符串xml)
{
T结果;
XmlSerializer ser=新的XmlSerializer(typeof(T));
使用(TextReader tr=new StringReader(xml))
{
结果=(T)序列反序列化(tr);
}
返回结果;
}
然后从我的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<House>(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();
}
TcpClient TcpClient=(TcpClient)客户端;
NetworkStream clientStream=tcpClient.GetStream();
字节[]消息=新字节[4096];
int字节读取;
while(true)
{
字节读取=0;
尝试
{
//阻塞,直到客户端发送消息
bytesRead=clientStream.Read(消息,04096);
}
抓住
{
//发生套接字错误
打破
}
如果(字节读==0)
{
//客户端已断开与服务器的连接
打破
}
//消息已成功接收
ascienceoding编码器=新的ascienceoding();
System.Diagnostics.Debug.WriteLine(encoder.GetString(message,0,bytesRead));
House=DeserializeFromXml(encoder.GetString(message,0,bytesRead));
//发回消息
byte[]buffer=encoder.GetBytes(“Hello Client-”+DateTime.Now.ToLongTimeString());
Write(buffer,0,buffer.Length);
clientStream.Flush();
}
tcpClient.Close();
}
首先创建一个空的ServerApplication和ClientApplication作为控制台应用程序,以简化示例
然后,将可序列化对象的定义放入单独的程序集中,然后向每个项目(服务器和客户端)添加对共享程序集的引用。必须共享相同的对象,而不仅仅是相同的类副本
生成DLL>
在解决方案资源管理器>添加新项目中的解决方案“服务器应用程序”中右键单击…->选择类库
(例如,将此项目命名为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; }
}
正确的clic在我的共享房屋和建设
现在dll已经生成,我们需要将其添加到服务器项目和客户端项目中。
在ServerApplication>addreference>Browse中单击鼠标右键clic并查找dll,如本例所示
Projects\ServerApplication\MySharedHouse\bin\Debug\MySharedHouse.dll
使用相同的dll(相同路径)在ClientApplication中重复此过程
现在,您可以将ServerApplication和ClientApplication中的House类实例作为单个对象使用,只需在顶部添加一句话“using 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();
}
}
}
}
客户端代码
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();
}
}
}
}
哇!第一个通过TCP/IP发送的房屋您可以直接序列化到tcpClient的流。@L.B:谢谢您的提示,我用这种方式更改了示例!