1.C++如何搭建Web服务端(WebSocketpp)
2.nodejs全网首发教程 从零写一个websocket服务器 无任何框架
3.微信小程序中如何使用WebSocket实现长连接(含完整源码)
4.探究webpack代码热更新原理
5.网络使用wireshark抓包 分析websocket协议 以及TCP三次握手(实测)
C++如何搭建Web服务端(WebSocketpp)
C++使用WebSocket++搭建Web服务端的方法及步骤:
WebSocket++是一种C++实现的WebSocket库,具有头文件仅需包含、C++语法支持、多种网络传输模块可选、线程安全、安全性和代理支持等特性。股票趋势公式源码借助它,C++开发者可以轻松集成WebSocket功能到自己的应用中。
为了使用WebSocket++,开发者需先确保环境安装了必要的依赖库,比如Boost和OpenSSL。安装步骤包括下载ActivePerl以执行Perl脚本并配置OpenSSL,以及安装Netwide Assembler (NASM) 用于OpenSSL的汇编编译。ActivePerl和NASM的安装路径应添加到环境变量中,确保OpenSSL和其他工具的正确访问。
具体安装时,检查Perl和NASM是bass 源码 c否已成功安装,并确认其路径正确无误。完成安装后,通过参考相应的`install.win`文件(在OpenSSL下载源目录中),将OpenSSL的头文件和库文件加入到项目工程中。同样,遵循Boost源代码内的`install`文档进行Boost的编译步骤。
在配置VS创建的控制台项目时,引入WebSocketpp的头文件路径至关重要,避免出现找不到头文件路径的警告。例如,可以将`websocketpp`目录添加到项目中,以便正确编译和链接所需库。
将WebSocket++相关的源代码项目进行本地配置,并将其编译成.exe文件。对于编译过程中可能出现的警告(如未分配的值),通常可以忽略,sgwin 源码出售因为它在构建过程中是由于编译器策略所导致的,而不是代码存在问题。
在成功编译并运行项目时,若未见到正常输出,可能原因在于项目的启动方式。默认情况下,WebSocket++可能采用`boost::asio`初始化网络,并监听端口接收数据。为了测试项目功能,可将默认参数更改并测试其反馈。使用浏览器访问相应的URL(如`.0.0.1:`并发送请求),应能查看到数据交换情况。
为了验证WebSocket++发送和接收数据的功能,可以参考特定的示例代码,将其整合至项目中。通过发送不同的修改html源码消息测试服务器的响应,以确定WebSocket++正确地实现消息的传输。
总的来说,WebSocket++为C++开发者提供了一个高效的WebSocket功能实现,简化了开发流程并提高了开发效率。正确地准备环境、配置代码并进行充分测试,有助于确保WebSocket++能在实际应用中稳定运行,实现预期的网络通信功能。
nodejs全网首发教程 从零写一个websocket服务器 无任何框架
nodejs从零搭建websocket服务器教程
这篇文章提供了一个无框架的全网首发教程,作者自信地表示,其行的源码已经具备了基础websocket服务器功能,且在便利性、性能和自定义性上优于主流框架。通过npm直接安装`npm i iiws`,只需注意修改package.json的main字段。源码链接:/Bylx/iiws,大众教育 源码注释为英文。 理解websocket与piler?=?webpack(config);?//?这里的server是全局变量?server?=?new?Server(compiler,?options,?log);?if?(options.socket)?{ ?server.listen(options.socket,?options.host,?(err)?=>?{ })?}?else?{ ?server.listen(options.port,?options.host,?(err)?=>?{ })?}?}深入核心,了解如何通过compiler初始化服务器server对象,并且调用listen方法
//?webpack-dev-server/lib/Server.js?class?Server?{ ?constructor(compiler,?options?=?{ },?_log)?{ ?//?保存webpack实例?this.compiler?=?compiler;?//?保存用户的配置参数?this.options?=?options;?this.heartbeatInterval?=?;?//?socketServer参数?this.socketServerImplementation?=?getSocketServerImplementation(this.options);?this.sockets?=?[];?//?设置文件监听的目录范围?this.contentBaseWatchers?=?[];?//?开启代码热更新的必备参数?this.hot?=?this.options.hot?||?this.options.hotOnly;?//?文件监听配置?this.watchOptions?=?options.watchOptions?||?{ };?this.setupHooks();?this.setupApp();?this.setupDevMiddleware();?this.createServer();?}?//?使用文件编译结束的钩子?setupHooks()?{ ?const?addHooks?=?(compiler)?=>?{ ?done.tap('webpack-dev-server',?(stats)?=>?{ ?//?服务端编译结束通过websocket告知客户端,以及传递当前的hash值和ok?this._sendStats(this.sockets,?this.getStats(stats));?this._stats?=?stats;?})?}?if?(this.compiler.compilers)?{ ?this.compiler.compilers.forEach(addHooks);?}?else?{ ?addHooks(this.compiler);?}?}?_sendStats(sockets,?stats,?force)?{ ?this.sockWrite(sockets,?'hash',?stats.hash);?this.sockWrite(sockets,?'ok');?}?//?利用express初始化一个服务器,用于静态资源的路由?setupApp()?{ ?this.app?=?new?express();?}?//?配置express搭建后的服务器,确认使用的协议?createServer()?{ ?//?如果使用的协议是piler,?Object.assign({ },?this.options,?{ ?logLevel:?this.log.options.level?})?)?}//?创建websocket服务器,用于下发模块更新的通知到客户端?createSocketServer()?{ ?const?SocketServerImplementation?=?this.socketServerImplementation;?this.socketServer?=?new?SocketServerImplementation(this);?this.socketServer.onConnection((connection,?headers)?=>?{ })?}?//?监听对应的端口开启静态资源路由,同时部署另一个websocket服务器?listen(port,?hostname,?fn)?{ ?return?this.listeningApp.listen(port,?hostname,?(err)?=>?{ ?this.createSocketServer();?}?}?}?//?添加两个打包入口模块,利用webpack将相关代码注入到bundle.js中,用于客户端开启websokct以及处理热模块替换?Server.addDevServerEntrypoints?=?require('./utils/addEntries');?module.exports?=?Server;到这里webpack的HMR在node层做的处理基本完成了,这部分同样是让服务端拥有静态资源路由以及主动下发代码更新通知到客户端的能力,下面看一下如何实现客户端接收websocket通知后主动拉取更新后的服务端代码,并且替换执行新的模块代码
webpack客户端的代码肯定不会让开发人员自己去实现,不然就会出现千奇百怪的问题。这部分代码处理被黑盒处理,隐藏在了Server.addDevServerEntrypoints方法内,悄悄得在webpack带包过程中添加entry注入这部分代码处理
巧妙地划分客户端能力到两个模块中
//?webpack-dev-server/utils/addEntries.js?function?addEntries(config,?options,?server)?{ ?const?domain?=?createDomain(options,?app);?const?sockHost?=?options.sockHost`&sockHost=${ options.sockHost}`?:?'';?const?sockPath?=?options.sockPath`&sockPath=${ options.sockPath}`?:?'';?const?sockPort?=?options.sockPort`&sockPort=${ options.sockPort}`?:?'';?//?引入搭建websocket客户端代码块module?const?clientEntry?=?`${ require.resolve(?'../../client/'?)}?${ domain}${ sockHost}${ sockPath}${ sockPort}`;?//?处理客户端从服务端获取新模块并且替换执行的代码块module?let?hotEntry;?if?(options.hotOnly)?{ ?hotEntry?=?require.resolve('webpack/hot/only-dev-server');?}?else?if?(options.hot)?{ ?hotEntry?=?require.resolve('webpack/hot/dev-server');?}?}?module.exports?=?addEntries;从这里可以看出来,客户端需要的两个能力被划分到了两个代码模块中,一个是搭建websocket客户端,一个是处理客户端的代码模块更新和替换
搭建websocket客户端
//?webpack-dev-server/client/index.js?var?socket?=?require('./socket');?var?sendMessage?=?require('./utils/sendMessage');?var?createSocketUrl?=?require('./utils/createSocketUrl');?var?reloadApp?=?require('./utils/reloadApp');?var?socketUrl?=?createSocketUrl(__resourceQuery);?var?onSocketMessage?=?{ ?//?接收websocket服务端返回的最新hash值?hash:?function?hash(_hash)?{ ?status.currentHash?=?_hash;?}?ok:?function?ok()?{ ?sendMessage('Ok');?reloadApp(options,?status);?}?}?socket(socketUrl,?onSocketMessage);当客户端收到服务端返回的ok消息推送时,会调用reloadApp,这里看一下具体是怎么处理的
//?webpack-dev-server/client/utils/reloadApp.js?function?reloadApp(_ref,?_ref2)?{ ?if?(hot)?{ ?log.info('[WDS]?App?hot?update...');?var?hotEmitter?=?require('webpack/hot/emitter');?hotEmitter.emit('webpackHotUpdate',?currentHash);?//?如果当前宿主是浏览器环境,则触发webpackHotUpdate消息推送?if?(typeof?self?!==?'undefined'?&&?self.window)?{ ?self.postMessage("webpackHotUpdate".concat(currentHash),?'*');?}?}?}?module.exports?=?reloadApp;所以调用this.postMessage("webpackHotUpdate".concat(currentHash),'*')
有发送就会有接收,找一下对应的回调处理,而处理这部分的代码被划分到了hot模块中,根据hash获取新的代码模块并进行替换执行
处理客户端的代码模块更新和替换
//?webpack/hot/dev-server.js?if?(module.hot)?{ ?var?lastHash;?var?check?=?function?check()?{ ?module.hot?.check(true)?.then(function(updatedModules)?{ ?//?容错,如果不存在待更新的模块,直接刷新页面?if?(!updatedModules)?{ ?log("warning",?"[HMR]?Cannot?find?update.?Need?to?do?a?full?reload!");?log(?"warning",?"[HMR]?(Probably?because?of?restarting?the?webpack-dev-server)"?);?window.location.reload();?return;?}?}?.catch(function(err)?{ ?window.location.reload();?}?}?hotEmitter.on("webpackHotUpdate",?function(currentHash)?{ ?lastHash?=?currentHash;?if?(!upToDate()?&&?module.hot.status()?===?"idle")?{ ?log("info",?"[HMR]?Checking?for?updates?on?the?server...");?//?调用check方法拉取更新后的模块代码并进行处理?check();?}?});?}这里的module.hot.check方法,其实是另一位隐藏的大佬进行的方法注入
HotModuleReplacementPlugin
由于涉及到另一个插件的解析,放到后面去扩展。感兴趣的读者可以去webpack/lib/hotModuleReplacement.js阅读源码。
这里重点介绍针对module.hot.check都注入了怎样的代码
//?webpack/lib/web/JsonpMainTemplate.runtime.jsfunction?hotCreateModule(moduleId)?{ ?var?hot?=?{ ?check:?hotCheck?}function?hotCheck(apply)?{ ?hotSetStatus("check");?return?hotDownloadManifest(hotRequestTimeout).then(function(update)?{ ?hotAvailableFilesMap?=?update.c;?hotUpdateNewHash?=?update.h;?hotSetStatus("prepare");})?}?function?hotDownloadManifest(requestTimeout)?{ ?requestTimeout?=?requestTimeout?||?;?return?new?Promise(function(resolve,?reject)?{ ?var?request?=?new?XMLHttpRequest();?var?requestPath?=?__webpack_require__.p?+?""?+?hotCurrentHash?+?".hot-update.json";?request.open("GET",?requestPath,?true);?request.timeout?=?requestTimeout;?request.send(null);?request.onreadystatechange?=?function()?{ ?var?update?=?JSON.parse(request.responseText);?resolve(update);?}?}?}这里之所以使用JSONP的方式获取新的模块代码,是因为JSONP获取的代码可以直接执行,而hash.hot-update.js代码里有个webpackHotUpdate函数调用,最后重点看一下这个函数是如何处理代码模块替换和执行的
//?webpack/lib/HotModuleReplacement.runtime.js?window["webpackHotUpdate"]?=?function?(chunkId,?moreModules)?{ ?hotAddUpdateChunk(chunkId,?moreModules);?};?function?hotAddUpdateChunk(chunkId,?moreModules)?{ ?//?更新的模块moreModules赋值给全局全量hotUpdate?for?(var?moduleId?in?moreModules)?{ ?if?(Object.prototype.hasOwnProperty.call(moreModules,?moduleId))?{ ?hotUpdate[moduleId]?=?moreModules[moduleId];?}?}?//?调网络使用wireshark抓包 分析websocket协议 以及TCP三次握手(实测)
深入理解网络通信,光是理论研究或阅读源码难以获得直观感受。借助抓包工具Wireshark进行实际数据抓取分析,能更直观地理解协议细节,尤其是WebSocket和TCP三次握手。
Wireshark是一款功能强大的网络封包分析工具,广泛应用于网络协议分析与调试。作为开源软件,其源码可在GitHub上获取,对深入研究Wireshark内部机制大有裨益。对于Wireshark的使用方法,可参阅其官方文档。
WebSocket的通信基础是帧(frame),单个帧构成完整消息。WebSocket数据帧格式遵循RFC标准,由FIN、操作码(Opcode)等字段组成,操作码决定后续数据载荷的解析方式。
在建立WebSocket连接过程中,通过TCP三次握手完成。Wireshark能够实时抓取连接建立过程中的数据包。
具体操作步骤如下:
1. 使用Wireshark选择网络适配器并过滤IP地址。
2. 打开浏览器访问HTML页面。
3. 保持连接状态秒钟。
4. 关闭浏览器。
抓包数据示例:
1-3步:TCP三次握手过程
1. A主机发送SYN(Seq=0),表示连接请求。
2. B主机响应ACK(Seq=1),同时发送SYN(Seq=0),表示接收请求并准备建立连接。
3. A主机回应ACK(Seq=1),同时发送SYN(Seq=1),完成三次握手。
随后,A主机发送HTTP协议信息,表明请求升级至WebSocket协议。
紧接着,B主机通过ACK应答确认,发送HTTP协议信息表示同意升级,并成功切换。
接下来,A主机进行ACK应答,B主机发出准备发送数据的请求,包含“PSH”标识。
A主机再次进行ACK应答,B主机发送WebSocket协议数据。
分析此过程与WebSocket帧格式对照,发现:
当前帧的FIN标记为1,指示此帧为消息末尾。
操作码值为2,表示二进制格式。
帧无掩码,数据长度为字节,数据部分由用户自定义。
通过Wireshark抓取的实际数据,能清晰地了解WebSocket和TCP三次握手的交互过程,直观展示协议的执行细节与数据结构。