unity+socket通信


想做一個傳感器鼠標控制器(手機陀螺儀控制PC端鼠標移動),Socket服務是其他大佬寫的,PC端和Android同時請求服務生成ID然后PC端生成一個二維碼(二維碼信息就是那個ID),手機端進行掃描PC端二維碼進行PC端和手機端的連接,成功后,手機端和PC端就可以通訊啦。將手機端的陀螺儀數據實時傳給PC,PC端編寫將陀螺儀數據實時轉換成鼠標位置。(目前實現發送手機陀螺儀數據到PC端,PC端可以接受到數據,沒進行和鼠標位置關聯)

大佬給了個C#例子,我就是參考這個例子編寫的代碼。例子如下:

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TPlantPlayerSocketTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

Socket client1 = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Socket client2 = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

private void btnConnect_Click(object sender, EventArgs e)
{
//兩個客戶端連接上同一個端口,產生兩個會話
int nPort = 14020;
IPAddress ip = IPAddress.Parse("10.0.180.110");
IPEndPoint point = new IPEndPoint(ip, nPort);
client1.Connect(point);
client2.Connect(point);

//接收分配到會話id
byte[] buffer = new byte[1024 * 1024];
int n = client1.Receive(buffer);
string sSessonID1 = Encoding.Default.GetString(buffer, 0, n).Trim();
//接收分配到會話id
n = client2.Receive(buffer);
string sSessonID2 = Encoding.Default.GetString(buffer, 0, n).Trim();

//關聯兩個會話
string sSend = String.Format("Attach {0} {1}\r\n", sSessonID1, sSessonID2);
buffer = Encoding.Default.GetBytes(sSend);
client1.Send(buffer);

//接受關聯到的SessionID
n = client1.Receive(buffer);
sSessonID1 = Encoding.Default.GetString(buffer, 0, n).Trim();
//接受關聯到的SessionID
n = client2.Receive(buffer);
sSessonID2 = Encoding.Default.GetString(buffer, 0, n).Trim();

txtContent.Text = "Attach Success";
}

private void btnSend_Click(object sender, EventArgs e)
{
//一個會話給另外一個會話發送消息
byte[] buffer = Encoding.Default.GetBytes("Send json string for other!\r\n");
client1.Send(buffer);
//接受消息
byte[] buffer1 = new byte[1024 * 1024];
int n = client2.Receive(buffer1);
string sContent = Encoding.Default.GetString(buffer1, 0, n).Trim();
txtContent.Text = sContent;


/*byte[] buffer = Encoding.UTF8.GetBytes("json string for other!");
string sContent = Convert.ToBase64String(buffer) + "\r\n";
buffer = Encoding.Default.GetBytes(sContent);

client1.Send(buffer);

byte[] buffer1 = new byte[1024 * 1024];
int n = client2.Receive(buffer1);
sContent = Encoding.Default.GetString(buffer1, 0, n).Trim();
buffer1 = Convert.FromBase64String(sContent);
sContent = Encoding.UTF8.GetString(buffer1);
txtContent.Text = sContent;*/
}
}
}

 

 

 

下面是unity+PC端代碼:

1.TcpClientHandler

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

