返回顶部
首页 > 资讯 > 前端开发 > JavaScript >CocosCreator通用框架设计之网络
  • 367
分享到

CocosCreator通用框架设计之网络

2024-04-02 19:04:59 367人浏览 八月长安
摘要

目录前言使用websocket构造 websocket 对象websocket 的状态websocket 的 APIwebsocket 的回调Echo 实例 设计框架Pro

前言

在 Cocos Creator 中发起一个 Http 请求是比较简单的,但很多游戏希望能够和服务器之间保持长连接,以便服务端能够主动向客户端推送消息,而非总是由客户端发起请求,对于实时性要求较高的游戏更是如此。这里我们会设计一个通用的网络框架,可以方便地应用于我们的项目中。

使用websocket

在实现这个网络框架之前,我们先了解一下 websocketWEBsocket 是一种基于 tcp 的全双工网络协议,可以让网页创建持久性的连接,进行双向的通讯。在 Cocos Creator 中使用 websocket 既可以用于 H5 网页游戏上,同样支持原生平台 AndroidiOS

构造 websocket 对象

在使用 websocket 时,第一步应该创建一个 websocket 对象。websocket 对象的构造函数可以传入2个参数,第一个是 url 字符串,第二个是协议字符串或字符串数组,指定了可接受的子协议,服务端需要选择其中的一个返回,才会建立连接,但我们一般用不到。

url 参数非常重要,主要分为4部分:协议、地址、端口、资源。

比如 ws://echo.websocket.org:

  • 协议:必选项,默认是 ws 协议,如果需要安全加密则使用 wss。
  • 地址:必选项,可以是 ip 或域名,当然建议使用域名。
  • 端口:可选项,在不指定的情况下,ws 的默认端口为 80,wss 的默认端口为 443。
  • 资源:可选性,一般是跟在域名后某资源路径,我们基本不需要它。

websocket 的状态

websocket 有4个状态,可以通过 readyState 属性查询:

  • 0 CONNECTING 尚未建立连接。
  • 1 OPEN WebSocket连接已建立,可以进行通信。
  • 2 CLOSING 连接正在进行关闭握手,或者该close()方法已被调用。
  • 3 CLOSED 连接已关闭。

websocket 的 API

websocket 只有2个 api,void send( data ) 发送数据和 void close( code, reason ) 关闭连接。

send 方法只接收一个参数——即要发送的数据,类型可以是以下4个类型的任意一种:string | ArrayBufferLike | Blob | ArrayBufferView。

如果要发送的数据是二进制,我们可以通过 websocket 对象的 binaryType 属性来指定二进制的类型,binaryType 只可以被设置为“blob”或“arraybuffer”,默认为“blob”。如果我们要传输的是文件这样较为固定的、用于写入到磁盘的数据,使用 blob。而你希望传输的对象在内存中进行处理则使用较为灵活的 arraybuffer。如果要从其他非 blob 对象和数据构造一个 blob,需要使用 blob 的构造函数。

在发送数据时,官方有2个建议:

  • 检测 websocket 对象的 readyState 是否为 OPEN,是才进行 send。
  • 检测 websocket 对象的 bufferedAmount 是否为0,是才进行 send(为了避免消息堆积,该属性表示调用 send 后堆积在 websocket 缓冲区的还未真正发送出去的数据长度)。

close 方法接收2个可选的参数,code 表示错误码,我们应该传入 1000 或 3000~4999 之间的整数,reason 可以用于表示关闭的原因,长度不可超过 123 字节。

websocket 的回调

websocket 提供了4个回调函数供我们绑定:

  • onopen:连接成功后调用。
  • onmessage:有消息过来时调用:传入的对象有 data 属性,可能是字符串、blob 或 arraybuffer。
  • onerror:出现网络错误时调用:传入的对象有 data 属性,通常是错误描述的字符串。
  • onclose:连接关闭时调用:传入的对象有 code、reason、wasClean 等属性。

注意:当网络出错时,会先调用 onerror 再调用 onclose,无论何种原因的连接关闭,onclose 都会被调用。

Echo 实例

下面 websocket 官网的 echo demo 的代码,可以将其写入一个 html 文件中并用浏览器打开,打开后会自动创建 websocket 连接,在连接上时主动发送了一条消息“WebSocket rocks”,服务器会将该消息返回,触发 onMessage,将信息打印到屏幕上,然后关闭连接。具体可以参考:http://www.websocket.org/echo.html17 

