欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

HoloLens中基于Socket的TCP通信系统

程序员文章站 2022-04-28 21:29:51
...

HoloLens中基于Socket的TCP通信系统

系统目标

实现服务器端PC与客户端HoloLens通信。PC向HoloLens发送数据,HoloLens接收到数据后,向PC发送消息确认。

服务器端

将下面代码挂在Unity场景中。

using System.Collections;
using System.Collections.Generic;
using System;
using System.IO;
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

public class Server : MonoBehaviour
{
    List<Socket> ClientProxSocketList = new List<Socket>();

    string editString = "编辑发送内容"; //编辑框文字
    //定义服务器的IP和端口,端口与服务器对应
    public string IPAddress_Server = "10.175.46.8";//可以是局域网或互联网ip
    public string Port_Server = "5000";

    // Start is called before the first frame update
    void Start()
    {
        
    }

    void OnGUI()
    {
        IPAddress_Server = GUI.TextField(new Rect(10, 10, 100, 20), IPAddress_Server);
        Port_Server = GUI.TextField(new Rect(120, 10, 60, 20), Port_Server);

        if (GUI.Button(new Rect(200, 10, 100, 20), "启动服务器"))
            ServerStart();
        editString = GUI.TextField(new Rect(10, 40, 150, 20), editString);
        if (GUI.Button(new Rect(180, 40, 100, 20), "发送字符串"))
            SendMsg();
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    private void ServerStart()
    {
        //1 创建Socket对象
        Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        //2 绑定端口ip
        socket.Bind(new IPEndPoint(IPAddress.Parse(IPAddress_Server), int.Parse(Port_Server)));
        //3 开启侦听
        socket.Listen(10);//链接等待队列:同时来了100个链接请求,队列里放10个等待链接客户端,其他返回错误信息
        //4 开始接受客户端的链接
        ThreadPool.QueueUserWorkItem(new WaitCallback(this.AcceptClientConnect), socket);
    }

    public void AcceptClientConnect(object socket)
    {
        var serverSocket = socket as Socket;//强制类型转换  

        this.AppendTextToConsole("服务器端开始接受客户端的链接");

        while (true)//不断的接收
        {
            var proxSocket = serverSocket.Accept();//会阻塞当前线程,因此必须放入异步线程池中
            this.AppendTextToConsole(string.Format("客户端:{0}链接上了", proxSocket.RemoteEndPoint.ToString()));
            ClientProxSocketList.Add(proxSocket);//使方法体外部也可以访问到方法体内部的数据

            //不停接收当前链接的客户端发送来的消息
            //不能因为接收一个客户端消息阻塞整个线程,启用线程池
            ThreadPool.QueueUserWorkItem(new WaitCallback(this.ReceiveData), proxSocket);
        }
    }

    //接收客户端消息
    public void ReceiveData(object socket)
    {
        var proxSocket = socket as Socket;
        byte[] data = new byte[1024 * 1024];
        while (true)
        {
            int len = 0;
            try
            {
                len = proxSocket.Receive(data, 0, data.Length, SocketFlags.None);
            }
            catch (Exception ex)
            {
                //异常退出,在阻塞线程时与服务器连接中断或断电等等
                AppendTextToConsole(string.Format("接收到客户端:{0}非正常退出", proxSocket.RemoteEndPoint.ToString()));
                ClientProxSocketList.Remove(proxSocket);
                StopConnect(proxSocket);
                return;
            }


            if (len <= 0)
            {
                //客户端正常退出
                AppendTextToConsole(string.Format("接收到客户端:{0}正常退出", proxSocket.RemoteEndPoint.ToString()));
                ClientProxSocketList.Remove(proxSocket);

                StopConnect(proxSocket);
                return;//让方法结束。终结当前接收客户端数据的异步线程
            }

            //把接收到的数据放到文本框上
            string str = Encoding.Default.GetString(data, 0, len);
            AppendTextToConsole(string.Format("接收到客户端:{0}的消息是:{1}", proxSocket.RemoteEndPoint.ToString(), str));
        }
    }
    private void StopConnect(Socket proxSocket)
    {
        try
        {
            if (proxSocket.Connected)
            {
                proxSocket.Shutdown(SocketShutdown.Both);
                proxSocket.Close(100);//100秒后没有正常关闭则强行关闭
            }
        }
        catch (Exception ex)
        {

        }
    }
    //发送字符串
    private void SendMsg()
    {
        foreach (var proxSocket in ClientProxSocketList)
        {
            if (proxSocket.Connected)
            {
                //原始的字符串转换成的字节数组
                byte[] data = Encoding.Default.GetBytes(editString);
                proxSocket.Send(data, 0, data.Length, SocketFlags.None);
            }
        }
    }

    //在控制台打印要显示的内容
    public void AppendTextToConsole(string txt)
    {
        Debug.Log(string.Format("{0}", txt));
    }

}

客户端

将下面代码挂在Unity场景中。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.IO;

public class SAEA : MonoBehaviour
{
    public Socket m_socket;
    IPEndPoint m_endPoint;
    private SocketAsyncEventArgs m_connectSAEA;
    private SocketAsyncEventArgs m_sendSAEA;
    public static string ip = "10.175.46.8";
    public int port = 5000;
    
