首页 > IT职业 > IT职场 > UDP 协议简单了解及应用
UdpClient,可发送和接收消息using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace UdpSender
{
class Program
{
static void Main(string[] args)
{
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPAddress broadcast = IPAddress.Loopback;
IPEndPoint ep = new IPEndPoint(broadcast, 514);
Console.WriteLine("请输入要发送的内容:");
while (true)
{
byte[] sendbuf = Encoding.UTF8.GetBytes(Console.ReadLine());
s.SendTo(sendbuf, ep);
}
}
}
}
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Udp
{
class Program
{
static void Main(string[] args)
{
var port = 514;
var server =
new UdpClient(port);
// new SocketReceiver(port);
var remoteEP = new IPEndPoint(IPAddress.Broadcast, port);
try
{
while (true)
{
Console.WriteLine("等待广播");
var bytes = server.Receive(ref remoteEP);
var msg = Encoding.UTF8.GetString(bytes);
Console.WriteLine($"接收来自 {remoteEP} 的广播:");
Console.WriteLine($"{msg}");
Console.WriteLine();
}
}
catch (SocketException e)
{
Console.WriteLine(e);
}
finally
{
server.Close();
}
}
}
}
using System;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
namespace Udp
{
public class SocketReceiver
{
private IntPtr _handle;
public SocketReceiver() : this(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
{
}
public SocketReceiver(int port) : this(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
{
var localEP = new IPEndPoint(IPAddress.Any, port);
Bind(localEP);
}
public SocketReceiver(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
{
Dns.GetHostName(); // 初始化必须
_handle = Interop.Winsock.WSASocketW(addressFamily, socketType, protocolType, IntPtr.Zero, 0u, SocketConstructorFlags.WSA_FLAG_OVERLAPPED);
}
public void Bind(EndPoint localEP)
{
var remoteEP = localEP;
var socketAddress = remoteEP.Serialize();
var buffer = socketAddress.GetValue("Buffer") as byte[];
var socketError = Interop.Winsock.bind(_handle, buffer, socketAddress.Size);
}
public unsafe byte[] Receive(ref IPEndPoint remoteEP)
{
var socketAddress = remoteEP.Serialize();
var socketAddressBuffer = socketAddress.GetValue("Buffer") as byte[];
var socketAddressSize = socketAddress.Size;
var maxSize = 0x10000;
var buffer = new byte[maxSize];
var received = 0;
fixed (byte* pinnedBuffer = &buffer[0])
{
received = Interop.Winsock.recvfrom(_handle, pinnedBuffer, maxSize, SocketFlags.None,
socketAddressBuffer, ref socketAddressSize);
}
socketAddress.SetValue("Buffer", socketAddressBuffer);
socketAddress.SetValue("InternalSize", socketAddressSize);
remoteEP = remoteEP.Create(socketAddress) as IPEndPoint;
// 不返回全部长度,只返回全部接受长度
if (received < maxSize)
{
byte[] newBuffer = new byte[received];
Buffer.BlockCopy(buffer, 0, newBuffer, 0, received);
return newBuffer;
}
return buffer;
}
public void Close()
{
GC.SuppressFinalize(this);
}
}
public static class ReflectionHelper
{
public static object GetValue(this object obj, string name)
{
var value = obj.GetType().InvokeMember(name,
BindingFlags.Instance | BindingFlags.GetField |BindingFlags.NonPublic,
null, obj, null);
return value;
}
public static void SetValue(this object obj, string name, object value)
{
obj.GetType().InvokeMember(name,
BindingFlags.Instance | BindingFlags.SetField | BindingFlags.NonPublic,
null, obj, new[] { value });
}
}
internal static class Interop
{
internal static class Winsock
{
/// <summary>
/// 绑定端口
/// </summary>
/// <param name="socketHandle"></param>
/// <param name="socketAddress"></param>
/// <param name="socketAddressSize"></param>
/// <returns></returns>
[DllImport("ws2_32.dll", SetLastError = true)]
internal static extern SocketError bind([In] IntPtr socketHandle, [In] byte[] socketAddress, [In] int socketAddressSize);
/// <summary>
/// 接收
/// </summary>
/// <param name="socketHandle"></param>
/// <param name="pinnedBuffer"></param>
/// <param name="len"></param>
/// <param name="socketFlags"></param>
/// <param name="socketAddress"></param>
/// <param name="socketAddressSize"></param>
/// <returns></returns>
[DllImport("ws2_32.dll", SetLastError = true)]
internal unsafe static extern int recvfrom([In] IntPtr socketHandle, [In] byte* pinnedBuffer, [In] int len, [In] SocketFlags socketFlags, [Out] byte[] socketAddress, [In] [Out] ref int socketAddressSize);
/// <summary>
/// 申请
/// </summary>
/// <param name="addressFamily"></param>
/// <param name="socketType"></param>
/// <param name="protocolType"></param>
/// <param name="protocolInfo"></param>
/// <param name="group"></param>
/// <param name="flags"></param>
/// <returns></returns>
[DllImport("ws2_32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern IntPtr WSASocketW([In] AddressFamily addressFamily, [In] SocketType socketType, [In] ProtocolType protocolType, [In] IntPtr protocolInfo, [In] uint group, [In] SocketConstructorFlags flags);
}
}
[Flags]
internal enum SocketConstructorFlags
{
WSA_FLAG_OVERLAPPED = 0x1,
WSA_FLAG_MULTIPOINT_C_ROOT = 0x2,
WSA_FLAG_MULTIPOINT_C_LEAF = 0x4,
WSA_FLAG_MULTIPOINT_D_ROOT = 0x8,
WSA_FLAG_MULTIPOINT_D_LEAF = 0x10
}
}
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
192.168.1.255则是广播消息到网络段192.168.1的所有主机NetworkStream网络流,可将接收改为异步+回调的方式接收消息该流的读取操作,实际就是从系统缓冲区读取数据。其中还请教了大神,UDP 数据缓冲区数据满了之后就会有数据丢失的情况,这是因为 udp 没有流量控制,而 TCP 则不会丢失。其它缓冲区满的情况还要继续摸索,不过相关参数还是可以调节的,比如缓冲区大小、TCP 的客户端连接数等来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/4369/viewspace-2823860/ ,如需转载,请注明出处,否则将追究法律责任。