默认的 url 前缀是wss,由于 wss 抽风,使用 ws 才可以连接上,如果 ws 也抽风,可以试试连这个地址ws://121.40.165.18:8800,这是国内的一个免费测试 websocket 的网址。

 设计框架

一个通用的网络框架,在通用的前提下还需要能够支持各种项目的差异需求,根据经验,常见的需求差异如下:

  • 用户协议差异,游戏可能传输 JSON、protobuf、flatbuffer 或者自定义的二进制协议。
  • 底层协议差异,我们可能使用 websocket、或者微信小游戏的 wx.websocket、甚至在原生平台我们希望使用 tcp/udp/kcp 等协议。
  • 登陆认证流程,在使用长连接之前我们理应进行登陆认证,而不同游戏登陆认证的方式不同。
  • 网络异常处理,比如超时时间是多久,超时后的表现是怎样的,请求时是否应该屏蔽 UI 等待服务器响应,网络断开后表现如何,自动重连还是由玩家点击重连按钮进行重连,重连之后是否重发断网期间的消息?等等这些。
  • 多连接的处理,某些游戏可能需要支持多个不同的连接,一般不会超过2个,比如一个主连接负责处理大厅等业务消息,一个战斗连接直接连战斗服务器,或者连接聊天服务器。

根据上面的这些需求,我们对功能模块进行拆分,尽量保证模块的高内聚,低耦合。

ProtocolHelper 协议处理模块——当我们拿到一块 buffer时,我们可能需要知道这个 buffer 对应的协议或者 id 是多少,比如我们在请求的时候就传入了响应的处理回调,那么常用的做法可能会用一个自增的 id 来区别每一个请求,或者是用协议号来区分不同的请求,这些是开发者需要实现的。我们还需要从 buffer 中获取包的长度是多少?包长的合理范围是多少?心跳包长什么样子等等。

Socket 模块——实现最基础的通讯功能,首先定义 Socket 的接口类 ISocket,定义如连接、关闭、数据接收与发送等接口,然后子类继承并实现这些接口。

NetworkTips 网络显示模块——实现如连接中、重连中、加载中、网络断开等状态的显示,以及 UI 的屏蔽。

NetNode 网络节点——所谓网络节点,其实主要的职责是将上面的功能串联起来,为用户提供一个易用的接口。

NetManager 管理网络节点的单例——我们可能有多个网络节点(多条连接),所以这里使用单例来进行管理,使用单例来操作网络节点也会更加方便。

ProtocolHelper

在这里定义了一个 IProtocolHelper 的简单接口,如下所示:


export type NetData = (string | ArrayBufferLike | Blob | ArrayBufferView);// 协议辅助接口
export interface IProtocolHelper
{    
    getHeadlen(): number;                   // 返回包头长度    
    getHearbeat(): NetData;                 // 返回一个心跳包    
    getPackageLen(msg: NetData): number;    // 返回整个包的长度    
    checkPackage(msg: NetData): boolean;    // 检查包数据是否合法    
    getPackageId(msg: NetData): number;     // 返回包的id或协议类型
}

Socket

在这里定义了一个 ISocket 的简单接口,如下所示:


// Socket接口
export interface ISocket {    
    onConnected: (event) => void;                 //连接回调 
    onMessage: (msg: NetData) => void;            // 消息回调    
    onError: (event) => void;                     // 错误回调    
    onClosed: (event) => void;                    // 关闭回调    
    connect(ip: string, port: number);            // 连接接口    
    send(buffer: NetData);                        // 数据发送接口    
    close(code?: number, reason?: string);        // 关闭接口
}

接下来我们实现一个 WebSock,继承于 ISocket,我们只需要实现 connect、send 和 close 接口即可。send 和 close 都是对 websocket 对简单封装,connect 则需要根据传入的 ip、端口等参数构造一个 url 来创建 websocket,并绑定 websocket 的回调。


