最近赶活,连续在网上抄了好几次代码,很让我觉得有点不好意思,因为我一般不大喜欢发代码段,觉得没啥意思。不过最近这个想法有所改变,大家互相抄抄有助于提高生产率嘛。。。
以下发一个通信类,如需引用,请注明作者,谢谢。
/// <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的部分注释掉了。
---------------------------------------------
作者:夏狼哉
博客:http://www.cnblogs.com/Moosdau
如需引用,敬请保留作者信息,谢谢