public class TcpClientHandler : MonoBehaviour
{
Socket serverSocket; //服務器端socket
private string ClientIP = "10.0.180.110";//IP地址
IPAddress ip; //主機ip
IPEndPoint ipEnd;
string recvStr; //接收的字符串
string ScanSuccessRecvStr;
string sendStr; //發送的字符串
byte[] recvData = new byte[1024]; //接收的數據,必須為字節
byte[] ScanSuccessRecvData = new byte[1024];
byte[] sendData = new byte[1024]; //發送的數據,必須為字節
int recvLen = 0; //接收的數據長度
Thread connectThread; //連接線程
public Vector3 ServerVector;
private Queue<string> queue = new Queue<string>();//新建一個隊列,用來存儲服務器發來的數據
private void Start()
{
//InitSocket();
OnStringToVector("(0,1,2)");
}
//服務器初始化
public void InitSocket()
{
ip = IPAddress.Parse(ClientIP);
ipEnd = new IPEndPoint(ip, 14020); //服務器端口號

//開啟一個線程連接
connectThread = new Thread(new ThreadStart(SocketReceive));
connectThread.Start();
}

//接收服務器消息
void SocketConnet()
{
if (serverSocket != null)
serverSocket.Close();
//定義套接字類型,必須在子線程中定義
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//連接
serverSocket.Connect(ipEnd);

recvLen = serverSocket.Receive(recvData);
recvStr = Encoding.UTF8.GetString(recvData, 0, recvLen);
//recvStr = Encoding.Default.GetString(recvData,0,recvLen);
print(recvStr);
Debug.LogError("SocketConnect:"+recvStr);
queue.Enqueue(recvStr);
}
void SocketReceive()
{
SocketConnet();
//不斷接收服務器發來的數據
while (true)
{
recvData = new byte[1024];
recvLen = serverSocket.Receive(recvData);
if (recvLen == 0)
{
SocketConnet();
continue;
}
recvStr = Encoding.UTF8.GetString(recvData, 0, recvLen);
queue.Enqueue(recvStr);
print(recvStr);
Debug.LogError("recvStr:"+recvStr);
//Debug.LogError("Vector3" + OnStringToVector(recvStr));
OnStringToVector(recvStr);
}
}
public void OnStringToVector(string p_sVec3)
{
Debug.LogError("^^^^6 " + p_sVec3);
if (p_sVec3 != "" && p_sVec3.Length != 0)
{
p_sVec3 = p_sVec3.Replace("(", "");
p_sVec3 = p_sVec3.Replace(")", "");
Debug.LogError("p_svec " + p_sVec3);
}
if (p_sVec3.Length <= 0)
{
ServerVector = Vector3.zero;
}
string[] tmp_sValues = p_sVec3.Trim(' ').Split(',');
if (tmp_sValues != null && tmp_sValues.Length == 3)
{
float tmp_fX = float.Parse(tmp_sValues[0]);
float tmp_fY = float.Parse(tmp_sValues[1]);
float tmp_fZ = float.Parse(tmp_sValues[2]);
ServerVector = new Vector3(tmp_fX, tmp_fY, tmp_fZ);
Debug.LogError("serverVector@@@ "+ServerVector);
}

}
private void OnApplicationQuit()
{
SocketQuit();


}
public void SocketQuit()
{
//關閉線程
if (connectThread != null)
{
connectThread.Interrupt();
connectThread.Abort();
}
//最后關閉服務器
if (serverSocket != null)
serverSocket.Close();
}

public void SocketSend(string sendStr)
{
//清空發送緩存
sendData = new byte[1024];
//數據類型轉換
sendData = Encoding.UTF8.GetBytes(sendStr);
//發送
serverSocket.Send(sendData, sendData.Length, SocketFlags.None);
}

//返回接收到的字符串
public string GetRecvStr()
{
string returnStr;
//加鎖防止字符串被改
lock (this)
{
if (queue.Count > 0)
{//隊列內有數據時,取出
returnStr = queue.Dequeue();
return returnStr;
}
}
return null;
}

}

 

2.TcpServer

 

