HoloLens中基于Socket的TCP通信系统
程序员文章站
2022-04-28 21:29:51
...
系统目标
实现服务器端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如下:
Capabilities设置如下:
测试与使用
在Unity中启动客户端,设置ip和port,启动服务器。
在HoloLens中运行之前打包生成的客户端UWP,与服务器进行连接,控制台消息如下:
上一篇: jQuery treepanel动态加载数据实现代码
下一篇: require.js的模块化知识整理
推荐阅读
-
详解Android 基于TCP和UDP协议的Socket通信
-
Android基于TCP协议的Socket通信简单实例
-
基于epoll的tcp-socket通信服务模块
-
Java中的网络编程(UDP通信、TCP通信、Socket编程)
-
TCP/IP课程设计总结(基于socket实现的简易聊天系统)
-
linux网络编程之用socket实现简单客户端和服务端的通信(基于TCP)
-
C#基于Socket的UDP和TCP处理通信报文开发传输
-
Java基于TCP协议的Socket通信
-
python中基于tcp协议的通信(数据传输)
-
基于Java的Socket类Tcp网络编程实现实时聊天互动程序(二):Tcp通信的过程及代码编写