网络游戏《丛林战争》开发与学习之(一):网络编程的基础知识
《丛林战争》是一款完整的网络游戏案例,运用U3D开发客户端,Socket开发服务端,其中涉及到了网络编程、数据库和Unity的功能实现,之前通过U3D开发了一个单机游戏《黑暗之光》,并没有涉及网络编程的知识,通过《丛林战争》这个完整的游戏,系统性地学习网络编程,并进一步学习利用U3D开发游戏。
本篇内容是网络编程的基础知识,主要内容如下:
- 介绍TCP/IP的基本概念以及基础TCP协议
- 实现服务器端与客户端的同步收发
- 实现服务器端与客户端的异步收发
1. TCP/IP基本概念
下图是一个网络的简化图,可以看出IP的作用是在复杂的网络环境中将数据包发给最终的目标地址,本节主要介绍IP、端口号和TCP协议。
1.1 IP
IP分为局域网IP和公网IP,每台机都有这两个IP。当一个路由器连接多个主机,相当于路由器与这些主机组成了一个局域网,路由器会给每个主机分配一个局域网IP,可以在Win+R > cmd,小黑窗中输入ipconfig查到,公网IP则可以通过百度查询到。
1.2 端口号
主机之间通过路由器进行通信,以主机B与主机D通信为例,B通过ip地址找到了主机D,连接建立之后,考虑到进行通信最终是软件之间的交互,因此需要搞清是与什么软件进行通信。假设D中有QQ、微信、绝地求生等软件,需要为每个软件分配一个端口号。(即ip找机器,端口号找软件)
下图就是一个例子,IP数据172.23.12.14找到了主机A,A中各个端口号对应不同应用(图中以服务端为例),需要通过独有的端口号找到对应软件。后期也会学习如何向系统申请端口号。
一般知名端口号在0~1023之间,而我们经常使用的自定义/动态分配的端口号则一般在1024~65535之间。详细参考百度百科。https://baike.baidu.com/item/%E7%AB%AF%E5%8F%A3%E5%8F%B7/10883658
1.3 TCP协议(三次握手与四次挥手)
三次握手与四次挥手的详解可以参照该博客:https://blog.csdn.net/sssnmnmjmf/article/details/68486261
在这里大致解释一下:(主机A代表张三,B代表李四)
三次握手:
张三:李四你在吗?(请求连接)
李四:张三我在的(确认应答)
张三:好的我要发数据了(对李四的确认应答)
四次挥手:
张三:李四我没事了,挂电话了(请求切断)
李四:好的,知道你没事了(确认应答)
李四:那就这样,挂电话吧(请求切断)
张三:那我挂了(确认应答)
2 利用TCP协议实现服务端与客户端的通信
利用C#服务器控制应用程序实现简单的通信,步骤如下图,图中所示即为服务端与客户端的连接步骤,TCP连接都是基于这个规则。
2.1 服务端与客户端的同步收发
服务端代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Net;
namespace TCPServer
{class Program{static void Main(string[] args){Socket socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //第一个参数表示时候用ipv4,第二个Stream表示TCP传输用到的数据流,如果是UDP协议可以用Dgram报文//IPAddress xxx.xx.xx.xx IPEndPoint xxx.xx.xx.x:port 需要用到using System.Net;IPAddress ipAddr = IPAddress.Parse("127.0.0.1"); //服务器端申请ip及端口号IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, 1200);socketServer.Bind(ipEndPoint); //进行绑定socketServer.Listen(10); //最多处理10个连接的队列Socket socketClient = socketServer.Accept(); // 接收客户端连接,之后通过socketClient进行对客户端数据的收发//发送给客户端string sendMsg = "hello,客户端";byte[] sendData = Encoding.UTF8.GetBytes(sendMsg); //字符串转为bype数组发送,用到using System.Text;socketClient.Send(sendData);//从客户端接收byte[] recvData = new byte[1024]; //分配1024字节大小的空间存储int count = socketClient.Receive(recvData); //接收到的字节大小string recvMsg = Encoding.UTF8.GetString(recvData, 0, count); //数组转为字符串,转换0~count长度,由于recvData未填满,直接转换recvData会出错Console.WriteLine(recvMsg);socketClient.Close();socketServer.Close();}}
}
客户端代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Net;
namespace TCPClient
{class Program{static void Main(string[] args){Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);clientSocket.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1200));//从服务端接收数据byte[] dataRecv = new byte[1024]; int count = clientSocket.Receive(dataRecv);string msgRecv = Encoding.UTF8.GetString(dataRecv, 0, count);Console.WriteLine(msgRecv);//向服务端发送数据string msgSend = Console.ReadLine();byte[] dataSend = Encoding.UTF8.GetBytes(msgSend); //字符串转为bype数组发送,用到using System.Text;clientSocket.Send(dataSend);Console.ReadKey();clientSocket.Close();}}
}
结果如下。
上述方法是一个同步发送与接收的例子,当服务器处于接收状态时,无法发送数据给客户端,反之亦然。因此需要一种异步的处理方法。
2.2 服务端实现异步接收
在服务器端添加异步接收功能,将之前的代码修改为:
static byte[] dataBuffer = new byte[1024];static void StartAsync(){Socket socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //第一个参数表示时候用ipv4,第二个Stream表示TCP传输用到的数据流,如果是UDP协议可以用Dgram报文//IPAddress xxx.xx.xx.xx IPEndPoint xxx.xx.xx.x:port 需要用到using System.Net;IPAddress ipAddr = IPAddress.Parse("127.0.0.1"); //服务器端申请ip及端口号IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, 1200);socketServer.Bind(ipEndPoint); //进行绑定socketServer.Listen(10); //最多处理10个连接的队列Socket socketClient = socketServer.Accept(); // 接收客户端连接,之后通过socketClient进行对客户端数据的收发//发送给客户端string sendMsg = "hello,客户端";byte[] sendData = Encoding.UTF8.GetBytes(sendMsg); //字符串转为bype数组发送,用到using System.Text;socketClient.Send(sendData);//从客户端接收socketClient.BeginReceive(dataBuffer, 0, 1024, SocketFlags.None, ReceiveCallBack, socketClient); //开始监听客户端数据,当接收到数据时调用RecvCallBack,实现异步接收Console.ReadKey();socketClient.Close();socketServer.Close();}static void ReceiveCallBack(IAsyncResult ar){Socket clientSocket = ar.AsyncState as Socket;int count = clientSocket.EndReceive(ar);string msg = Encoding.UTF8.GetString(dataBuffer, 0, count);Console.WriteLine("接收到的消息为:" + msg);clientSocket.BeginReceive(dataBuffer, 0, 1024, SocketFlags.None, ReceiveCallBack, clientSocket); //接收完一条消息后回掉自身,继续接收}
在客户端发送数据代码前加一个while(true)以达到不断发送数据的目的,结果如下。
2.3 服务端接收多个客户端的异步数据
若要使服务端同时接收多个客户端的数据,服务端实现异步收发需要调用AcceptCallBack
socketServer.BeginAccept(AcceptCallBack, socketServer);
服务端代码如下
static void StartAsyncAcceptAndRecv(){Socket socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //第一个参数表示时候用ipv4,第二个Stream表示TCP传输用到的数据流,如果是UDP协议可以用Dgram报文IPAddress ipAddr = IPAddress.Parse("127.0.0.1"); //服务器端申请ip及端口号IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, 1200);socketServer.Bind(ipEndPoint); //进行绑定socketServer.Listen(10); //最多处理10个连接的队列//Socket socketClient = socketServer.Accept(); // 接收客户端连接,之后通过socketClient进行对客户端数据的收发socketServer.BeginAccept(AcceptCallBack, socketServer);}
客户端不变,此时服务端可以接收多个客户端的数据,如下图所示。
工程源码下载地址:https://download.csdn.net/download/s1314_jhc/10519603(下载分不够可以私聊我发代码)
网络游戏《丛林战争》开发与学习之(一):网络编程的基础知识相关推荐
- Java编程语言学习:Java语言编程的基础知识之Java的变量与数据类型、符号、运算符、数组Array总结之详细攻略
Java编程语言学习:Java语言编程的基础知识之Java的变量与数据类型.符号.运算符.数组Array总结之详细攻略 目录 Java语言编程的基础知识之Java的变量与数据类型.符号.运算符.数组总 ...
- 黑马程序员_java自学学习笔记(八)----网络编程
黑马程序员_java自学学习笔记(八)----网络编程 android培训. java培训.期待与您交流! 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无 ...
- react ui框架_Web开发 React 学习(二十)连载基础篇大结局
系列文章: 测开技能--Web开发 React 学习(一) 测开技能--Web开发 React 学习(二)环境搭建 测开技能--Web开发 React 学习(三)元素的渲染 测开技能--Web开发 R ...
- 学习笔记:Java 并发编程①_基础知识入门
若文章内容或图片失效,请留言反馈. 部分素材来自网络,若不小心影响到您的利益,请联系博主删除. 视频链接:https://www.bilibili.com/video/av81461839 视频下载: ...
- 学习Spring必学的Java基础知识
学习Spring必学的Java基础知识(1)----反射 引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓"登高必自卑,涉远必自迩".以下几项Jav ...
- pwn学习总结(四)—— 堆基础知识(持续更新)
pwn学习总结(四)-- 堆基础知识(持续更新) 前言 chunk 使用中(分配后) 空闲中(释放后) 堆块大小 空间复用 bins fastbin unsorted bin small bin 前言 ...
- 3D视觉学习计划之PCL库的基础知识
3D视觉学习计划之PCL库的基础知识 一.PCL库的概述 PCL是一个大型跨平台开源C++编程库,它在吸收了前人点云相关研究基础上建立起来,实现了大量点云相关的通用算法和高效数据结构,涉及到点云获取. ...
- 从零开始学习VIO笔记 --- 第一讲:基础知识(四元数,李代数)
从零开始学习VIO笔记 --- 第一讲:基础知识(四元数,李代数) 一. 向量的内积与外积 二. 旋转与平移 2.1 旋转表示 --- 旋转矩阵R 2.2 平移向量 2.3 变换矩阵T与齐次坐标 2. ...
- Kotlin学习(一):Kotlin基础知识
Kotlin学习(一):Kotlin基础知识 定义变量常量 在Kotlin中,定义变量时有以下几点与java不同: 位置不同:在 Kotlin 中,数据类型要放到变量后面,并且用冒号(:)分隔,这正好 ...
最新文章
- 使用python爬取教程生成PDF
- php发送指令,PHP发送AT指令实例代码
- linux 关闭磁盘检测,linux下检测磁盘状态
- Java开发知识之Java中的集合上List接口以及子类讲解.
- 安装kinetic之后无法import cv2解决方案
- php签名墙,肺功能检查质量控制网
- HTML5与原生APP之争胜负已出?
- js与php时间戳,js时间戳与日期格式之间的互转
- 网页从数据库读取出现乱码问题
- 台式计算机能装蓝牙吗,台式机如何安装蓝牙
- 运维是技术含量最低的岗位吗?自学应该看书还是看视频?答案都在这里!
- Kyan网络监控设备账号密码泄露漏洞
- excel自动筛选_在Excel 2007中按选择自动筛选
- 2017下半年掘金日报优质文章合集:Android篇,android开发工程师
- 数据结构顺序表和单链表优缺点
- 使用http-server启本地服务
- 【学习笔记】斗鱼p2p架构
- dnspod 动态域名的使用。openwrt使用dnspod动态域名解析。
- 用 TimingLaba(时方校园定时广播系统)软件,实现学校、办公室定时播放体操、上下课(班)铃声、休息音乐
- Latex之给字符上加横线、波浪线、^等