export class WebSock implements ISocket {    
    private _ws: WebSocket = null;              // websocket对象   
    onConnected: (event) => void = null;    
    onMessage: (msg) => void = null;    
    onError: (event) => void = null;    
    onClosed: (event) => void = null;   
    connect(options: any) {        
    if (this._ws) {            
        if (this._ws.readyState === WebSocket.CONNECTING) {                
            console.log("websocket connecting, wait for a moment...")                
            return false;
        }
    }
    let url = null;        
    if(options.url) {           
        url = options.url;        
    } else {            
        let ip = options.ip;            
        let port = options.port;            
        let protocol = options.protocol;            
        url = `${protocol}://${ip}:${port}`;           
    }        
        this._ws = new WebSocket(url);       
        this._ws.binaryType = options.binaryType ? options.binaryType : "arraybuffer";        
        this._ws.onmessage = (event) => {           
        this.onMessage(event.data);        
    };        
        this._ws.onopen = this.onConnected;        
        this._ws.onerror = this.onError;        
        this._ws.onclose = this.onClosed;       
        return true;    
    }    
    send(buffer: NetData) {        
    if (this._ws.readyState == WebSocket.OPEN)  {           
        this._ws.send(buffer);           
        return true;       
    }       
    return false;    
    }    
    close(code?: number, reason?: string) {        
    this._ws.close();    
    }
}

NetworkTips

INetworkTips 提供了非常的接口,重连和请求的开关,框架会在合适的时机调用它们,我们可以继承 INetworkTips 并定制我们的网络相关提示信息,需要注意的是这些接口可能会被**多次调用**。


// 网络提示接口
export interface INetworkTips {    
    connectTips(isshow: boolean): void;    
    reconnectTips(isShow: boolean): void;    
    requestTips(isShow: boolean): void;
}

NetNode

Netnode 是整个网络框架中最为关键的部分,一个 NetNode 实例表示一个完整的连接对象,基于 NetNode 我们可以方便地进行扩展,它的主要职责有:

连接维护

  • 连接的建立与鉴权(是否鉴权、如何鉴权由用户的回调决定)
  • 断线重连后的数据重发处理
  • 心跳机制确保连接有效(心跳包间隔由配置,心跳包的内容由ProtocolHelper定义)
  • 连接的关闭

数据发送

  • 支持断线重传,超时重传
  • 支持唯一发送(避免同一时间重复发送)

数据接收

  • 支持持续监听
  • 支持request-respone模式

界面展示

  • 可自定义网络延迟、短线重连等状态的表现
  • 首先我们定义了 NetTipsType、NetNodeState 两个枚举,以及 NetConnectOptions 结构供 NetNode 使用。
  • 接下来是 NetNode 的成员变量,NetNode 的变量可以分为以下几类:
  • NetNode 自身的状态变量,如 ISocket 对象、当前状态、连接参数等等。
  • 各种回调,包括连接、断开连接、协议处理、网络提示等回调。
  • 各种定时器,如心跳、重连相关的定时器。
  • 请求列表与监听列表,都是用于接收到的消息处理。

接下来介绍网络相关的成员函数,首先看初始化与:

  • init 方法用于初始化 NetNode,主要是指定 Socket 与协议等处理对象。
  • connect 方法用于连接服务器。
  • initSocket 方法用于绑定 Socket 的回调到 NetNode 中。
  • updateNetTips 方法用于刷新网络提示。

onConnected 方法在网络连接成功后调用,自动进入鉴权流程(如果设置了_connectedCallback),在鉴权完成后需要调用 onChecked 方法使 NetNode 进入可通讯的状态,在未鉴权的情况,我们不应该发送任何业务请求,但登录验证这类请求应该发送给服务器,这类请求可以通过带force参数强制发送给服务器。

接收到任何消息都会触发 onMessage,首先会对数据包进行校验,校验的规则可以在自己的 ProtocolHelper 中实现,如果是一个合法的数据包,我们会将心跳和超时计时器进行更新——重新计时,最后在 _requests 和 _listener 中找到该消息的处理函数,这里是通过 rspCmd 进行查找的,rspCmd 是从 ProtocolHelper 的 getPackageId 取出的,我们可以将协议的命令或者序号返回,由我们自己来决定请求和响应如何对应。

onError 和 onClosed 是网络出错和关闭时调用的,无论是否出错,最终都会调用 onClosed,在这里我们执行断线回调,以及做自动重连的处理。当然也可以调用 close来关闭套接字。close 与 closeSocket 的区别在于 closeSocket 只是关闭套接字——我仍然要使用当前的 NetNode,可能通过下一次 connect 恢复网络。而 close则是清除所有的状态。

发起网络请求有3种方式:

send 方法,纯粹地发送数据,如果当前断网或者验证中会进入 _request 队列。

