【Unity3D】同步Socket通讯
1 前言在多人对战网络游戏中,玩家之间一般不是直接通讯,而是与服务器通讯,服务器再把消息转发给其他玩家。网络通讯一般基于 Socket 实现,也有一些开源网络游戏框架,如:光子引擎 Photon,其底层仍然使用 Socket 实现网络通讯。
同步 Socket 是指 Socket 的部分方法会阻塞当前线程(如:Accept、Receive 方法),直到方法返回,当前线程才会继续执行。
当有客户连接上服务器后,服务器会生成一个 Socket(通过 Accept 方法返回 Socket,可以理解为客服),与客户对接,进行信息交流。
2 案例
1)Socket 基本操作接口
BaseSocket.cs
public interface BaseSocket {
void Listening(); // 监听连接, 监听消息
void Receive(); // 接收到消息
void Send(string msg); // 发送消息
}
2)服务端
SyncSocketServer.cs
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
public class SyncSocketServer : BaseSocket{
private Socket serverSocket; // 服务端通讯主机socket, 监听打进来的电话,并转接给客服
private Socket kefuScoket; // 客服socket, 负责与客户一对一通讯
private Action<string> msgCallback; // 消息回调
private byte[] readBuff; // 收到消息的缓存
public SyncSocketServer(Action<string> callback) {
msgCallback = callback;
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, 12345);
serverSocket.Bind(endPoint); // 绑定ip和端口
new Thread(() => {
Listening();
}).Start();
}
public void Listening() {
serverSocket.Listen(1); // 监听电话连接, 设置最大客服人数, 如果是0就是无限个客服
kefuScoket = serverSocket.Accept(); // 接电话, 分配客服和客户进行一对一通信, 没有电话打进来就会一直阻塞
msgCallback(&#34;客服的本地端口是: &#34; + kefuScoket.LocalEndPoint.ToString());
msgCallback(&#34;客户的远程端口是: &#34; + kefuScoket.RemoteEndPoint.ToString());
readBuff = new byte;
while(true) {
Receive();
}
}
public void Receive() {
Array.Clear(readBuff, 0, readBuff.Length); // 清空缓存
int count = kefuScoket.Receive(readBuff); // 收到消息, 并存放在缓冲区, 没有消息就会一直阻塞
string msg = Encoding.UTF8.GetString(readBuff, 0, count);
msgCallback(&#34;客户端发来消息: &#34; + msg);
}
public void Send(string msg) {
byte[] buffer = Encoding.UTF8.GetBytes(msg);
kefuScoket.Send(buffer);
}
~SyncSocketServer() {
kefuScoket.Close();
serverSocket.Close();
}
}
3)客户端
SyncSocketClient.cs
using System;
using System.Net.Sockets;
using System.Text;
using System.Threading;
public class SyncSocketClient : BaseSocket {
private Socket clientSocket; // 客户端socket
private Action<string> msgCallback; // 消息回调
private byte[] readBuff; // 收到消息的缓存
public SyncSocketClient(Action<string> callback) {
msgCallback = callback;
clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
new Thread(() => {
clientSocket.Connect(&#34;127.0.0.1&#34;, 12345); //连接服务器, 未连接上就会一直阻塞
Listening();
}).Start();
}
public void Listening() {
readBuff = new byte;
while(true) {
Receive();
}
}
public void Receive() {
Array.Clear(readBuff, 0, readBuff.Length); // 清空缓存
int count = clientSocket.Receive(readBuff); // 收到消息, 并存放在缓冲区, 没有消息就会一直阻塞
string msg = Encoding.UTF8.GetString(readBuff, 0, count);
msgCallback(&#34;客服发来消息: &#34; + msg);
}
public void Send(string msg) {
byte[] buffer = Encoding.UTF8.GetBytes(msg);
clientSocket.Send(buffer);
}
~SyncSocketClient() {
clientSocket.Close();
}
}
4)测试类
SyncSocketTest.cs
using UnityEngine;
public class SyncSocketTest : MonoBehaviour {
private BaseSocket socket; // 客户端/服务端socket
private string sendText; // 发送的消息
private string receiveText; // 接收的消息
private bool isSideInited = false; // 是否已初始化端测
private string sideTag = null; // 端测标记, 服务端/客户端
private void Awake() {
Application.runInBackground = true; // 支持后台运行
}
private void OnGUI() {
InitSide();
initSideView();
}
private void InitSide() { // 初始化端测
if (!isSideInited) {
CreateServer();
CreateClient();
}
}
private void CreateServer() { // 创建服务器
if (GUILayout.Button(&#34;创建服务器&#34;)) {
socket = new SyncSocketServer((msg) => {
receiveText += msg + &#34;\n&#34;;
});
sideTag = &#34;服务端&#34;;
isSideInited = true;
}
}
private void CreateClient() { // 创建客户端
if (GUILayout<span class="p">.Button(&#34;创建客户端&#34;)) {
socket = new SyncSocketClient((msg) => {
receiveText += msg + &#34;\n&#34;;
});
sideTag = &#34;客户端&#34;;
isSideInited = true;
}
}
private void initSideView() { // 初始化端测界面
if (isSideInited) {
GUILayout.Label(sideTag);
sendText = GUILayout.TextField(sendText);
if (GUILayout.Button(&#34;发送&#34;)) {
socket.Send(sendText);
}
GUILayout.Label(&#34;接收到的消息: &#34;);
GUILayout.Label(receiveText);
}
}
}
5)运行效果
声明:本文转自【Unity3D】同步Socket通讯
页:
[1]