    private void Start()
    {
        Client();
    }
    public void Client()
    {
        m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IPAddress iPAddress = IPAddress.Parse(ip);
        m_endPoint = new IPEndPoint(iPAddress, port);
        m_connectSAEA = new SocketAsyncEventArgs { RemoteEndPoint = m_endPoint };
        m_connectSAEA.Completed += new EventHandler<SocketAsyncEventArgs>(OnConnectedCompleted);
        m_socket.ConnectAsync(m_connectSAEA);
    }

    private void OnConnectedCompleted(object sender, SocketAsyncEventArgs e)
    {
        if (e.SocketError != SocketError.Success) return;
        Socket socket = sender as Socket;
        string iPRemote = socket.RemoteEndPoint.ToString();

        Debug.Log("Client : 连接服务器" + iPRemote + "成功");

        SocketAsyncEventArgs receiveSAEA = new SocketAsyncEventArgs();
        byte[] receiveBuffer = new byte[1024*1024*16];
        receiveSAEA.SetBuffer(receiveBuffer, 0, receiveBuffer.Length);
        receiveSAEA.Completed += OnReceiveCompleted;
        receiveSAEA.RemoteEndPoint = m_endPoint;
        socket.ReceiveAsync(receiveSAEA);
    }
    private void OnReceiveCompleted(object sender, SocketAsyncEventArgs e)
    {

        if (e.SocketError == SocketError.OperationAborted) return;

        Socket socket = sender as Socket;

        if (e.SocketError == SocketError.Success && e.BytesTransferred > 0)
        {
            ipAdress = socket.RemoteEndPoint.ToString();
            lengthBuffer = e.BytesTransferred;
            receiveBuffer = e.Buffer;
            
            //向服务器端发送消息
            Send("成功收到消息");
            
			socket.ReceiveAsync(e);  
		}
		else if (e.SocketError == SocketError.ConnectionReset && e.BytesTransferred == 0)
        {
            Debug.Log("Client: 服务器断开连接 ");
        }
        else
        {
            return;
        }

        #region 发送
    	public void Send(string msg)
    	{
        	byte[] sendBuffer = Encoding.Default.GetBytes(msg);
        	if (m_sendSAEA == null)
        	{
            	m_sendSAEA = new SocketAsyncEventArgs();
            	m_sendSAEA.Completed += OnSendCompleted;
        	}

        	m_sendSAEA.SetBuffer(sendBuffer, 0, sendBuffer.Length);
        	if (m_socket != null)
        	{
            	m_socket.SendAsync(m_sendSAEA);
        	}
    	}

    	private void OnSendCompleted(object sender, SocketAsyncEventArgs e)
    	{
        	if (e.SocketError != SocketError.Success) return;
        	Socket socket = sender as Socket;
        	byte[] sendBuffer = e.Buffer;

        	string sendMsg = Encoding.Default.GetString(sendBuffer);

        	Debug.Log("Client : Send message"+ sendMsg+ "to Serer"+ socket.RemoteEndPoint.ToString());
    }
    #endregion
    #region 断开连接
    public void DisConnect()
    {
        if (m_socket != null)
        {
            try
            {
                m_socket.Shutdown(SocketShutdown.Both);
            }
            catch (SocketException e)
            {
            }
            finally
            {
                m_socket.Close();
            }
        }
    }
    #endregion

}

打包生成UWP应用,Player Setting如下:
HoloLens中基于Socket的TCP通信系统
HoloLens中基于Socket的TCP通信系统
Capabilities设置如下:
HoloLens中基于Socket的TCP通信系统

测试与使用

在Unity中启动客户端,设置ip和port,启动服务器。
在HoloLens中运行之前打包生成的客户端UWP,与服务器进行连接,控制台消息如下:
HoloLens中基于Socket的TCP通信系统

相关标签: HoloLens