using UnityEngine;
using System.Collections;
using LitJson;
using UnityEngine.SceneManagement;
using System.Collections.Generic;
using UnityEngine.UI;
public class TcpServer : MonoBehaviour
{
public static TcpServer _instance;
TcpClientHandler tcpClient;
JsonData returnDataJson;
public RawImage RawImageRef;
public string returnData { get; private set; }

 

void Awake()
{
DontDestroyOnLoad(this.gameObject);
}

 

// Use this for initialization
void Start()
{
//初始化網絡連接
//tcpClient=new TcpClientHandler();
tcpClient = gameObject.AddComponent<TcpClientHandler>();
tcpClient.InitSocket();
}

 

// Update is called once per frame
void Update()
{
//returnDataHandle();//2018.12.5
returnData = tcpClient.GetRecvStr();
if (returnData != null)
{
RawImageRef.texture=BarcodeCam.BarCodeCamInstance.CreateQRCode(returnData,512,512);
Debug.LogError("RawImage ");
}
}

 

//服務器返回消息的處理
void returnDataHandle()
{
returnData = tcpClient.GetRecvStr();
print(returnData);
Debug.LogError("returnData:"+returnData);
if (returnData != null)
{

 

returnDataJson = JsonMapper.ToObject(returnData);
Debug.LogError("returnDataJson:" + returnDataJson);
switch (returnDataJson["cmd"].ToString())
{

 

//在此處解析Json,如有項目需要,最好在其他腳本編寫,此處只為方便
}
}
else
{
Debug.LogError("This is null");
}
}

 

void OnApplicationQuit()
{
//退出時關閉連接
tcpClient.SocketQuit();
print("Quit");
}

 

public void closeC()
{//此處比較關鍵,因為在我們調試時,關閉程序Unity並不一定認為你是退出,所以上面代碼也許不會執行,導致與服務器一直連接,Unity崩潰
tcpClient.SocketQuit();
print("closeC");
}
}

 

 3.BarcodeCam

 

using UnityEngine;
using System.Collections;
using ZXing;
using ZXing.QrCode;
using System;
using ZXing.Common;
using ZXing.Rendering;
using System.Collections.Generic;

 

public class BarcodeCam : MonoBehaviour
{
public Texture2D encoded;

public static BarcodeCam BarCodeCamInstance;
void Awake()
{
BarCodeCamInstance = this;
}
void Start()
{

}
public Texture2D CreateQRCode(string QRCodeStr,int infowidth,int infoheight)
{
//設置二維碼大小
encoded = new Texture2D(infowidth, infoheight);
//二維碼邊框
BitMatrix BIT;
//設置二維碼掃描結果
string name = QRCodeStr;

 

Dictionary<EncodeHintType, object> hints = new Dictionary<EncodeHintType, object>();

 

//設置編碼方式
hints.Add(EncodeHintType.CHARACTER_SET, "UTF-8");

 

BIT = new MultiFormatWriter().encode(name, BarcodeFormat.QR_CODE, infowidth, infoheight, hints);
int width = BIT.Width;
int height = BIT.Width;

 

for (int x = 0; x < height; x++)
{
for (int y = 0; y < width; y++)
{
if (BIT[x, y])
{
encoded.SetPixel(y, x, Color.black);
}
else
{
encoded.SetPixel(y, x, Color.white);
}

 

}
}
encoded.Apply();
return encoded;

 

}
//void OnGUI()
//{
// GUI.DrawTexture(new Rect(100, 100, 256, 256), encoded);
//}

 

}

 

 

 下面是unity+Android的代碼

