欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C#实现Upd通信(二)--socket通信配合订阅者模式广播及收发信息

程序员文章站 2022-03-11 16:10:01
上一节讲的是简单的socket通信,为了提高复用率,整理为一个帮助类,并加入订阅者模式(想要接受通知的类或者界面只要注册了该类,则无需通过一层层传递的方式传递数据,具体下次写一篇具体说明),方便本机电脑广播的方式发生信息给多台用户,并在多个界面能够接到远程设备返回的数据。帮助类代码:private static SocketHelper instants;public static SocketHelper Instants{ get { if (instants =...

上一节讲的是简单的socket通信,为了提高复用率,整理为一个帮助类,并加入订阅者模式(想要接受通知的类或者界面只要注册了该类,则无需通过一层层传递的方式传递数据,具体下次写一篇具体说明),方便本机电脑广播的方式发生信息给多台用户,并在多个界面能够接到远程设备返回的数据。

所有代码:
https://download.csdn.net/download/Yyuanyuxin/13026074
帮助类代码:

private static SocketHelper instants;
public static SocketHelper Instants
{
    get
    {
        if (instants == null)
            instants = new SocketHelper();
        return instants;
    }
}
private Socket _server;
public IPAddress Ip;
public int Port;
public string Mac;
public Dictionary<IPAddress, int> ClientIpAndPort=new Dictionary<IPAddress, int>();

public bool Init(string ip = "", string port = "")
{
    try
    {
        if (!IPAddress.TryParse(ip == "" ? GetLocalIP() : ip, out Ip))
        {
            MessageBox.Show("获取本机信息错误!");
            return false;
        }
        if (!int.TryParse(port == "" ? GetLocalValidPort() : port, out Port))
        {
            MessageBox.Show("本机没有可用的端口!");
            return false;
        }
        Mac = GetLocalMac();
        if (Mac == "")
        {
            MessageBox.Show("获取本机MAC错误!");
            return false;
        }
        _server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        _server.Bind(new IPEndPoint(Ip, Port));//绑定端口号和IP
        Thread t1 = new Thread(ReceiveMsg);//开启接收消息线程
        t1.IsBackground = true;
        t1.Start();
        return true;
    }
    catch (Exception ex)
    {
        return false;
    }

}
/// <summary>
/// 接收发送给本机ip对应端口号的数据报
/// </summary>
public void ReceiveMsg()
{
    while (true)
    {
        EndPoint port = new IPEndPoint(IPAddress.Any, 0);//用来保存发送方的ip和端口号
        byte[] buffer = new byte[1024];
        int length = _server.ReceiveFrom(buffer, ref port);//接收数据报
        var port1 = port as IPEndPoint;
        string message = Encoding.UTF8.GetString(buffer, 0, length);
        if (NotifyEvent != null)
        {
            NotifyEvent(this, port1, message );
        }
    }
}
public void SendMsg(object msg)
{
    Thread t2 = new Thread(new ParameterizedThreadStart(SendMsgThread));//开启发送消息线程
    t2.IsBackground = true;
    if (msg is string msgString)
    {
        t2.Start(Encoding.UTF8.GetBytes(msgString));
    }
    else if (msg is byte[] msgbyte)
    {
        t2.Start(msgbyte);
    }
}
/// <summary>
/// 向特定ip的主机的端口发送数据报
/// </summary>
private void SendMsgThread(object msg)
{
    IPAddress curIp =null;
    try
    {
        if (ClientIpAndPort == null) return;
        if (msg is byte[] buffle)
        {
            foreach (var ip in ClientIpAndPort.Keys)
            {
                curIp = ip;
                EndPoint port = new IPEndPoint(ip, ClientIpAndPort[ip]);
                _server.SendTo(buffle, port);
            }
        }
    }
    catch (Exception ex)
    {
        if (curIp != null && ClientIpAndPort.ContainsKey(curIp))
            ClientIpAndPort.Remove(curIp);
        MessageBox.Show(ex.Message);
        
    }
    
    

}
public bool  AddClientIpAndPort(string ipString,string portString)
{
    if (IPAddress.TryParse(ipString, out IPAddress ip)&& int.TryParse(portString,out int port))
    {
        if (ClientIpAndPort.ContainsKey(ip))
        {
            ClientIpAndPort[ip] = port;
        }
        else
        {
            ClientIpAndPort.Add(ip, port);
        }
        return true;
    }
    return false;
}
/// <summary>
///  // 获得本机局域网IP地址 
/// </summary>
/// <returns></returns>
private string GetLocalIP()
{
    IPAddress[] AddressList = Dns.GetHostByName(Dns.GetHostName()).AddressList;
    if (AddressList.Length < 1)
    {
        return "";
    }
    return AddressList[0].ToString();
}
/// <summary>
/// 获取本地有效的端口号
/// </summary>
/// <returns></returns>
private string GetLocalValidPort()
{
    IPGlobalProperties properties = IPGlobalProperties.GetIPGlobalProperties();
    //返回本地计算机上的所有Tcp监听程序    
    var ipsTcp = properties.GetActiveTcpListeners();
    //返回本地计算机上的所有UDP监听程序     
    var ipsUdp = properties.GetActiveUdpListeners();
    for (int i = 1024; i < 5000; i++)
    {
        if (ClientIpAndPort.ContainsValue(i)) continue;
        foreach (var ip in ipsTcp)
        {
            if (ip.Port == i) continue;
            foreach (var ip2 in ipsUdp)
            {
                if (ip2.Port != i)
                {
                    return i.ToString();
                }
            }
        }
        if (i == 4999)
        {
            return "";
        }

    }
    return "";
}
public string GetLocalMac()
{
    ManagementObjectSearcher query = new ManagementObjectSearcher("SELECT * FROM Win32_NetworkAdapterConfiguration");
    ManagementObjectCollection queryCollection = query.Get();
    foreach (ManagementObject mo in queryCollection)
    {
        if (mo["IPEnabled"].ToString() == "True")
            return mo["MacAddress"].ToString();
    }
    return "";
}
#region 用于通知订阅者
private NotifyEventHandler NotifyEvent;
public void AddObserver(NotifyEventHandler observer) 
{
    NotifyEvent += observer;
}
public void RemoveObserver(NotifyEventHandler observer)
{
    NotifyEvent -= observer;
}
#endregion

订阅者接口

public delegate void NotifyEventHandler(SocketHelper sender, IPEndPoint port,object data);
public interface IMySocketObserver
{
   void Receive(SocketHelper sender, IPEndPoint port, object data);
}

使用
初始化:

SocketHelper socketHelper = SocketHelper.Instants;
socketHelper.AddObserver(Receive);
if(socketHelper.Init(textBox1.Text, textBox2.Text))
{
    textBox1.Text = socketHelper.Ip.ToString();
    textBox2.Text = socketHelper.Port.ToString();
}

发送广播信息:

socketHelper.AddClientIpAndPort(textBox4.Text, textBox3.Text);
socketHelper.SendMsg(richTextBox1.Text);

订阅者(例如):

public partial class Form1 : Form, IMySocketObserver
{
	public void Receive(SocketHelper sender, IPEndPoint port, object data)
        {
            this.Invoke((EventHandler)delegate 
            {
                richTextBox2.AppendText(port+"  :"+data.ToString()+ "\r\n");
            });
        }
}

本文地址:https://blog.csdn.net/Yyuanyuxin/article/details/109244484