Recently, I copied code several times on the Internet, which made me feel a little embarrassed, because I generally do not like sending code segments, and I feel boring. However, this idea has recently changed. Copying data from one another helps increase productivity...
The following is a communication class. If you need to quote it, please indicate the author. Thank you.
/// <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); } } }}
Note:
This class contains two subclasses, tcpmanage and udpmanage, which process TCP and UDP protocols respectively. TCP is used for point-to-point and UDP is used for intra-group multicast. Because the actual network conditions are complex and changing, try and check more, but I will not do it if I am lazy. If I want to reference this class in the project, and if you are just as reluctant to modify it as I do, you should add try when calling every method.
In addition, when receiving data, I have no segments for the sake of simplicity, so it can only be used to process small data volumes and can only transmit strings. (If you want to implement other functions, you just need to perform some processing on this basis.) The purpose of this class is very clear. Just like QQ, strings that are not too long are transmitted over the network, so its interface is very simple, it is very easy to call. But at the same time, it also sacrifices the custom space, but I think this is generally not a problem, the purpose of encapsulation is to be simple.
The following is the test code and demonstrates how to use this class.
Create a new windows form project and put two text boxes on it (they should be big enough). The above one is called txt1, which is used to save the message history. The following is called txt2, used to send messages to others (just like the QQ chat window). Put a button at the bottom, as shown in:
Then in the code page:
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); } }
The code above demonstrates the usage of both TCP and UDP classes, and some of them are commented out.