IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> C# UDP Socket 笔记 -> 正文阅读

[网络协议]C# UDP Socket 笔记


(所有注释全部出自C#官方文档 地址

网络相关常用接口

获取本地IP

//通过网络接口描述来获取IP

       public static string GetLocalIP_LAN80211()
        {
            //GetAllNetworkInterfaces 返回描述本地计算机上的网络接口的对象。
            foreach (var interfaces in NetworkInterface.GetAllNetworkInterfaces())
            {
                //NetworkInterfaceType 网络接口的类型,Wireless80211 网络接口使用无线 LAN 连接(IEEE 802.11 标准)。
                //OperationalStatus 指定网络接口的操作状态,Up 网络接口已运行,可以传输数据包。
                if (interfaces.NetworkInterfaceType == NetworkInterfaceType.Wireless80211 && interfaces.OperationalStatus == OperationalStatus.Up)
                {
                    //GetIPProperties 返回描述此网络接口的配置的对象。
                    //IPInterfaceProperties 提供有关支持 Internet 协议版本 4 (IPv4) 或 Internet 协议版本 6 (IPv6) 的网络接口的信息。
                    //UnicastAddresses 获取分配给此接口的单播地址。
                    foreach (var ip in interfaces.GetIPProperties().UnicastAddresses)
                    {
                        //InterNetwork IP 版本 4 的地址。InterNetworkV6 IP 版本 6 的地址。
                        if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
                        {
                            //192. 开头保证获取的是内网地址
                            if (ip.Address.ToString().StartsWith("192."))
                                return ip.Address.ToString();
                        }
                    }
                }
            }

            return string.Empty;
        }
//通过DNS解析本地IP
        public static string GetLocalIP_V2()
        {
            try
            {
                //获取本地计算机的主机名。
                string HostName = Dns.GetHostName();
                //将主机名或 IP 地址解析为 IPHostEntry 实例。
                IPHostEntry IpEntry = Dns.GetHostEntry(HostName);
                //AddressList 获取或设置与主机关联的 IP 地址列表。
                for (int i = 0; i < IpEntry.AddressList.Length; i++)
                {
                    //从IP地址列表中筛选出IPv4类型的IP地址
                    //AddressFamily.InterNetwork表示此IP为IPv4,
                    //AddressFamily.InterNetworkV6表示此地址为IPv6类型
                    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 的广播

(如果不考虑接收广播,发送方可以随便定个端口)

使用

  • 发广播
    方法 UdpClient.Send
    如果是 UdpClient() 无参构造函数创建的 udp 对象,只能先调用 Connect 再调用 Send(Byte[], Int32) 来广播
    其他情况则调用 Send(Byte[], Int32, IPEndPoint) 来广播,最后一个参数为广播指定的 IP 和端口
  • 收广播
    UdpClient.Receive(IPEndPoint)
    需要开线程,会阻塞
    UdpClient.ReceiveAsync
    (异步天下无敌!)
        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);
            //UnityEngine.Debug.Log($"OnGetMessage ip:{receive.RemoteEndPoint} msg:{msg}");
            EventOnGetMessage?.Invoke(receive.RemoteEndPoint, msg);
        }

如果在异步执行中,调用 UdpClient.Close 后,await 那一行代码会报错,不过好像对功能没影响

Socket

简介

详细描述(转发)
Socket 跟 TCP/IP 的关系

讲个笑话
问:socket 跟 websocket 什么关系?
答:跟 java 和 JavaScript 的关系一样。

namespace System.Net.Sockets
class Socket

服务端

  • 创建对象
    		try
    		{
    			//1.0 实例化套接字(IP4寻找协议,流式协议,TCP协议)
    			_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    			//IP为本地IP,端口
    			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.Shutdown(SocketShutdown.Both);
    					clientSocket.Close();
    
    					clientSocket = null;
    				}
    				break;
    			}
    		}
    	}
    
    客户端异常断开链接后,会不停的 Receive 到空字符,就手动判断了客户端链接状态
    ReceiveAsync 方法不能直接 await ,并没有方便多少,所以用的 thread.Start(clientSocket);
  • 给客户端发送信息
    Socket.Send
    想发送的内容转 byte[] 然后调用 send 就完事了

客户端

  • 连接服务器
		public void StartClient()
        {
            try
            {
                //1.0 实例化套接字(IP4寻址地址,流式传输,TCP协议)
                _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //IP为服务器 IP ,端口
                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;

			//SelectRead	如果已调用 Listen(Int32) 并且有挂起的连接,则为 true。
			//- 或 - 如果有数据可供读取,则为 true。
			//- 或 - 如果连接已关闭、重置或终止,则返回 true; 否则,返回 false。
			bool part1 = socket.Poll(1000, SelectMode.SelectRead);
			//获取已经从网络接收且可供读取的数据量。
			bool part2 = socket.Available == 0;

			if ((part1 && part2) || !socket.Connected)
				return false;
			else
				return true;
        }

局域网聊天实现

使用同一个路由器,或者同一个手机热点

  • 纯 udp 实现
    • 所有人直接 udp 广播就可以
  • Socket 实现。udp 广播服务器IP,其他人 socket 链接到服务器
    • 开应用之后等1到2秒,看有没有收到服务器 IP 的广播
      • 如果收到广播,接入服务器
      • 如果没收到,自己初始化服务器,然后广播自己的 IP
    • 服务器把客户端发送到的消息转发给其他的客户端
  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-07-29 12:01:15  更:2021-07-29 12:02:28 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 18:31:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码