注意:客戶端和服務器實現基本一致,本地host和port和多播的host和port可以一樣
(1)多播
1.將本地host加入多播組中,只有加入多播組的成員才能接受同組的節點發送的多播
MulticastOption mcastOption = new MulticastOption(IPAddress.Parse(MultiCastHost), IPAddress.Parse(localHost));
socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, mcastOption);
2.將本地host移出多播組中
socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.DropMembership, mcastOption);
3.多播生存時間 millisecond
socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 10);
發送信息指定MultiCastHost發送
(2)廣播
開啟廣播
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
發送信息指定255.255.255.255發送
參考:MSDN
public class UdpServiceSocket
{
private readonly string broadCastHost = "255.255.255.255";
//接收數據事件
public Action<string> recvMessageEvent = null;
//發送結果事件
public Action<int> sendResultEvent = null;
//接收緩存數組
private byte[] recvBuff = null;
//發送緩存數組
private byte[] sendBuff = null;
//用於發送數據的SocketAsyncEventArgs
private SocketAsyncEventArgs sendEventArg = null;
//用於接收數據的SocketAsyncEventArgs
private SocketAsyncEventArgs recvEventArg = null;
//監聽socket
private Socket socket = null;
//用於socket發送和接收的緩存區大小
private int bufferSize = 1024;
//udp服務器綁定地址
private string localHost = "";
//udp服務器監聽端口
private int localPort = 0;
//udp廣播組地址
private string MultiCastHost = "";
//udp廣播組端口
private int MultiCastPort = 0;
/// <summary>
/// 構造函數
/// </summary>
/// <param name="bufferSize">用於socket發送和接受的緩存區大小</param>
public UdpServiceSocket()
{
//設置用於發送數據的SocketAsyncEventArgs
sendBuff = new byte[bufferSize];
sendEventArg = new SocketAsyncEventArgs();
sendEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed);
sendEventArg.SetBuffer(sendBuff, 0, bufferSize);
//設置用於接受數據的SocketAsyncEventArgs
recvBuff = new byte[bufferSize];
recvEventArg = new SocketAsyncEventArgs();
recvEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed);
recvEventArg.SetBuffer(recvBuff, 0, bufferSize);
}
/// <summary>
/// 開啟udp服務器,等待udp客戶端數據(設置廣播)
/// </summary>
public void Start(string localHost, int localPort)
{
if (string.IsNullOrEmpty(localHost))
throw new ArgumentNullException("localHost cannot be null");
if (localPort < 1 || localPort > 65535)
throw new ArgumentOutOfRangeException("localPort is out of range");
this.localHost = localHost;
this.localPort = localPort;
try
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
//設置廣播
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse(localHost), localPort);
socket.Bind(endpoint);//設置監聽地址和端口
StartRecvFrom();
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// 開啟udp服務器,等待udp客戶端數據(設置多播,廣播)
/// </summary>
/// <param name="ip"></param>
/// <param name="port"></param>
public void Start(string localHost, int localPort, string MultiCastHost, int MultiCastPort)
{
if (string.IsNullOrEmpty(localHost))
throw new ArgumentNullException("localHost cannot be null");
if (localPort < 1 || localPort > 65535)
throw new ArgumentOutOfRangeException("localPort is out of range");
if (string.IsNullOrEmpty(MultiCastHost))
throw new ArgumentNullException("MultiCastHost cannot be null");
if (MultiCastPort < 1 || MultiCastPort > 65535)
throw new ArgumentOutOfRangeException("MultiCastPort is out of range");
this.localHost = localHost;
this.localPort = localPort;
this.MultiCastHost = MultiCastHost;
this.MultiCastPort = MultiCastPort;
try
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
//設置廣播
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
//設置多播
socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, true);
MulticastOption mcastOption = new MulticastOption(IPAddress.Parse(MultiCastHost), IPAddress.Parse(localHost));
socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, mcastOption);
IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse(localHost), localPort);
socket.Bind(endpoint);//設置監聽地址和端口
StartRecvFrom();
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// 開始接受udp客戶端發送的數據
/// </summary>
private void StartRecvFrom()
{
recvEventArg.RemoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
bool willRaiseEvent = socket.ReceiveFromAsync(recvEventArg);
if (!willRaiseEvent)
{
ProcessReceive(recvEventArg);
}
}
/// <summary>
/// socket.sendAsync和socket.recvAsync的完成回調函數
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void IO_Completed(object sender, SocketAsyncEventArgs e)
{
switch (e.LastOperation)
{
case SocketAsyncOperation.ReceiveFrom:
ProcessReceive(e);
break;
case SocketAsyncOperation.SendTo:
ProcessSend(e);
break;
default:
throw new ArgumentException("The last operation completed on the socket was not a receive or send");
}
}
/// <summary>
/// 處理接收到的udp客戶端數據
/// </summary>
/// <param name="e"></param>
private void ProcessReceive(SocketAsyncEventArgs e)
{
if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
{
if (recvMessageEvent != null)
//一定要指定GetString的長度
recvMessageEvent(Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred));
StartRecvFrom();
}
else
{
Restart();
}
}
/// <summary>
/// 處理udp服務器發送的結果
/// </summary>
/// <param name="e"></param>
private void ProcessSend(SocketAsyncEventArgs e)
{
AsyncUserToken token = (AsyncUserToken)e.UserToken;
if (e.SocketError == SocketError.Success)
{
if (sendResultEvent != null)
sendResultEvent(e.BytesTransferred);
}
else
{
if (sendResultEvent != null)
sendResultEvent(e.BytesTransferred);
Restart();
}
}
/// <summary>
/// 關閉udp服務器
/// </summary>
public void CloseSocket()
{
if (socket == null)
return;
try
{
socket.Shutdown(SocketShutdown.Both);
}
catch { }
try
{
socket.Close();
}
catch { }
}
/// <summary>
/// 重新啟動udp服務器
/// </summary>
public void Restart()
{
CloseSocket();
if (string.IsNullOrEmpty(MultiCastHost))
Start(localHost, localPort, MultiCastHost, MultiCastPort);
else
Start(localHost, localPort);
}
/// <summary>
/// 發送廣播
/// </summary>
/// <param name="message"></param>
public void SendMessageByBroadcast(string message)
{
if (socket == null)
throw new ArgumentNullException("socket cannot be null");
if (string.IsNullOrEmpty(message))
throw new ArgumentNullException("message cannot be null");
byte[] buff = Encoding.UTF8.GetBytes(message);
if (buff.Length > bufferSize)
throw new ArgumentOutOfRangeException("message is out off range");
sendEventArg.RemoteEndPoint = new IPEndPoint(IPAddress.Parse(broadCastHost), localPort);
buff.CopyTo(sendEventArg.Buffer, 0);
sendEventArg.SetBuffer(0, buff.Length);
bool willRaiseEvent = socket.SendToAsync(sendEventArg);
if (!willRaiseEvent)
{
ProcessSend(sendEventArg);
}
}
/// <summary>
/// 發送單播
/// </summary>
/// <param name="message"></param>
public void SendMessageByUnicast(string message, string destHost, int destPort)
{
if (socket == null)
throw new ArgumentNullException("socket cannot be null");
if (string.IsNullOrEmpty(message))
throw new ArgumentNullException("message cannot be null");
if (string.IsNullOrEmpty(destHost))
throw new ArgumentNullException("destHost cannot be null");
if (destPort < 1 || destPort > 65535)
throw new ArgumentOutOfRangeException("destPort is out of range");
byte[] buff = Encoding.UTF8.GetBytes(message);
if (buff.Length > bufferSize)
throw new ArgumentOutOfRangeException("message is out off range");
sendEventArg.RemoteEndPoint = new IPEndPoint(IPAddress.Parse(destHost), destPort);
buff.CopyTo(sendEventArg.Buffer, 0);
sendEventArg.SetBuffer(0, buff.Length);
bool willRaiseEvent = socket.SendToAsync(sendEventArg);
if (!willRaiseEvent)
{
ProcessSend(sendEventArg);
}
}
/// <summary>
/// 發送組播(多播)
/// </summary>
/// <param name="message"></param>
public void SendMessageByMulticast(string message)
{
if (socket == null)
throw new ArgumentNullException("socket cannot be null");
if (string.IsNullOrEmpty(message))
throw new ArgumentNullException("message cannot be null");
if (string.IsNullOrEmpty(MultiCastHost))
throw new ArgumentNullException("MultiCastHost cannot be null");
if (MultiCastPort < 1 || MultiCastPort > 65535)
throw new ArgumentOutOfRangeException("MultiCastPort is out of range");
byte[] buff = Encoding.UTF8.GetBytes(message);
if (buff.Length > bufferSize)
throw new ArgumentOutOfRangeException("message is out off range");
sendEventArg.RemoteEndPoint = new IPEndPoint(IPAddress.Parse(MultiCastHost), MultiCastPort);
buff.CopyTo(sendEventArg.Buffer, 0);
sendEventArg.SetBuffer(0, buff.Length);
bool willRaiseEvent = socket.SendToAsync(sendEventArg);
if (!willRaiseEvent)
{
ProcessSend(sendEventArg);
}
}
}