request 方法,在请求的时候即以闭包的方式传入回调,在该请求的响应回到时会执行回调,如果同时有多个相同的请求,那么这 N 个请求的响应会依次回到客户端,响应回调也会依次执行(每次只会执行一个回调)。

requestUnique 方法,如果我们不希望有多个相同的请求,可以使用 requestUnique 来确保每一种请求同时只会有一个。

这里确保没有重复之所以使用的是遍历 _requests,是因为我们不会积压大量的请求到 _requests中,超时或异常重发也不会导致 _requests 的积压,因为重发的逻辑是由 NetNode 控制的,而且在网络断开的情况下,我们理应屏蔽用户发起请求,此时一般会有一个全屏遮罩——网络出现波动之类的提示。

我们有2种回调,一种是前面的 request 回调,这种回调是临时性的,一般随着请求-响应-执行而立即清理,_listener 回调则是常驻的,需要我们手动管理的,比如打开某界面时监听、离开是关闭,或者在游戏一开始就进行监听。适合处理服务器的主动推送消息。

最后是心跳与超时相关的定时器,我们每隔 _heartTime 会发送一个心跳包,每隔 _receiveTime 检测如果没有收到服务器返回的包,则判断网络断开。

完整代码,大家可以进入源码查看!

NetManager

NetManager 用于管理 NetNode,这是由于我们可能需要支持多个不同的连接对象,所以需要一个 NetManager 专门来管理 NetNode,同时,NetManager 作为一个单例,也可以方便我们调用网络。


