最近趕活,連續在網上抄了好幾次代碼,很讓我覺得有點不好意思,因為我一般不大喜歡發程式碼片段,覺得沒啥意思。不過最近這個想法有所改變,大家互相抄抄有助於提高生產率嘛。。。
以下發一個通訊類,如需引用,請註明作者,謝謝。
/// <summary>/// Author:Scott.Yan/// Blog:http://www.cnblogs.com/moosdau/// </summary>public class Communication{ /// <summary> /// Get the first valid IPV4 address /// </summary> /// <returns></returns> public static System.Net.IPAddress GetLocalIP() { var host = System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName()); if (host.AddressList.Length < 1) throw new Exception("Can't find any valid IP address."); System.Net.IPAddress myIP = null; foreach (var p in host.AddressList) { if (!p.IsIPv6LinkLocal) { myIP = p; break; } } if (myIP == null) throw new Exception("Can't find any valid IPV4 address."); return myIP; } /// <summary> /// Communication based on TCP by Scott.Yan /// </summary> public class TCPManage { private Action<string> DgGetMsg; private System.Windows.Forms.Control Owner; /// <summary> /// indicate whether the thread should stop listening /// </summary> private bool IsListening = true; /// <summary> /// 1123 is the birthday of Scott.Yan who is the author of this class /// </summary> private const int TCPPort = 1123; private System.Threading.Thread thTCPListener; /// <summary> /// send message to others /// </summary> /// <param name="destinationIP">the destination ip ,e.g.,192.168.1.1</param> /// <param name="msg">message you want to send</param> public void SendMessage(string destinationIP, string msg) { byte[] buffer = System.Text.Encoding.UTF8.GetBytes(msg); var destIP = System.Net.IPAddress.Parse(destinationIP); var myIP = Communication.GetLocalIP(); var epDest = new System.Net.IPEndPoint(destIP, TCPPort); var dpLocal = new System.Net.IPEndPoint(myIP, TCPPort); var tcpClient = new System.Net.Sockets.TcpClient(); tcpClient.Connect(epDest); var netStream = tcpClient.GetStream(); if (netStream.CanWrite) netStream.Write(buffer, 0, buffer.Length); } /// <summary> /// call this method to start listening /// <param name="owner">formally you should pass "this"</param> /// <param name="dgGetMsg">a delegate handles when receive a message</param> /// </summary> public void StartListen(System.Windows.Forms.Control owner, Action<string> dgGetMsg) { IsListening = true; Owner = owner; DgGetMsg = dgGetMsg; thTCPListener = new System.Threading.Thread(ListenHandler); thTCPListener.Start(); } /// <summary> /// call this method to stop listening /// </summary> public void StopListen() { IsListening = false; } private void ListenHandler() { var myIP = Communication.GetLocalIP(); var epLocal = new System.Net.IPEndPoint(myIP, TCPPort); var tcpListener = new System.Net.Sockets.TcpListener(epLocal); tcpListener.Start(); while (IsListening) { System.Threading.Thread.Sleep(1000); if (tcpListener.Pending()) { var tcpClient = tcpListener.AcceptTcpClient(); var netStream = tcpClient.GetStream(); var buffer = new byte[1024]; if (!netStream.DataAvailable) continue; List<byte> bufferTotal = new List<byte>(); while (netStream.DataAvailable) { netStream.Read(buffer, 0, 1024); bufferTotal.AddRange(buffer); } tcpClient.Close(); netStream.Close(); var receive = System.Text.Encoding.UTF8.GetString(bufferTotal.ToArray()); Owner.Invoke(DgGetMsg, receive); } } tcpListener.Stop(); } } /// <summary> /// Communication based on UDP by Scott.Yan /// </summary> public class UDPManage { /// <summary> /// this is a group address /// </summary> private System.Net.IPAddress GroupIP = System.Net.IPAddress.Parse("224.0.0.2"); /// <summary> /// the birthday of Scott.Yan in Chinese lunar calendar /// </summary> private const int UDPPort = 1019; private System.Net.Sockets.UdpClient UdpClient; private System.Threading.Thread thUDPListener; private bool IsListening = true; private System.Windows.Forms.Control Owner; private Action<string> DgGetMsg; /// <summary> /// broadcast a message to others /// </summary> /// <param name="msg"></param> public void Broadcast(string msg) { var epGroup = new System.Net.IPEndPoint(GroupIP, UDPPort); var buffer = System.Text.Encoding.UTF8.GetBytes(msg); UdpClient.Send(buffer, buffer.Length, epGroup); } /// <summary> /// listen to the group /// </summary> /// <param name="owner">"this" in most case</param> /// <param name="dgGetMsg">handles message arriving</param> public void StartListen(System.Windows.Forms.Control owner, Action<string> dgGetMsg) { Owner = owner; DgGetMsg = dgGetMsg; IsListening = true; UdpClient = new System.Net.Sockets.UdpClient(UDPPort); UdpClient.JoinMulticastGroup(GroupIP); thUDPListener = new System.Threading.Thread(ListenHandler); thUDPListener.Start(); } /// <summary> /// stop listen /// </summary> public void StopListen() { IsListening = false; UdpClient.DropMulticastGroup(GroupIP); UdpClient.Close(); } private void ListenHandler() { var epGroup = new System.Net.IPEndPoint(System.Net.IPAddress.Any, UDPPort); byte[] buffer = null; while (IsListening) { System.Threading.Thread.Sleep(1000); try { buffer = UdpClient.Receive(ref epGroup); } catch { } if (buffer == null || buffer.Length < 1) continue; var msg = System.Text.Encoding.UTF8.GetString(buffer); if (msg.Length > 0) Owner.Invoke(DgGetMsg, msg); } } }}
說明:
這個類包含兩個子類,TCPManage和UDPManage,分別處理TCP和UDP兩種協議。TCP用於點對點,UDP用於組內多播。由於實際網路情況複雜多變,應多加try和檢查,但是我偷懶,就不做了,如果要在項目中引用本類,而你也和我一樣懶得去修改它的話,應在調用每一個方法時加try。
另外,當接收資料時我為簡單起見沒有分段,所以只能用於處理小資料量,而且只能傳輸字串。(要實現其它,在這個基礎上稍做處理即可)這個類的目的非常明確,就像QQ一樣在網路上傳輸不太長的字串,所以它的介面非常簡單,調用起來非常容易。但同時也犧牲了自訂的空間,不過我認為這一般不是個問題,封裝的目的就是要簡單。
以下是測試代碼,同時也示範了如何使用這個類。
建立一個windows form項目,在上面放兩個文字框(它們最好夠大),上面一個叫txt1,用於儲存訊息曆史,下面一個叫txt2,用於向別人發送(就像qq聊天視窗一樣),最下面放個按鈕, 如所示:
然後在字碼頁中:
public partial class Form1 : Form { public Form1() { InitializeComponent(); } Communication.UDPManage udpMng; Communication.TCPManage tcpMng; private void Form1_Load(object sender, EventArgs e) { //tcpMng = new Communication.TCPManage(); //tcpMng.StartListen(this, SetText); udpMng = new Communication.UDPManage(); udpMng.StartListen(this, SetText); } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { //tcpMng.StopListen(); udpMng.StopListen(); } private void SetText(string val) { txt1.Text += val + System.Environment.NewLine; } private void button1_Click(object sender, EventArgs e) { //tcpMng.SendMessage("192.168.1.2", txt2.Text); udpMng.Broadcast(txt2.Text); } }
以上代碼同時示範了tcp和udp兩個類的使用方法,其中tcp的部分注釋掉了。