【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通讯,但是上一个例子只能实现一个服务端和一个客户端之间的通讯,如果有多个客户端连接服务端,则需要通过多线程技术来实 ...
随机推荐
- Go-并发-Go程和信道
- [转帖]Oracle与防火墙
https://www.laoxiong.net/oracle_and_firewall.html 老熊 Oracle数据库管理 2009-04-20 最近有两次Oracle数据库故障与防火墙有关.这 ...
- [转帖]警惕Oracle数据库性能“隐形杀手”——Direct Path Read
一. 简介 Oracle 的11g版本正式发布到今天已经10年有余,最新版本也已经到了20c,但是Direct Path Read(直接路径读)导致性能问题的案例仍时有发生,很多12c的用户还是经常遇 ...
- [转帖]如何用python连接Linux服务器
1.安装paramiko库 pip install paramiko 2.使用paramiko库连接linux #导入库 import paramiko 创建一个sshclient对象 ssh = p ...
- 编译打包rabbitmq然后一键部署的简单方法
摘要 之前总结过一版,但是感觉不太全面 想着本次能够将使用中遇到的问题总结一下. 所以本次是第二版 介质下载 rabbitmq 不区分介质的打包文件 rabbitmq-server-generic-u ...
- 基于javaPoet的缓存key优化实践
一. 背景 在一次系统opsreview中,发现了一些服务配置了@Cacheable注解.@cacheable 来源于spring cache框架中,作用是使用aop的方式将数据库中的热数据缓存在re ...
- Ant Design Vue栅格Grid的使用
栅格系统的设计理念 建议横向排列的盒子数量最多四个,最少一个. 因此我们的span一般设置为3或者4 小屏幕的话就另当别论了 栅格系统的简单介绍 1.通过row在水平方向建立一组column(简写 c ...
- Go泛型简介
Go语言的泛型是在Go 1.18版本中引入的一个新特性,它允许开发者编写可以处理不同数据类型的代码,而无需为每种数据类型都编写重复的代码.以下是关于Go语言泛型的一些关键点: 泛型是通过在函数或类型定 ...
- 在C#或python中使用xpath解析xml
记几个笔记 文件后缀不一定要.xml,可以是任意后缀,只要内容是符合xml和格式即可解析出来 文件编码需要是utf-8,python和c#都需要,或者xml文件头有这样一句:<?xml vers ...
- TienChin 渠道管理-渠道页面完善
最后附上渠道管理的数据 install SQL 语句: INSERT INTO TienChin.tienchin_channel (channel_id, channel_name, status, ...