AccelerometerTest(手機加速儀應用)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class AccelerometerTest : MonoBehaviour {
public Transform destroy; //聲明掛載BlueClinderFX游戲對象的變量
public Transform flash; //聲明掛載BlueClinderFX(1)游戲對象的變量
public Transform sphere; //聲明場景中小球的游戲變量
Vector3 dir = Vector3.zero; //聲明一個三維向量的變量
private float distance; //定義距離變量
private bool flag = false; //聲明一個用來判斷小球是否消失的標志位
private float mindistance = 4.0f; //定義小球和BlueClinderFX游戲對象的最小距離變量
private Vector3 currentPos;
private float speed = 5.0f;
public Text AccelerometerTempText;//加速度

void Update()
{
UpdateInput();
dir.x = Input.acceleration.x; //三維向量的x分量為加速度傳感器的x分量
dir.z = Input.acceleration.y; //三維向量的z分量為加速度傳感器的y分量
this.transform.GetComponent<Rigidbody>().AddForce(dir * 5);//為小球添加力的效果
distance = Vector3.Distance(sphere.position, destroy.position);//獲取當前小球和BlueClinderFX的距離
//Debug.LogError("Distance"+distance);
AccelerometerTempText.text ="Accelerometer:"+ Input.acceleration.ToString();
if (distance <= mindistance)
{
sphere.position = destroy.position;//重置小球的當前位置
Invoke("spheredestroy", 0.1f); //在0.1秒后調用spheredestroy方法
flag = !flag; //標志位置反
}
if (flag)
{
//destroy.gameObject.SetActive(true);//BlueClinderFX
sphere.position = flash.position;//重置小球的當前位置
flash.gameObject.SetActive(true);//將BlueClinderFX(1)游戲對象的active置為true
Invoke("sphereflash", 1.0f);//在1秒后調用sphereflash方法
Invoke("flashreset", 10.0f);//在1秒后調用flashreset方法
flag = !flag;//標志位置反
}
}
void spheredestroy()
{
sphere.gameObject.SetActive(false);//將小球的active置為false(即為不可見)
}
void sphereflash()
{
sphere.gameObject.SetActive(true);//將小球的active置為true
}
void flashreset()
{
flash.gameObject.SetActive(false);//將BlueClinderFX(1)對象的active置為false
}
void UpdateInput()
{
if (Input.GetMouseButton(0))
{
Vector3 ms = Input.mousePosition;
// ms = Camera.main.ScreenToWorldPoint(ms);
Ray ray = Camera.main.ScreenPointToRay(ms);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
currentPos = hit.point;
}
Vector3 pos = Vector3.MoveTowards(this.transform.position, currentPos, speed * Time.deltaTime);
this.transform.position = pos;
}
}
}

GyroscopeTest(手機陀螺儀應用)

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

 

public class GyroscopeTest : MonoBehaviour {
bool draw = false;
bool gyinfo;
Gyroscope go;
public Text GyroscopeText;

void Start()
{
gyinfo = SystemInfo.supportsGyroscope;
go = Input.gyro;
go.enabled = true;
}
void Update()
{
if (gyinfo)
{
Vector3 a = go.attitude.eulerAngles;
a = new Vector3(-a.x, -a.y, a.z); //直接使用讀取的歐拉角發現不對,於是自己調整一下符號
this.transform.eulerAngles = a;
this.transform.Rotate(Vector3.right * 90, Space.World);
draw = false;
GyroscopeText.text = "Gyroscope:"+ go.attitude.ToString();
GlobleData.CurrentGyroscopeValue = go.attitude.ToString();
}
else
{
draw = true;
GlobleData.CurrentGyroscopeValue = gameObject.transform.position.ToString();
}
}

 

void OnGUI()
{
if (draw)
{
GUI.Label(new Rect(100, 100, 100, 30), "啟動失敗");
}
}
}

AndroidTcpClientHandler

 

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

 

