(所有注释全部出自C#官方文档
地址)
网络相关常用接口
获取本地IP
public static string GetLocalIP_LAN80211()
{
foreach (var interfaces in NetworkInterface.GetAllNetworkInterfaces())
{
if (interfaces.NetworkInterfaceType == NetworkInterfaceType.Wireless80211 && interfaces.OperationalStatus == OperationalStatus.Up)
{
foreach (var ip in interfaces.GetIPProperties().UnicastAddresses)
{
if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
{
if (ip.Address.ToString().StartsWith("192."))
return ip.Address.ToString();
}
}
}
}
return string.Empty;
}
public static string GetLocalIP_V2()
{
try
{
string HostName = Dns.GetHostName();
IPHostEntry IpEntry = Dns.GetHostEntry(HostName);
for (int i = 0; i < IpEntry.AddressList.Length; i++)
{
if (IpEntry.AddressList[i].AddressFamily == AddressFamily.InterNetwork)
{
string ip = "";
ip = IpEntry.AddressList[i].ToString();
return IpEntry.AddressList[i].ToString();
}
}
return "";
}
catch (Exception ex)
{
return ex.Message;
}
}
UDP
namespace System.Net.Sockets class UdpClient
简介
详细描述(转发) 简单来说,传输层,无连接,不可靠,广播多播解决方案
初始化
- UdpClient 构造函数(常用,还有其他的构造函数)
- UdpClient()
使用该构造函数需要调用 Connect 方法来指定远程主机 - UdpClient(Int32)
参数为要绑定的端口号,使用该构造函数,接受同端口的所有广播 - UdpClient(IPEndPoint)
参数为要绑定的 IP 地址,使用该构造函数,只接收传入的 IP 的广播
(如果不考虑接收广播,发送方可以随便定个端口)
使用
public async void ListenAsync()
{
while (true)
{
if (udpClient != null)
{
try
{
OnGetMessage(await udpClient.ReceiveAsync());
}
catch
{
break;
}
}
}
}
private void OnGetMessage(UdpReceiveResult receive)
{
string msg = Encoding.UTF8.GetString(receive.Buffer);
EventOnGetMessage?.Invoke(receive.RemoteEndPoint, msg);
}
如果在异步执行中,调用 UdpClient.Close 后,await 那一行代码会报错,不过好像对功能没影响
Socket
简介
详细描述(转发) Socket 跟 TCP/IP 的关系
讲个笑话 问:socket 跟 websocket 什么关系? 答:跟 java 和 JavaScript 的关系一样。
namespace System.Net.Sockets class Socket
服务端
- 创建对象
try
{
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ip = IPAddress.Parse(IP);
IPEndPoint endPoint = new IPEndPoint(ip, Port);
_socket.Bind(endPoint);
_socket.Listen(MaxValue);
ListenClientConnectAsync();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
throw;
}
- 监听客户端链接
Socket clientSocket = await _socket.AcceptAsync();
一个同步(阻塞)、一个异步,都是提供操作新接入客户端的一个 Socket 对象。换句话说每一个获取到的 Socket 对应一个连接的客户端,要收、发客户端消息,就需要操作指定的 Socket 对象。
- 接收客户端信息
Socket.Receive private void ReceiveMessage(object socket)
{
Socket clientSocket = socket as Socket;
string tmpIP = clientSocket.RemoteEndPoint.ToString();
if (clientSocket != null)
dicClientSocket.Add(tmpIP, clientSocket);
while (clientSocket != null&&clientSocket.Connected)
{
try
{
int length = clientSocket.Receive(buffer);
string msg = Encoding.UTF8.GetString(buffer, 0, length);
if (!CheckSocketIsConnect(clientSocket))
throw new Exception("已断开链接");
OnGetMsg(clientSocket.RemoteEndPoint.ToString(), msg);
}
catch (Exception e)
{
if (clientSocket != null)
{
OnClientDisconnect(tmpIP);
dicClientSocket.Remove(tmpIP);
clientSocket.Close();
clientSocket = null;
}
break;
}
}
}
客户端异常断开链接后,会不停的 Receive 到空字符,就手动判断了客户端链接状态 ReceiveAsync 方法不能直接 await ,并没有方便多少,所以用的 thread.Start(clientSocket); - 给客户端发送信息
Socket.Send 想发送的内容转 byte[] 然后调用 send 就完事了
客户端
public void StartClient()
{
try
{
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ip = IPAddress.Parse(IP);
IPEndPoint endPoint = new IPEndPoint(ip, Port);
_socket.Connect(endPoint);
Thread thread = new Thread(ReceiveMessage);
thread.Start(_socket);
}
catch (Exception e)
{
UnityEngine.Debug.LogError("链接失败 : " + e);
throw;
}
}
- 收、发消息
与服务器对 Socket 收发消息相同
断开 Socket 链接
先判断是否是连接状态,如果是需要先调用 Socket.Shutdown(SocketShutdown) 断开链接 然后调用 Socket.Close
try
{
aSocket.Shutdown(SocketShutdown.Both);
}
finally
{
aSocket.Close();
}
判断 Socket 是否是连接状态
Socket.Poll(Int32, SelectMode) Socket.Connected
public static bool CheckSocketIsConnect(Socket socket)
{
if (socket == null) return false;
bool part1 = socket.Poll(1000, SelectMode.SelectRead);
bool part2 = socket.Available == 0;
if ((part1 && part2) || !socket.Connected)
return false;
else
return true;
}
局域网聊天实现
使用同一个路由器,或者同一个手机热点
- 纯 udp 实现
- Socket 实现。udp 广播服务器IP,其他人 socket 链接到服务器
- 开应用之后等1到2秒,看有没有收到服务器 IP 的广播
- 如果收到广播,接入服务器
- 如果没收到,自己初始化服务器,然后广播自己的 IP
- 服务器把客户端发送到的消息转发给其他的客户端
|