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