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

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

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

posted on 2009-09-19 15:57  夏狼哉  阅读(789)  评论(1编辑  收藏  举报