Unity3D网络游戏0.1

一、网络游戏的架构

(1)网络游戏:

  分为客户端服务端两个部分,客户端程序运行在用户的电脑或手机上,服务端程序运行在游戏运营商的服务器上。
  以下是一些典型的游戏客户端。
Unity3D网络游戏0.1_第1张图片                          《金铲铲之战》客户端

Unity3D网络游戏0.1_第2张图片                         《英雄联盟》客户端

(2)游戏使用的网络通信协议:

  TCP是游戏中常用的网络通信协议,除此之外还有UDP、KCP、HTTP等协议。

(3)客户端间通信方式:

  客户端和客户端之间通过服务端的信息转发进行通信。
Unity3D网络游戏0.1_第3张图片

(4)位置同步实例:

  玩家1移动->客户端1向服务端发送新的坐标信息->服务端处理信息->服务端将玩家1的新坐标转发给客户端2->客户端2收到信息并更新玩家1的位置。

(5)服务端的分布式架构

  为了支撑可能百万的用户同时在线,游戏服务端通常采用分布式架构使用分区的服务端,每个服务端负责不同区的玩家
  客户端连接服务端。服务端之间互相连接(通常使用TCP网络通信),形成服务端集群
Unity3D网络游戏0.1_第4张图片

二、网络连接的端点:Socket

(1)Socket

  网络中两个程序通过一个双向的通信连接实现数据交换,这个连接的一端称为一个Socket

  • Socket包含进行网络通信必须的五种信息
     【1】连接使用的协议
     【2】本地主机的IP地址
     【3】本地的协议端口
     【4】远程主机的IP地址
     【5】远程协议端口
  • 至少需要两个Socket才能进行网络通信。

(2)IP地址

  网络上的计算机都是通过IP地址识别的,应用程序通过通信端口彼此通信

  • 自己计算机的IP称为”本地IP“。
  • 别人计算机的IP称为”远程IP“。
  • 在Windows命令提示符窗口输入ipconfig查看本机IP地址。
  • 可用理解为每一个IP地址对应于一台计算机(实际上一台计算机可用拥有多个IP)。

(3)端口

  端口是设备与外界通信交流的出口

  • 每台计算机可以分配0~65535个端口。
  • 端口是个逻辑概念, IP地址+端口 类似于 xx路+xx号 。
  • 每个Socket连接都是从一台计算机的一个端口连接到另外一台计算机的某个端口。
  • 一个进程可以拥有多个Socket,每个Socket通过不同的端口与其他计算机连接。
  • 每一条Socket代表着:本地IP -> 本地端口 -> 网络介质 -> 远程端口 -> 远程Socket 的链路。
  • Socket通信分为”通信方“和”监听方“,连接方使用不同的端口连接,监听方只使用一个端口监听
  • 所有客户端的连接请求都由服务端固定的唯一监听端口处理,且监听端口仅处理监听事务
  • 客户端的游戏进程可以创建多个Socket与服务器的监听端口进行连接同一进程的不同Socket指的是使用不同的端口与服务器监听端口进行连接。服务端的固定监听端口针对每一个Socket连接产生新的Socket用于处理客户端不同Socket与服务端的数据交换

(4)Socket的通信流程

  Socket通信的基本流程如下所示:
  (1)开启一个连接前需要创建一个Socket对象(使用API Socket),然后绑定本地使用的端口(API Bind)客户端在连接时(使用API Connect)会有系统分配端口。(即客户端和服务端都需要先创建Socket然后绑定端口
  (2)服务端开启监听(使用API Listen)等待客户端接入(API Connect)
  (3)客户端连接服务端(使用API Connect)
  (4)服务器接受连接(使用API Accept)
  (5)客户端和服务端通过Send和Receive等API 收发数据,操作系统会自动完成数据的确认、重传等步骤,确保传输的数据准确无误。
  (6)某一方关闭连接(API Close),操作系统会执行 ”四次挥手“ 的步骤,关闭双方连接
Unity3D网络游戏0.1_第5张图片

(5)编写客户端程序

  核心代码:

public class Echo : MonoBehaviour
{
	Socket socket;
	public InputField = InputFeld;
	public Text text;
	public void Connection()
	{
		//创建Socket
		Socket socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
		//连接服务器
		socket.Connect("127.0.0.1",8888);
	}
	
	public void Send()
	{
		string sendStr = Input.Feld.text;
		//字符串转换为字节流
		byte[] sendBytes = System.Text.Encoding.Default.GetBytes(sendStr);
		//发送字节流
		socket.Send(sendBytes);
		byte[] readBuff = new byte[1024];
		//接受消息转换字节流为字符串
		int count = socket.Receive(readBuff);
		string recvStr = System.Text.Encoding.Default.GetString(readBuff,0,count);
		text.text = recvStr;
		socket.Close();
	}
}

  上述程序包含知识点的含义如下:
  (1)using System.Net.Sockets
   Socket编程的API(如Socket、AddressFamily等)位于System.Net.Sockets命名空间中,因此引用。
  (2)创建 Socket 对象
    Socket(地址族,套接字类型,协议)用于创建Socket对象。
   地址族指明使用IPv4还是IPv6,其值与对应含义如下所示:

AddressFamily的值 含义
InterNetwork 使用IPv4
InterNetworkV6 使用IPv6

   SocketType是指套接字类型(游戏中最常用的是字节流套接字即Stream):

SocketType的值 含义
Dgram 支持数据报
Raw 支持对基础传输协议的访问
RDM 支持无连接、面向消息、以可靠方式发送的信息
Seqpacket 在网络上提供排序字节流的面向连接且可靠的双向传输
Stream 支持可靠、双向、基于连接的字节流,而且不重复数据,也不保留边界。
Unknown 指定未知的Socket类型

    微软官方文档

   ProtocolType指明协议

    微软官方文档

  (3)连接Connect
   客户端会通过socket.Connect(远程IP地址,远程端口)连接服务端。Connect是一个阻塞的方法,直到服务端回应接受、拒绝或超时)。
  (4)发送消息Send
   通过Socket.Send()方法发送数据,Send是一个阻塞的方法接受byte[]类型参数为发送内容,返回值为发送数据的长度。使用System.Text.Encoding.Default. GetBytes(sendStr)可将字符串sendStr转换为byte[] 数组。
   备注:发送的成功完成并不表示数据已成功传递。 如果传输系统中没有可用于保存要传输的数据的缓冲区空间,除非套接字处于非阻止模式,否则发送将阻塞。
   官方文档阻塞描述
  (5)接受消息Receive
   客户端通过socket.Receive()方法接受服务端消息,Receive是一个阻塞方法直到接受到服务端数据为止。其返回值为接受到的字符数组的长度。使用System.Text.Encoding.Default.GetString(readBuff,0,count)将字符数组转换为字符串。
  (6)关闭链接Close
   通过socket.Close关闭连接。

  备注:关于详细unity的UI界面创建以及事件的添加本文不做阐述,详情见《Unity3D网络游戏实战》,本文中部分内容引用于其。

