• 应用程序在网络上通信的实现(C#)


    最近赶活,连续在网上抄了好几次代码,很让我觉得有点不好意思,因为我一般不大喜欢发代码段,觉得没啥意思。不过最近这个想法有所改变,大家互相抄抄有助于提高生产率嘛。。。

    以下发一个通信类,如需引用,请注明作者,谢谢。

    /// <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的部分注释掉了。

  • 相关阅读:
    day22 面向对象
    springMVC中 POST 请求数据变乱码问题
    Handler dispatch failed; nested exception is java.lang.AbstractMethodError: Method com/mchange/v2/c3p0/impl/NewProxyResultSet.isClosed()Z is abstract
    java.sql.SQLException: Unknown system variable 'tx_isolation'
    Mysql命令
    paas相关,添加ing
    Angular2中实现基于TypeScript的对象合并方法:extend()
    NgStyle和NgIf控制HTML标签显示的区别
    执行ng build --prod --aot命令报错
    JavaScript中的小陷阱(不定期更新。。)
  • 原文地址:https://www.cnblogs.com/Moosdau/p/1570062.html
Copyright © 2020-2023  润新知