export class NetManager {
	private static _instance: NetManager = null;
	protected _channels: {
		[key: number]: NetNode
	} = {};
	public static getInstance(): NetManager {
		if (this._instance == null) {
			this._instance = new NetManager();
		}
		return this._instance;
	} // 添加Node,返回ChannelID    
	public setNetNode(newNode: NetNode, channelId: number = 0) {
		this._channels[channelId] = newNode;
	} // 移除Node    
	public removeNetNode(channelId: number) {
		delete this._channels[channelId];
	} // 调用Node连接    
	public connect(options: NetConnectOptions, channelId: number = 0): boolean {
		if (this._channels[channelId]) {
			return this._channels[channelId].connect(options);
		}
		return false;
	} // 调用Node发送   
	public send(buf: NetData, force: boolean = false, channelId: number = 0): boolean {
		let node = this._channels[channelId];
		if (node) {
			return node.send(buf, force);
		}
		return false;
	} // 发起请求,并在在结果返回时调用指定好的回调函数   
	public request(buf: NetData, rspCmd: number, rspObject: CallbackObject, showTips: boolean = true, force: boolean =
		false, channelId: number = 0) {
		let node = this._channels[channelId];
		if (node) {
			node.request(buf, rspCmd, rspObject, showTips, force);
		}
	} // 同request,但在request之前会先判断队列中是否已有rspCmd,如有重复的则直接返回    
	public requestUnique(buf: NetData, rspCmd: number, rspObject: CallbackObject, showTips: boolean = true, force:
		boolean = false, channelId: number = 0): boolean {
		let node = this._channels[channelId];
		if (node) {
			return node.requestUnique(buf, rspCmd, rspObject, showTips, force);
		}
		return false;
	} // 调用Node关闭  
	public close(code ? : number, reason ? : string, channelId: number = 0) {
		if (this._channels[channelId]) {
			return this._channels[channelId].closeSocket(code, reason);
		}
	}

测试例子

接下来我们用一个简单的例子来演示一下网络框架的基本使用,首先我们需要拼一个简单的界面用于展示,3个按钮(连接、发送、关闭),2个输入框(输入 url、输入要发送的内容),一个文本框(显示从服务器接收到的数据),如下图所示。

该例子连接的是 websocket 官方的 echo.websocket.org 地址,这个服务器会将我们发送给它的所有消息都原样返回给我们。

接下来,实现一个简单的 Component,这里新建了一个 NetExample.ts 文件,做的事情非常简单,在初始化的时候创建 NetNode、绑定默认接收回调,在接收回调中将服务器返回的文本显示到 msgLabel中。接着是连接、发送和关闭几个接口的实现:


// 不关键的代码省略
@ccclassexport
default class NetExample extends cc.Component {
	@property(cc.Label)
	textLabel: cc.Label = null;
	@property(cc.Label)
	urlLabel: cc.Label = null;
	@property(cc.RichText)
	msgLabel: cc.RichText = null;
	private lineCount: number = 0;
	onLoad() {
		let Node = new NetNode();
		Node.init(new WebSock(), new DefStringProtocol());
		Node.setResponeHandler(0, (cmd: number, data: NetData) => {
			if (this.lineCount > 5) {
				let idx = this.msgLabel.string.search("\n");
				this.msgLabel.string = this.msgLabel.string.substr(idx + 1);
			}
			this.msgLabel.string += `${data}\n`;
			++this.lineCount;
		});
		NetManager.getInstance().setNetNode(Node);
	}
	onConnectClick() {
		NetManager.getInstance().connect({
			url: this.urlLabel.string
		});
	}
	onSendClick() {
		NetManager.getInstance().send(this.textLabel.string);
	}
	onDisconnectClick() {
		NetManager.getInstance().close();
	}
}

代码完成后,将其挂载到场景的 canvas 节点下(其他节点也可以),然后将场景中的 Label 和 RichText 拖拽到我们的 NetExample 的属性面板中:

运行效果如下所示:

小结

可以看到,Websocket 的使用很简单,我们在开发的过程中会碰到各种各样的需求和问题,要实现一个好的设计,快速地解决问题。

我们一方面需要对我们使用的技术本身有深入的理解,websocket 的底层协议传输是如何实现的?与 tcp、http 的区别在哪里?基于 websocket 能否使用 udp 进行传输呢?使用 websocket 发送数据是否需要自己对数据流进行分包(websocket 协议保证了包的完整)?数据的发送是否出现了发送缓存的堆积(查看 bufferedAmount)?

另外需要对我们的使用场景及需求本身的理解,对需求的理解越透彻,越能做出好的设计。哪些需求是项目相关的,哪些需求是通用的?通用的需求是必须的还是可选的?不同的变化我们应该封装成类或接口,使用多态的方式来实现呢?还是提供配置?回调绑定?事件通知?

我们需要设计出一个好的框架,来适用于下一个项目,并且在一个一个的项目中优化迭代,这样才能建立深厚的沉淀、提高效率。

以上就是CocosCreator通用框架设计之网络的详细内容,更多关于CocosCreator框架设计之网络的资料请关注编程网其它相关文章!

--结束END--

本文标题: CocosCreator通用框架设计之网络

本文链接: https://lsjlt.com/news/123552.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • CocosCreator通用框架设计之网络
    目录前言使用websocket构造 websocket 对象websocket 的状态websocket 的 APIwebsocket 的回调Echo 实例 设计框架Pro...
    99+
    2024-04-02
  • CocosCreator通用框架设计之资源管理
    目录cocos creator 资源管理存在的问题资源依赖资源使用ResLoader使用ResLoader如果你想使用Cocos Creator制作一些规模稍大的游戏,那么资源管理是...
    99+
    2024-04-02
  • CocosCreator入门教程之网络通信
    网络通信概况 开发一个网络游戏,难免要处理网络通信。有几点问题需要注意: 1.服务端为了快速开发可能前期使用http通信,后面再改成websocket/socket。 2.同时存在h...
    99+
    2024-04-02
  • GameFramework框架详解之 Network网络框架
    前言 目前流行的一些开源的网络框架有很多,我自己也手写过网络相关的模块。但是当我看了GameFramework的网络框架,还是眼前一亮的感觉。他的封装继承体系真的非常值得我们细细去品味,去学习。今天就...
    99+
    2023-10-25
    网络 tcp/ip udp gameframework protobuf
  • 使用CocosCreator怎么实现网络通信
    使用CocosCreator怎么实现网络通信?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。具体实施public constructor(driver: Co...
    99+
    2023-06-14
  • 计算机网络之一:网络架构
    一:七层架构OSI是Open System Interconnect即开放系统互连模型。二:五层架构三:四层架构TCP/IP四层模型四层协议和对应的标准七层协议的关系如下图:四:数据包五:程序是如何工作的...
    99+
    2023-06-03
  • [Android]网络框架之OkHttp(详细)(kotlin)
    目录 OkHttp的介绍 添加依赖 OkHttp的使用 get的同步与异步请求 post的同步与异步请求 POST请求的数据格式 POST请求上传文件 POST请求上传json对象 POST请求上传多个数据 OkHttp的配置 1.Buil...
    99+
    2023-09-10
    android okhttp kotlin
  • Java框架设计之反射怎么应用
    这篇文章主要讲解了“Java框架设计之反射怎么应用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java框架设计之反射怎么应用”吧!框架:半成品软件。可以在框架的基础上进行软件开发,简化编码...
    99+
    2023-07-02
  • 系统架构设计师-计算机网络
    目录 一、计算机网络技术概述         1、网络概述         2、网络有关指标         3、网络分类         4、5G技术 二、组网技术         1、交换技术         2、基本交换原理 三、TC...
    99+
    2023-10-01
    软件工程 系统架构
  • HTML框架的终极指南:解锁网络设计的新高度
    选择合适的框架 在选择HTML框架之前,考虑以下因素: 目标受众:框架是否适合您的目标受众? 技术栈:框架是否与您的技术栈兼容? 学习曲线:框架是否易于学习和使用? 支持和社区:框架有活跃的支持社区和资源吗? 流行的HTML框架 B...
    99+
    2024-04-02
  • learun通用权限系统框架功能实现设计
    Learun快速开发平台是一套基于智能化可扩展组件式的软件系统项目,使用了当前主流的应用开发技术,框架内置工作流、向导式智能开发组件、即时通讯组件、APP开发组件、微信组件、通用权限等一系列组件,以及可扩展...
    99+
    2024-04-02
  • Android 网络请求框架解析之okhttp与okio
    安卓网络请求 先看一下今天的大纲 导入okhttp和okio依赖 禁用掉明文流量请求的检查 添加访问权限 布局及代码实现 运行结果 下面...
    99+
    2024-04-02
  • 网络爬虫框架Scrapy怎么用
    这篇文章将为大家详细讲解有关网络爬虫框架Scrapy怎么用,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。Scrapy是用纯Python实现一个为了爬取网站数据、提取结构性数据而编写的应用框架,用途非常广泛...
    99+
    2023-06-27
  • 基于Java(SpringBoot框架)毕业设计作品成品(40)网络网上个人博客系统设计与实现
    博主介绍:《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者,CSDN博客专家,在线教育专家,CSDN钻石讲师;专注大学生毕业设计教育和辅导。 所有项目都配有从入门到精通的基础知识视频课程,免费 项目配有对应开发文档、开题...
    99+
    2023-10-20
    个人博客系统毕业设计作品 毕设毕业设计 springboot框架
  • 如何使用Scrapy网络爬虫框架
    这篇文章将为大家详细讲解有关如何使用Scrapy网络爬虫框架,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。scrapy 介绍标准介绍Scrapy是一个为了爬取网站数据,提...
    99+
    2024-04-02
  • 如何使用C++网络服务框架
    这篇文章主要讲解了“如何使用C++网络服务框架”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何使用C++网络服务框架”吧!C++  是最重要的编程语言之一。它既可以进行、过程化程...
    99+
    2023-06-15
  • 基于Java(SpringBoot框架)毕业设计作品成品(08)web网页网络在线考试网站系统设计与实现
    博主介绍:《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者,CSDN博客专家,在线教育专家,CSDN钻石讲师;专注大学生毕业设计教育和辅导。 所有项目都配有从入门到精通的基础知识视频课程,免费 项目配有对应开发文档、开题...
    99+
    2023-10-12
    在线考试系统毕业设计 网络考试系统毕设作品 毕设 毕业设计 计算机毕业设计
  • 利用CSS设计一个全面的网页布局框架
    如何运用CSS创建一个完善的网页布局框架 随着互联网的快速发展和普及,网页布局框架的重要性也日益凸显。而CSS(层叠样式表)作为前端开发的基础技术,可以实现网页的美观、灵活和可维护,成为创建一个完善的网页布局框架的重要工具。本文...
    99+
    2024-01-16
    网页布局 CSS布局 网页框架
  • 怎么设计DDoS抵抗力强的网络架构
    设计DDoS抵抗力强的网络架构需要考虑以下几个方面: 分布式架构:将网络资源分布在多个地理位置,避免单点故障。这样即使某个地区受...
    99+
    2024-04-22
    DDoS攻击
  • 使用NIO实现一个Netty网络框架
    使用NIO实现一个Netty网络框架?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。Netty是一个高性能、异步事件驱动的NIO框架,它提供了对TCP、UDP和文件传输的支持,N...
    99+
    2023-05-31
    nio netty
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作