(5)编写服务端程序

class MainClas
{
	public static void Main(string[] args)
	{
		Console.WriteLine("Hello World!");
		//创建Socket
		Socket listenfd = new Socket(AddressFamily.InterNetWork,SocketType.Stream,ProtocolType.Tcp);
		//创建Bind
		IPAddress ipAdr = IPAddress.Parse("127.0.0.1");
		IPEndPoint ipEp = new IPEndPoint(ipAdr,8888);
		listenfd.Bind(ipEp);
		//监听listen
		listenfd.Listen(0);
		while(true)
		{
			//等待客户端连接
			Socket connfd = listenfd.Accept();
			byte[] readBuff = new byte[1024];
			//接受信息
			int count = connfd.Receive(readBuff);
			string readStr = System.Text.Encoding.Default.GetString(readBuff,0,count);
			Console.WriteLine("[服务器接受]"+readStr);
			//发送信息
			byte[] sendBytes = System.Text.Encoding.Default.GetBytes(readStr);
			connfd.Send(sendBytes);
		}
	} 
}

  上述程序包含知识点的含义如下:
  (1)绑定Bind
   listenfd.Bind(ipEp)方法将给listenfd套接字绑定IP和端口
   注:“127.0.0.1”是回送地址,指本地机,一般用于测试。
  (2)监听Listen
   服务器通过listenfd.Listen(backlog)开启监听等待客户端连接。参数backlog指定队列中最多可容纳等待接受的连接数,0表示不受限制。
  (3)应答Accept
   开启监听后,服务器调用listenfd.Accept()接收客户端连接,Accept()方法为阻塞方法,直到监听到客户端连接,Accept()方法会返回一个新客户端的Socket对象
   注:对于服务端而言,有一个监听Socket(例中listenfd)用来监听(Listen)和应答(Accept)客户端的连接,对每一个客户端还有一个专门的Socket(例中connfd)用来处理该客户端的数据
  (4)IPAddressIPEndPoint
   使用IPAddress指定IP地址,使用IPEndPoint指定IP和端口

  思考:当前服务端每次只能处理一个客户端的请求,如果我们要做一套聊天系统,它必须同时处理多个客户端的请求,那么该如何实现呢?

(6)更多API

  System.Net.Socket命名空间中的Socket类为网络通信提供了一套丰富的方法和属性,更多API可查阅微软.Net Socket官方文档。

(7)公网和局域网

  将服务端连接到公网,例如连接宽带,或者购买阿里云、腾讯云服务器,就可以获得这一台计算机的公网IP。客户端只需要连接这个公网IP和端口,即可连接到服务器
  如果使用无限路由或者局域网,将宽带连接路由器上,再由路由器分发到多台计算机(校园网,公司局域网)。这种情况下,路由器会有公网和局域网两个IP。如果将服务器部署到连接路由器的某台计算机上,因为它只有局域网IP,所以只有局域网内的计算机可以连接上。如果拥有路由器的控制权,可以利用“端口映射”技术使外网计算机访问内网服务端计算机。
  如果没有路由器控制权,将服务端程序部署到阿里云、腾讯云等云服务器即可。
Unity3D网络游戏0.1_第6张图片

你可能感兴趣的:(Unity网络游戏,网络,开发语言)