2011-10-21 36 views
4

我有一個服務器和客戶端設置使用TcpListenerTcpClient序列化對象準備發送通過TCPClient流

我想發送一個對象到我的服務器應用程序進行處理。

我發現了using System.Runtime.Serialization和以下documentation,但我並不想費盡周折才發現我正在以冗長的方式做這件事。

問題:通過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"; 

回答

7

假設你有一個類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,a.s.o.更高),但我希望我給你正確的建議,以幫助你的方式;-)

+2

您可以直接序列化到tcpClient的流。 –

+0

@ L.B:感謝您的提示,我以這種方式改變了樣本! – Fischermaen

2

你的回答意味着下列對象(通常的做法是使用駝峯名班):

[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); 
} 
2

你可以簡單地用[Serializable]屬性裝飾你House類。 (您不需要像在其他答案中一樣定義所有其他內容)

然後,您可以通過使用BinaryFormatter類對其進行序列化來發送此對象。

您是否考慮設置WCF服務而不是使用TcpListener和TcpClient?讓生活變得更輕鬆。

例如,你可以定義返回家中的服務

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

this現實世界的例子。

1

如何將xml House流反序列化回接收端的House對象? 我指的是Fischermaen回答中給出的解決方案。

在我recieving結束時,我可以用下面的看到我的輸出窗口字符串表示:

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; 
    } 
從我的TPC/IP Recieving結束

然後我打電話像方法,以便:

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(); 
    } 
0

首先創建一個空的ServerApplication和ClientApplication作爲控制檯應用程序來簡化示例。

然後,將可序列化對象的定義放入一個單獨的程序集中,然後將共享程序集的引用添加到每個項目(服務器和客戶機)。需要共享同一個對象,而不僅僅是相同的類副本。

來生成DLL> 右鍵集團公司在Solution Explorer中解決方案 'ServerApplication'>添加新項目... - >選擇類庫 (如將此項目命名爲MySharedHouse) 重命名默認的Class1到房子並完成它

[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; } 
} 

enter image description here

在MySharedHouse和Build中右鍵點擊。

現在這個dll已經建好了,我們需要將它添加到Server Project和Client Project中。在ServerApplication 右CLIC>添加引用>瀏覽和查找DLL,在這個例子中

項目\ ServerApplication \ MySharedHouse \ BIN \調試\ MySharedHouse.dll

重複使用在ClientApplication過程相同的DLL(相同的路徑)。

現在,您可以在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發送的房屋

相關問題