public class AndroidTcpClientHandler : MonoBehaviour
{
Socket serverSocket; //服務器端socket
private string ClientIP = "10.0.180.110";//IP地址
IPAddress ip; //主機ip
IPEndPoint ipEnd;
string recvStr; //接收的字符串
string sendStr; //發送的字符串
byte[] recvData = new byte[1024]; //接收的數據,必須為字節
byte[] sendData = new byte[1024]; //發送的數據,必須為字節
int recvLen = 0; //接收的數據長度
Thread connectThread; //連接線程

private Queue<string> queue = new Queue<string>();//新建一個隊列,用來存儲服務器發來的數據
private void Start()
{
// InitSocket();
}
//服務器初始化
public void InitSocket()
{
ip = IPAddress.Parse(ClientIP);
ipEnd = new IPEndPoint(ip, 14020); //服務器端口號

 

//開啟一個線程連接
connectThread = new Thread(new ThreadStart(SocketReceive));
connectThread.Start();
}
void SocketReceive()
{
SocketConnet();
//不斷接收服務器發來的數據
while (true)
{
Debug.LogError("data$$4");
recvData = new byte[1024];
recvLen = serverSocket.Receive(recvData);
if (recvLen == 0)
{
SocketConnet();
continue;
}
recvStr = Encoding.UTF8.GetString(recvData, 0, recvLen);
queue.Enqueue(recvStr);
print(recvStr);
Debug.LogError("recvStr:"+recvStr);
}
}
public void ConnectChat(string ID1,string ID2)
{
byte[] buffer = new byte[1024*1024];
string sSend = string.Format("Attach {0} {1}\r\n",recvStr,GlobleData.ScannerServerID);
buffer = Encoding.Default.GetBytes(sSend);
serverSocket.Send(buffer);
Debug.LogError("buffer+"+buffer);
}
public void SendMessageToServer(string msg)
{
byte[] buffer = Encoding.Default.GetBytes("Send "+msg+"\r\n");
serverSocket.Send(buffer);
Debug.LogError("hah");
}

//接收服務器消息
void SocketConnet()
{
if (serverSocket != null)
serverSocket.Close();
//定義套接字類型,必須在子線程中定義
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//連接
serverSocket.Connect(ipEnd);

 

recvLen = serverSocket.Receive(recvData);
//recvStr = Encoding.UTF8.GetString(recvData, 0, recvLen);
recvStr = Encoding.Default.GetString(recvData, 0, recvLen);
print(recvStr);
Debug.LogError("SocketConnect:" + recvStr);
queue.Enqueue(recvStr);

 

}

//private void OnApplicationQuit()
//{
// SocketQuit();
//}
public void SocketQuit()
{
//關閉線程
if (connectThread != null)
{
connectThread.Interrupt();
connectThread.Abort();
}
//最后關閉服務器
if (serverSocket != null)
serverSocket.Close();
}

 

public void SocketSend(string sendStr)
{
//清空發送緩存
sendData = new byte[1024];
//數據類型轉換
sendData = Encoding.UTF8.GetBytes(sendStr);
//發送
serverSocket.Send(sendData, sendData.Length, SocketFlags.None);
}

 


//返回接收到的字符串
public string GetRecvStr()
{
string returnStr;
//加鎖防止字符串被改
lock (this)
{
if (queue.Count > 0)
{//隊列內有數據時,取出
returnStr = queue.Dequeue();
return returnStr;
}
}
return null;
}

}

AndroidTcpServer

 

using UnityEngine;
using System.Collections;
using LitJson;
using UnityEngine.SceneManagement;
using System.Collections.Generic;
using System.Text;
public class AndroidTcpServer : MonoBehaviour
{
public static AndroidTcpClientHandler _instance;
AndroidTcpClientHandler tcpClient;
JsonData returnDataJson;
bool isOnOnce=true;
public string returnData { get; private set; }

 

void Awake()
{

DontDestroyOnLoad(this.gameObject);
}

 

// Use this for initialization
void Start()
{
//初始化網絡連接
//tcpClient=new TcpClientHandler();
tcpClient = gameObject.AddComponent<AndroidTcpClientHandler>();
tcpClient.InitSocket();
}

 

// Update is called once per frame
void Update()
{
//returnDataHandle();
if (MouseToolLogic.MouseToolLogicInstance.IsScanSuccess)
{
if (GlobleData.ScannerServerID != "")
{
if (isOnOnce)
{
isOnOnce = false;
Debug.LogError("Connect ");
OnConnect();
}
}
}
}
private void OnConnect()
{
tcpClient.ConnectChat(tcpClient.GetRecvStr(),GlobleData.ScannerServerID);
}
public void OnSendMessageToServer()
{

 

tcpClient.SendMessageToServer(GlobleData.CurrentGyroscopeValue);
}
//服務器返回消息的處理
void returnDataHandle()
{
returnData = tcpClient.GetRecvStr();
//print (returnData);
if (returnData != null)
{

returnDataJson = JsonMapper.ToObject(returnData);
Debug.LogError("returnDataJson:"+returnDataJson);
switch (returnDataJson["cmd"].ToString())
{

//在此處解析Json,如有項目需要,最好在其他腳本編寫,此處只為方便

 

}
}
}

 

void OnApplicationQuit()
{
//退出時關閉連接
tcpClient.SocketQuit();
print("Quit");
}

 

public void closeC()
{//此處比較關鍵,因為在我們調試時,關閉程序Unity並不一定認為你是退出,所以上面代碼也許不會執行,導致與服務器一直連接,Unity崩潰
tcpClient.SocketQuit();
print("closeC");
}
}

 

 GlobleData

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GlobleData
{
public static string ScannerServerID="";
public static string CurrentGyroscopeValue="";
}

