提交 12ce04e5 编写于 作者: xc13262215230's avatar xc13262215230

[#359_websocket握手完成并优化]

上级 2b4e0cf8
......@@ -195,9 +195,10 @@ namespace doyou {
// 分析:http客户端支持长连接,web服务器就建立长链接,不支持就建立短连接。
// web服务器兼容长连接和短连接两种case
char const* str = HeaderGetStr("Connection", "");
if (0 == strcmp("keep-alive", str) ||
0 == strcmp("Keep-Alive", str) ||
0 == strcmp("Upgrade", str)) {
if (0 == strcmp("keep-alive", str) || // http协议
0 == strcmp("Keep-Alive", str) || // http协议
0 == strcmp("Upgrade", str) // websocket协议
) {
_keepAlive = true; // 设置建立长连接标识
}
......
#ifndef _CELL_SERVER_HPP_
#define _CELL_SERVER_HPP_
#include"CELL.hpp"
#include"INetEvent.hpp"
#include"Client.hpp"
#include"Semaphore.hpp"
#include"FDSet.hpp" // 导入头文件
#include<vector>
#include<map>
// [2024-7-12-ing]
#include "CELL.hpp"
#include "INetEvent.hpp"
#include "Client.hpp"
#include "Semaphore.hpp"
#include "FDSet.hpp" // 导入头文件
#include <vector>
#include <map>
namespace doyou {
namespace io { // 增加两层命令空间,避免在其它项目应用时类名出现冲突
......@@ -17,12 +19,12 @@ namespace doyou {
class Server
{
public:
Server()
Server() // 默认无参构造函数
{
_pNetEvent = nullptr; // 推荐采用在属性声明位置一并完成需要的初始化动作
}
virtual ~Server()
virtual ~Server() // 虚析构函数:避免可能的内存泄露
{
CELLLog_Info("Server%d.~Server exit begin", _id);
Close();
......@@ -260,7 +262,7 @@ namespace doyou {
std::vector<Client*> _clientsBuff;
//缓冲队列的锁
std::mutex _mutex;
//网络事件对象
// 网络事件对象
INetEvent* _pNetEvent = nullptr;
//
TaskServer _taskServer;
......
......@@ -21,8 +21,40 @@ namespace doyou {
// 多态:父类指针变量可以指向子类对象
return new HttpClientS(cSock, _nSendBuffSize, _nRecvBuffSize);
}
//
virtual void OnNetMsgHttp(Server* pServer, HttpClientS* pHttpClient) // 由OnNetMsg进行调用
{
}
private:
// 处理网路消息
virtual void OnNetMsg(Server* pServer, Client* pClient, netmsg_DataHeader* header)
{
// 消息计数(子类显示调用继承自父类的同名方法)
TcpServer::OnNetMsg(pServer, pClient, header);
// 收到消息
HttpClientS* pHttpClient = dynamic_cast<HttpClientS*>(pClient); // 将父类指针变量强转为子类指针变量[确保此时父类指针装的是被强转的子类指针对象,否则可能出现访问属性或方法的错误]
if (nullptr == pHttpClient) {
CELLLog_Error("nullptr == pHttpClient");
return;
}
// 解析消息
if (!pHttpClient->GetRequestInfo()) {
CELLLog_Error("get http req info err.");
return;
}
pHttpClient->resetDTHeart(); // 长链接:重置心跳消息计时置零
OnNetMsgHttp(pServer, pHttpClient);
} // to func
};
......
......@@ -1048,9 +1048,15 @@ engine2.0: 构建项目整体的服务端架构,服务端不同模块间,服
websocket服务端收到消息后对其key键值按计算公式加密后,进行数据应答。websocket客户端收到消息后
进行校验,校验通过,即成功建立websocket通信前的握手过程。
【191】websocket协议通信前握手过程是采用http协议消息进行的,握手成功后可进行正常websocket协议
网络消息的通信,而通信过程类似于TCP网络消息原生的数据形式,并进行精简设计。TCP网络消息也有拆包
组包的过程。比如一个TCP网络消息包很大,就会进行拆包,然后发送。
【192】websocket网络消息:
1)数据帧:websocket客户端、服务端通信的最小单位是帧-frame, 由一个或多个帧组成一条完整的
消息-message.
2)发送端:将消息切割成多个帧,并发送给接收端。
3)接收端:接收消息帧,并将关联的帧重新组装成完成的消息。
......
......@@ -12,33 +12,17 @@ using namespace doyou::io; // 命名空间
class MyServer : public TcpHttpServer
{
public:
// 处理网路消息
virtual void OnNetMsg(Server* pServer, Client* pClient, netmsg_DataHeader* header)
//
virtual void OnNetMsgHttp(Server* pServer, HttpClientS* pHttpClient) // 继承父类虚方法并进行函数重写
{
// 收到消息
HttpClientS* pHttpClient = dynamic_cast<HttpClientS*>(pClient); // 将父类指针变量强转为子类指针变量[确保此时父类指针装的是被强转的子类指针对象,否则可能出现访问属性或方法的错误]
if (nullptr == pHttpClient) {
CELLLog_Error("nullptr == pHttpClient");
return;
}
// 解析消息
if (!pHttpClient->GetRequestInfo()) {
CELLLog_Error("get http req info err.");
return;
}
// 消息计数(子类显示调用继承自父类的同名方法)
TcpServer::OnNetMsg(pServer, pClient, header);
// 分析:优化方案,采用map映射方式,key作为调用方法token,val为调用方法的函数地址
// 处理消息
if (pHttpClient->UrlCompare("/add")) { // nginx
if (pHttpClient->UrlCompare("/add")) { // nginx, 上层已经进行指针判空处理
int a = pHttpClient->ArgsGetInt("a", 0);
int b = pHttpClient->ArgsGetInt("b", 0);
int c = a + b;
char respBodyBuff[32] = {0}; // 编程规范:变量在使用前都应该初始化
char respBodyBuff[32] = { 0 }; // 编程规范:变量在使用前都应该初始化
sprintf(respBodyBuff, "a + b = %d", c);
pHttpClient->Resp200OK(respBodyBuff, strlen(respBodyBuff));
......@@ -86,9 +70,10 @@ public:
// web服务器找不到对应项,返回404
pHttpClient->Resp404NotFound();
}
}
} // end if
}
} // end func
// 响应文件-normal
bool RespFile(HttpClientS* pHttpClient)
......
......@@ -15,21 +15,8 @@ class MyServer : public TcpHttpServer
{
public:
// 处理网路消息
virtual void OnNetMsg(Server* pServer, Client* pClient, netmsg_DataHeader* header)
virtual void OnNetMsgHttp(Server* pServer, HttpClientS* pHttpClient)
{
// 收到消息
HttpClientS* pHttpClient = dynamic_cast<HttpClientS*>(pClient); // 将父类指针变量强转为子类指针变量[确保此时父类指针装的是被强转的子类指针对象,否则可能出现访问属性或方法的错误]
if (nullptr == pHttpClient) {
CELLLog_Error("nullptr == pHttpClient");
return;
}
// 解析消息
if (!pHttpClient->GetRequestInfo()) {
CELLLog_Error("get http req info err.");
return;
}
auto strUpgrade = pHttpClient->HeaderGetStr("Upgrade", "");
if (0 != strcmp(strUpgrade, "websocket")) {
CELLLog_Error("not found Upgrade: websocket");
......@@ -45,13 +32,20 @@ public:
std::string sKey = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; // 服务端固定key
sKey = cKey + sKey;
unsigned char p[20];
SHA1_String((const unsigned char*)sKey.c_str(), sKey.length(), p);
unsigned char strSha1[20] = {0}; // 编程建议:变量在使用前应该初始化,以避免可能的错误
SHA1_String((const unsigned char*)sKey.c_str(), sKey.length(), strSha1);
std::string sKeyAccept = Base64Encode(strSha1, 20); // 常量=非常量,反之不行
char resp[256] = { 0 };
strcat(resp, "HTTP/1.1 101 Switching Protocols\r\n");
strcat(resp, "Connection: Upgrade\r\n");
strcat(resp, "Upgrade: websocket\r\n");
strcat(resp, "Sec-WebSocket-Accept: ");
strcat(resp, sKeyAccept.c_str());
strcat(resp, "\r\n\r\n");
pHttpClient->SendData(resp, strlen(resp));
}
......@@ -94,8 +88,8 @@ int main(int argc, char* args[])
// 分析:调试模式读取不到配置文件配置信息, 就采用默认值
const char* wwwroot = Config::Instance().getStr("wwwroot", "./www");
const char* indexpage = Config::Instance().getStr("indexpage", "index.html");
server.SetWwwRoot(wwwroot);
server.SetIndexPage(indexpage);
//server.SetWwwRoot(wwwroot);
//server.SetIndexPage(indexpage);
server.Bind(strIP, nPort);
// 分析:服务器同一时刻能监听的最大客户端数量,可以提高服务器连接客户端的效率
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册