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通讯的更多相关文章

  1. Unity3d基于Socket通讯例子(转)

    按语:按照下文,服务端利用网络测试工具,把下面客户端代码放到U3D中摄像机上,运行结果正确. http://www.manew.com/thread-102109-1-1.html 在一个网站上看到有 ...

  2. GJM: Unity3D基于Socket通讯例子 [转载]

    首先创建一个C# 控制台应用程序, 直接服务器端代码丢进去,然后再到Unity 里面建立一个工程,把客户端代码挂到相机上,运行服务端,再运行客户端. 高手勿喷!~! 完全源码已经奉上,大家开始研究吧! ...

  3. Unity3d网络游戏Socket通讯

    http://blog.csdn.net/wu5101608/article/details/37999409

  4. 利用BlazeDS的AMF3数据封装与Flash 进行Socket通讯

    前几天看到了Adobe有个开源项目BlazeDS,里面提供了Java封装AMF3格式的方法.这个项目貌似主要是利用Flex来Remoting的,不过我们可以利用他来与Flash中的Socket通讯. ...

  5. c#Socket通讯

    参考http://bbs.cskin.net/thread-326-1-1.html的大神的代码 socket封装 /// <summary> /// 自定义Socket对象 /// &l ...

  6. 闲来无事,写个基于TCP协议的Socket通讯Demo

    .Net Socket通讯可以使用Socket类,也可以使用 TcpClient. TcpListener 和 UdpClient类.我这里使用的是Socket类,Tcp协议. 程序很简单,一个命令行 ...

  7. 试解析Tomcat运行原理(一)--- socket通讯

    关于这篇文章也确实筹划了很久,今天决定开篇写第一篇,说起tomcat首先很容易联想到IIS,因为我最开始使用的就是.net技术,我第一次使用asp写学生成绩管理系统后,很茫然如何让别人都能看到或者说使 ...

  8. c# TCP Socket通讯基础

    在做网络通讯方面的程序时,必不可少的是Socket通讯. 那么我们需要有一套既定的,简易的通讯流程. 如下: <pre name="code" class="csh ...

  9. Android笔记:Socket通讯常见问题

    经验证的socket通讯问题 1.如果是模拟器和本机PC直接通讯,需要使用本机IP地址 而不是 10.0.2.2  如本机的静态地址为192.168.1.2 则直接使用该地址 2.接收和连接代码不能在 ...

  10. java socket通讯(二)处理多个客户端连接

    通过java socket通讯(一) 入门示例,就可以实现服务端和客户端的socket通讯,但是上一个例子只能实现一个服务端和一个客户端之间的通讯,如果有多个客户端连接服务端,则需要通过多线程技术来实 ...

随机推荐

  1. Go-并发-Go程和信道

  2. [转帖]Oracle与防火墙

    https://www.laoxiong.net/oracle_and_firewall.html 老熊 Oracle数据库管理 2009-04-20 最近有两次Oracle数据库故障与防火墙有关.这 ...

  3. [转帖]警惕Oracle数据库性能“隐形杀手”——Direct Path Read

    一. 简介 Oracle 的11g版本正式发布到今天已经10年有余,最新版本也已经到了20c,但是Direct Path Read(直接路径读)导致性能问题的案例仍时有发生,很多12c的用户还是经常遇 ...

  4. [转帖]如何用python连接Linux服务器

    1.安装paramiko库 pip install paramiko 2.使用paramiko库连接linux #导入库 import paramiko 创建一个sshclient对象 ssh = p ...

  5. 编译打包rabbitmq然后一键部署的简单方法

    摘要 之前总结过一版,但是感觉不太全面 想着本次能够将使用中遇到的问题总结一下. 所以本次是第二版 介质下载 rabbitmq 不区分介质的打包文件 rabbitmq-server-generic-u ...

  6. 基于javaPoet的缓存key优化实践

    一. 背景 在一次系统opsreview中,发现了一些服务配置了@Cacheable注解.@cacheable 来源于spring cache框架中,作用是使用aop的方式将数据库中的热数据缓存在re ...

  7. Ant Design Vue栅格Grid的使用

    栅格系统的设计理念 建议横向排列的盒子数量最多四个,最少一个. 因此我们的span一般设置为3或者4 小屏幕的话就另当别论了 栅格系统的简单介绍 1.通过row在水平方向建立一组column(简写 c ...

  8. Go泛型简介

    Go语言的泛型是在Go 1.18版本中引入的一个新特性,它允许开发者编写可以处理不同数据类型的代码,而无需为每种数据类型都编写重复的代码.以下是关于Go语言泛型的一些关键点: 泛型是通过在函数或类型定 ...

  9. 在C#或python中使用xpath解析xml

    记几个笔记 文件后缀不一定要.xml,可以是任意后缀,只要内容是符合xml和格式即可解析出来 文件编码需要是utf-8,python和c#都需要,或者xml文件头有这样一句:<?xml vers ...

  10. TienChin 渠道管理-渠道页面完善

    最后附上渠道管理的数据 install SQL 语句: INSERT INTO TienChin.tienchin_channel (channel_id, channel_name, status, ...