MouseToolLogic

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MouseToolLogic : MonoBehaviour {
public static MouseToolLogic MouseToolLogicInstance;
public GameObject QRCodePanel;
public bool IsScanSuccess=true;
private void Awake()
{
MouseToolLogicInstance = this;
}
// Use this for initialization
void Start ()
{

}
void ScannerLogic()
{
if (GlobleData.ScannerServerID != "")
{
SetPanelActive(QRCodePanel,false);
}
else
{
SetPanelActive(QRCodePanel,true);
}
}
void SetPanelActive(GameObject obj,bool isActive)
{
obj.SetActive(isActive);
}
// Update is called once per frame
void Update ()
{
//ScannerLogic();
}
}

 

Cam(調用攝像頭)

 

 

 

 

 

using UnityEngine;
using System.Collections;
using ZXing;
using UnityEngine.UI;

public class Cam : MonoBehaviour {
public Color32[] data;
private bool isScan; //是否能掃描
public RawImage cameraTexture;
public Text txt;
private WebCamTexture webCameraTexture;
private BarcodeReader barcodeReader;
private float timer = 0;
//public GameObject QRCodePanel;
IEnumerator Start()
{
barcodeReader = new BarcodeReader();
yield return Application.RequestUserAuthorization(UserAuthorization.WebCam);
if (Application.HasUserAuthorization(UserAuthorization.WebCam))
{
WebCamDevice[] devices = WebCamTexture.devices;
string devicename = devices[0].name;
webCameraTexture = new WebCamTexture(devicename, 400, 300);
cameraTexture.texture = webCameraTexture;
webCameraTexture.Play();
isScan = true;
}

}
int width;
//屏幕橫豎屏切換
void ScreenChange()
{
if (width == Screen.width)
return;
width = Screen.width;

if (width>Screen.height)
{
cameraTexture.transform.localEulerAngles = Vector3.zero;
}
else
{
cameraTexture.transform.localEulerAngles = new Vector3(0, 0, -90);
}
}

void Update()
{
Debug.LogError("hahhhhhhh");
if (isScan)
{
timer += Time.deltaTime;

if (timer >0.5f)// 0.5秒掃描一次
{
StartCoroutine(ScanQRcode());
timer = 0;
}
}
ScreenChange();
}

IEnumerator ScanQRcode()
{
data = webCameraTexture.GetPixels32();
DecodeQR(webCameraTexture.width, webCameraTexture.height);
yield return new WaitForEndOfFrame();
}

private void DecodeQR(int width, int height)
{
var br = barcodeReader.Decode(data, width, height);
if (br != null)
{
txt.text = br.Text;
//Debug.LogError("BR:"+br);
isScan = false;
GlobleData.ScannerServerID = br.Text;
}
}

}

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM