记录在unity 网络连接中,对 socket UDP学习过程。

2020-7-15更新 前段时间需要写广播功能、、

Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
//初始化一个Scoket实习,采用UDP传输

IPEndPoint iep = new IPEndPoint(IPAddress.Broadcast, 8888);
//初始化一个发送广播和指定端口的网络端口实例   就跟  IPAdress.Any 一样,可以接受任何ip发来的消息

sock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
 //设置该scoket实例的发送形式

 data = Encoding.ASCII.GetBytes(msg);
 socket.SendTo(data, iep);

服务端

UDP服务端,绑定了固定端口,知道自己的固定IP。

using UnityEngine;
using System.Collections;
//引入库
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Collections.Generic;
 
public class UdpServer:MonoBehaviour
{
    Socket socket; //定义一个socket
    EndPoint clientEnd; //负责客户端参数
    IPEndPoint ipEnd; //定义自身侦听端口
    //IPEndPoint继承与EndPoint。IPEndPoint引用的时候参数为IP和端口。
    //IPEndPoint iep = new IPEndPoint(IPAddress.Any, 9050);.net中 Bind(EndPoint localEP);方法参数是EndPoint,
    //填入IPEndPoint会按照EndPoint参数执行。EndPoint是IPEndPoint的基类,
    //IPEndPoint可以强转为EndPoint。EndPoint ep = (EndPoint)iep;
    //主要目的是IPEndPoint可以自己写入IP地址和端口
    string recvStr; //接收的字符串
    string sendStr; //发送的字符串
    byte[] recvData=new byte[1024]; //接收的数据,必须为字节
    byte[] sendData=new byte[1024]; //发送的数据,必须为字节
    int recvLen; //接收的数据长度
    Thread connectThread; //定义线程
 	Queue<string> queue = new Queue<string>();//定义一个队列(先进先出)
 
    // Use this for initialization
    void Start()
    {
        InitSocket(); 
    }
    //初始化
    void InitSocket()
    {
        //定义侦听端口,侦听任何IP
        ipEnd=new IPEndPoint(IPAddress.Any,5555);
        //定义socket 
        socket=new Socket(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);
        //服务端定义端口
        socket.Bind(ipEnd);
        //定义客户端任何IP和端口(这里参数没啥意义,后面接收过程中会再次赋值,当然如果自己知道目标主机的IP和端口,这里倒是可以直接赋值,然后发送。这就变得跟下面客户端差不多了。只要知道目标IP跟端口,就可以发送UDP消息。果然UDP没有什么客户端与服务端,只是绑了一个端口而已,而且客户端也可以绑端口)
        IPEndPoint sender=new IPEndPoint(IPAddress.Any,0);
        clientEnd=(EndPoint)sender;
        //开启一个线程连接,负责接收数据
        connectThread=new Thread(new ThreadStart(SocketReceive));
        connectThread.IsBackground = true;//跟随主线程退出而退出
        connectThread.Start();
    }
 
    void SocketSend(string sendStr)
    {
        //清空发送缓存
        sendData=new byte[1024];
        //数据类型转换(有很多种,服务端跟客户端保持一致,解析数据才能保持正确)
        sendData=Encoding.ASCII.GetBytes(sendStr);
        //发送给指定客户端
        socket.SendTo(sendData,sendData.Length,SocketFlags.None,clientEnd);
    }
 
    //服务器接收
    void SocketReceive()
    {
        //进入接收循环
        while(true)
        {    
            recvData=new byte[1024];
            //获取客户端,获取客户端数据,用引用给客户端赋值
            recvLen=socket.ReceiveFrom(recvData,ref clientEnd);
            Debug.Log(clientEnd.ToString()); //打印客户端信息(ip与端口信息,这里可以获取那些与服务器连接的客户端,毕竟是UDP检测不到断开与连接,倒是可以考虑写个心跳包功能)
            //输出接收到的数据
            recvStr=Encoding.ASCII.GetString(recvData,0,recvLen);
             Debug.Log(recvStr);
             queue.Enqueue(recvStr);//将消息存入队列
           
        }
    }
 
    //连接关闭
    void SocketQuit()
    {
        //关闭线程
        if(connectThread!=null)
        {
            connectThread.Interrupt();
            connectThread.Abort();
        }
        //最后关闭socket
        if(socket!=null)
            socket.Close();
    }
   
    // Update is called once per frame
    void Update()
    {
    		if(queue.Count>0)
    		{   			
    		   //取出收到的数据进行处理再发送出去
    		   //个人觉得还是不要在线程里面处理,毕竟如果数据庞大,还需要解析验证等环节。
               sendStr="From Server: "+queue.Dequeue();
               SocketSend(sendStr);
    		}
          
    }
 
    void OnApplicationQuit()
    {
        SocketQuit();
    }
}

客户端

UDP客户端,不固定的IP,不固定的端口(可以固定),向一台已知并固定IP与端口的主机建立连接。

using UnityEngine;
using System.Collections;
//引入库
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Collections.Generic;
 
public class UdpClient:MonoBehaviour
{
    string _string="hello wolrd"; 
    
    Socket socket; //定义socket
    EndPoint serverEnd; //负责服务端参数
    IPEndPoint ipEnd; //用来定义目标服务端信息
    //IPEndPoint ClientIpEnd; //用来定义客户端信息(固定客户端端口,可以不要,这样客户端端口就是自己随机赋值)
    string recvStr; //接收的字符串
    string sendStr; //发送的字符串
    byte[] recvData=new byte[1024]; //接收的数据,必须为字节
    byte[] sendData=new byte[1024]; //发送的数据,必须为字节
    int recvLen; //接收的数据长度
    Thread connectThread; //线程
	Queue<string> queue = new Queue<string>();//定义一个队列(先进先出)
	
	 // Use this for initialization
    void Start()
    {
        InitSocket(); //在这里初始化
    } 

    void InitSocket()
    {
        //定义连接的服务器ip和端口,可以是本机ip,局域网,互联网(这里定义的是本机IP,毕竟是在同一台电脑上做测试)
        ipEnd=new IPEndPoint(IPAddress.Parse("127.0.0.1"),5555); 
        //定义一个UDP连接
        socket=new Socket(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);
        //定义服务端(这里也没什么用。。毕竟服务端在上面已经定义好了,跟上面服务端中客户端作用一致,为了来接收收到消息是来自什么IP,什么端口)
        IPEndPoint sender=new IPEndPoint(IPAddress.Any,0);
        serverEnd=(EndPoint)sender;  
        //定义客户端端口,让客户端端口固定,否则就是随机赋值端口 
 		//ClientIpEnd=new IPEndPoint(IPAddress.Any, 3333);
 		//socket.Bind(ClientIpEnd);
        //建立初始连接,测试通信是否正常(必须在服务器已经运行的情况下)
        SocketSend("hello");
 
        //开启一个线程连接
        connectThread=new Thread(new ThreadStart(SocketReceive));
        connectThread.Start();
    }
 
    void SocketSend(string sendStr)
    {
        //清空发送缓存
        sendData=new byte[1024];
        //数据类型转换
        sendData=Encoding.ASCII.GetBytes(sendStr);
        //发送给指定服务端
        socket.SendTo(sendData,sendData.Length,SocketFlags.None,ipEnd);
    }
 
    //接收数据
    void SocketReceive()
    {
        //进入接收循环
        while(true)
        {
            //对data清零
            recvData=new byte[1024];
            //获取服务端端数据,用引用给服务端赋值,实际上服务端已经定义好并不需要赋值(其实UPD没有什么服务端客户端的分别)
            recvLen=socket.ReceiveFrom(recvData,ref serverEnd);
            Debug.Log("message from: "+serverEnd.ToString()); //打印服务端信息
            //输出接收到的数据
            recvStr=Encoding.ASCII.GetString(recvData,0,recvLen);
             Debug.Log(recvStr);
             queue.Enqueue(recvStr);//将消息存入队列
        }
    }
 
    //连接关闭
    void SocketQuit()
    {
        //关闭线程
        if(connectThread!=null)
        {
            connectThread.Interrupt();
            connectThread.Abort();
        }
        //最后关闭socket
        if(socket!=null)
            socket.Close();
    }
 
         
    // Update is called once per frame
    void Update()
    {
 		if(queue.Count>0)
    	{   			
    	   //取出收到的数据进行处理
    	    //个人觉得还是不要在线程里面处理,毕竟如果数据庞大,还需要解析验证等环节。
           String s=queue.Dequeue()             
    	}
    	 if(Input.GetKeyDown(KeyCode.Space))
        {
        	//按下空格向服务器发送消息
			SocketSend(_string);
        }	
    }
 
    void OnApplicationQuit()
    {
        SocketQuit();
    }
}

除了看C#官方Socket的API,还看了下面的文章,很详细。再加上自己的理解与看法。恩,就这样。