[C#] 使用Socket進行資料傳輸 (Udp)
前言
最近由於專案的需求,必須接收C++程式所傳送過來的資訊給Wcf Service,
所以使用Socket寫了一個簡單的Proxy來當作Wcf和c++程式間的媒介,
並簡單實作了一個Hoster以及Sender方便Reuse
實際演練
在使用Socket傳輸的時候,為了方便可以直接傳送Class或是Struct,
所以在傳送之前,先對object進行序列化(Serialize),
當Server端收到後,再反序列化即可得到所需要的Class或Struct,
並且在Server端監聽訊息時,會獨自建立一條Thread來進行,
避免佔用main thread的空間,
同時在開始、結束、收到訊息時會觸發相對應的事件。
UdpSocketHoster.cs
public class UdpSocketHoster
{
#region Fields (3)
private Thread mListenThread;
private int mRecieverBuffer = 1024;
private Socket mSocket;
#endregion Fields
#region Properties (3)
public string Ip
{
get;
set;
}
public int Port
{
get;
set;
}
public int RecieverBuffer
{
get { return mRecieverBuffer; }
set { mRecieverBuffer = value; }
}
#endregion Properties
#region Delegates and Events (3)
// Events (3)
public event EventHandler<RecieveDataEventArgs> RecievedData;
public event EventHandler StartListening;
public event EventHandler StopListening;
#endregion Delegates and Events
#region Methods (4)
// Public Methods (3)
public void Start()
{
if (StartListening != null)
{
StartListening(this, new EventArgs());
}
mListenThread = new Thread(new ParameterizedThreadStart(startListen));
mListenThread.Start();
}
public void Start(string ip, int port)
{
this.Ip = ip;
this.Port = port;
Start();
}
public void Stop()
{
if (StopListening != null)
{
StopListening(this, new EventArgs());
}
mSocket.Close();
mListenThread.Abort();
}
// Private Methods (1)
private void startListen(object sender)
{
//Setting Endpoint
IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, Port);
mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
//Binding Endpoint
mSocket.Bind(endpoint);
//Getting Client Ip
IPEndPoint clientEndpoint = new IPEndPoint(IPAddress.Any, 0);
EndPoint Remote = (EndPoint)(clientEndpoint);
//Start loop for receiving data
while (true)
{
try
{
int recv;
byte[] receivePackage = new byte[mRecieverBuffer];
//Receive data from client
recv = mSocket.ReceiveFrom(receivePackage, ref Remote);
//Deserialize data
BinaryFormatter bf = new BinaryFormatter();
MemoryStream stream = new MemoryStream(receivePackage);
object data = bf.Deserialize(stream);
if (RecievedData != null)
{
RecievedData(this, new RecieveDataEventArgs(data));
}
}
catch (Exception ex)
{
throw;
}
}
}
#endregion Methods
}
RecieveDataEventArgs.cs
public class RecieveDataEventArgs : EventArgs
{
#region Fields (1)
private object mData;
#endregion Fields
#region Constructors (1)
public RecieveDataEventArgs(object data)
{
this.mData = data;
}
#endregion Constructors
#region Properties (1)
public object Data
{
get
{
return mData;
}
}
#endregion Properties
}
UdpSocketSender.cs
public class UdpSocketSender
{
#region Fields (1)
private int mPackageBuffer = 1024;
#endregion Fields
#region Constructors (1)
public UdpSocketSender(string ip, int port)
{
this.Ip = ip;
this.Port = port;
}
#endregion Constructors
#region Properties (3)
public string Ip { get; set; }
public int PackageBuffer
{
get { return mPackageBuffer; }
set { mPackageBuffer = value; }
}
public int Port { get; set; }
#endregion Properties
#region Methods (1)
// Public Methods (1)
public void Send(object data)
{
//Setting Server Endpoint
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(Ip), Port);
Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
//Serialize Data
byte[] package = new byte[mPackageBuffer];
BinaryFormatter bf = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
bf.Serialize(stream, data);
package = stream.ToArray();
//Send Data
server.SendTo(package, package.Length, SocketFlags.None, endPoint);
}
#endregion Methods
}
Server端
UdpSocketHoster hoster = new UdpSocketHoster();
hoster.RecievedData +=(o, e)=> Console.WriteLine(e.Data);
hoster.StartListening +=(o, e)=> Console.WriteLine("Start Hosting...");
hoster.StopListening +=(o, e)=> Console.WriteLine("Stop Hosting...");
hoster.Start("127.0.0.1", 8001);
Client端
UdpSocketSender sender = new UdpSocketSender("127.0.0.1", 8001);
sender.Send("Hi");
sender.Send("Hello");
sender.Send("How Are You?");
Console.Read();
結語
如此一來,在使用上就多了許多的彈性,
如果有任何問題,請大家多多指教囉 :)