【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("客服的本地端口是: " + kefuScoket.LocalEndPoint.ToString());
msgCallback("客户的远程端口是: " + kefuScoket.RemoteEndPoint.ToString());
readBuff = new byte[1024];
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("客户端发来消息: " + 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("127.0.0.1", 12345); //连接服务器, 未连接上就会一直阻塞
Listening();
}).Start();
}
public void Listening() {
readBuff = new byte[1024];
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("客服发来消息: " + 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("创建服务器")) {
socket = new SyncSocketServer((msg) => {
receiveText += msg + "\n";
});
sideTag = "服务端";
isSideInited = true;
}
}
private void CreateClient() { // 创建客户端
if (GUILayout.Button("创建客户端")) {
socket = new SyncSocketClient((msg) => {
receiveText += msg + "\n";
});
sideTag = "客户端";
isSideInited = true;
}
}
private void initSideView() { // 初始化端测界面
if (isSideInited) {
GUILayout.Label(sideTag);
sendText = GUILayout.TextField(sendText);
if (GUILayout.Button("发送")) {
socket.Send(sendText);
}
GUILayout.Label("接收到的消息: ");
GUILayout.Label(receiveText);
}
}
}
5)运行效果

声明:本文转自【Unity3D】同步Socket通讯
【Unity3D】同步Socket通讯的更多相关文章
- Unity3d基于Socket通讯例子(转)
按语:按照下文,服务端利用网络测试工具,把下面客户端代码放到U3D中摄像机上,运行结果正确. http://www.manew.com/thread-102109-1-1.html 在一个网站上看到有 ...
- GJM: Unity3D基于Socket通讯例子 [转载]
首先创建一个C# 控制台应用程序, 直接服务器端代码丢进去,然后再到Unity 里面建立一个工程,把客户端代码挂到相机上,运行服务端,再运行客户端. 高手勿喷!~! 完全源码已经奉上,大家开始研究吧! ...
- Unity3d网络游戏Socket通讯
http://blog.csdn.net/wu5101608/article/details/37999409
- 利用BlazeDS的AMF3数据封装与Flash 进行Socket通讯
前几天看到了Adobe有个开源项目BlazeDS,里面提供了Java封装AMF3格式的方法.这个项目貌似主要是利用Flex来Remoting的,不过我们可以利用他来与Flash中的Socket通讯. ...
- c#Socket通讯
参考http://bbs.cskin.net/thread-326-1-1.html的大神的代码 socket封装 /// <summary> /// 自定义Socket对象 /// &l ...
- 闲来无事,写个基于TCP协议的Socket通讯Demo
.Net Socket通讯可以使用Socket类,也可以使用 TcpClient. TcpListener 和 UdpClient类.我这里使用的是Socket类,Tcp协议. 程序很简单,一个命令行 ...
- 试解析Tomcat运行原理(一)--- socket通讯
关于这篇文章也确实筹划了很久,今天决定开篇写第一篇,说起tomcat首先很容易联想到IIS,因为我最开始使用的就是.net技术,我第一次使用asp写学生成绩管理系统后,很茫然如何让别人都能看到或者说使 ...
- c# TCP Socket通讯基础
在做网络通讯方面的程序时,必不可少的是Socket通讯. 那么我们需要有一套既定的,简易的通讯流程. 如下: <pre name="code" class="csh ...
- Android笔记:Socket通讯常见问题
经验证的socket通讯问题 1.如果是模拟器和本机PC直接通讯,需要使用本机IP地址 而不是 10.0.2.2 如本机的静态地址为192.168.1.2 则直接使用该地址 2.接收和连接代码不能在 ...
- java socket通讯(二)处理多个客户端连接
通过java socket通讯(一) 入门示例,就可以实现服务端和客户端的socket通讯,但是上一个例子只能实现一个服务端和一个客户端之间的通讯,如果有多个客户端连接服务端,则需要通过多线程技术来实 ...
随机推荐
- 使用QQ屏幕识图实现识别表格功能
1.问题 目前市场上的OCR工具对于识别表格功能均是采取了收费制度,但我们时常要进行一些表格的复制(原表格为图片) 便可以使用QQ或钉钉自带的功能来实现 2.解决 1.QQ屏幕识图 先使用屏幕识图功能 ...
- 百度网盘(百度云)SVIP超级会员共享账号每日更新(2023.11.22)
一.百度网盘SVIP超级会员共享账号 可能很多人不懂这个共享账号是什么意思,小编在这里给大家做一下解答. 我们多知道百度网盘很大的用处就是类似U盘,不同的人把文件上传到百度网盘,别人可以直接下载,避免 ...
- 【面试题精讲】说一说springboot加载配置文件优先级
有的时候博客内容会有变动,首发博客是最新的,其他博客地址可能会未同步,认准https://blog.zysicyj.top 首发博客地址 文章更新计划 系列文章地址 Spring Boot 加载配置文 ...
- Python学习之十二_tkinter的学习与使用
Python学习之十二_tkinter的学习与使用 摘要 本来想说会用QT5进行界面编程 但是发现比较繁琐 还是先学习使用 tkinter的方式进行界面化的编写和学习了 基础知识 tkinter是一个 ...
- [转帖]绕过CDN查看网站真实IP
https://www.itblogcn.com/article/viewcdnip.html 这是一个总结帖,查了一下关于这个问题的国内外大大小小的网站,对其中说的一些方法总结归纳形成. 首先, ...
- [转帖]GPT4All 一个开源 ChatGPT
https://zhuanlan.zhihu.com/p/618947904 通用预训练语言模型. ChatGPT 正在迅速发展与传播,新的大型语言模型 (LLM) 正在以越来越快的速度开发.就在过去 ...
- [转帖]iozone - 性能压力测试工具
<存储工具系列文章>主要介绍存储相关的测试和调试工具,包括不限于dd.fio.vdbench.iozone.iometer.cosbench等性能负载工具,及strace等调试工具. 1 ...
- [转帖]Linux系统:page fault
Linux进程如何访问内存 Linux下,进程并不是直接访问物理内存,而是通过内存管理单元(MMU)来访问内存资源,原因后面会讲到. 为什么需要虚拟内存地址空间 假设某个进程需要4MB的空间,内存假设 ...
- [转帖]dd命令中dsync和fsync区别
在Linux系统中经常会使用dd命令来测试硬盘的写入速度,命令会涉及几个常用参数:sync.dsync.fsync与fdatasync # dd if=/dev/zero of=/tmp/1G bs= ...
- K8S的pod展示镜像信息
https://kubernetes.io/zh/docs/tasks/access-application-cluster/list-all-running-container-images/ ku ...