提交 2b4e0cf8 编写于 作者: xc13262215230's avatar xc13262215230

[cs358_创建websocket工程]

上级 f5d301c1
...@@ -355,7 +355,7 @@ namespace doyou { ...@@ -355,7 +355,7 @@ namespace doyou {
WriteResponse("404 Not Found", "(^o^): 404!", 11); WriteResponse("404 Not Found", "(^o^): 404!", 11);
} }
// // 数据应答-OK
void Resp200OK(const char* bodyBuff, int bodyLen) void Resp200OK(const char* bodyBuff, int bodyLen)
{ {
WriteResponse("200 OK", bodyBuff, bodyLen); WriteResponse("200 OK", bodyBuff, bodyLen);
......
#ifndef _CELL_SELECT_SERVER_HPP_ #ifndef _CELL_SELECT_SERVER_HPP_
#define _CELL_SELECT_SERVER_HPP_ #define _CELL_SELECT_SERVER_HPP_
#include"Server.hpp" // [2024-7-4-ok]
#include "Server.hpp"
#include <vector> // 重复包含没有关系,因为存在宏校验,尽量避免重复包含相同头文件 #include <vector> // 重复包含没有关系,因为存在宏校验,尽量避免重复包含相同头文件
...@@ -15,7 +16,7 @@ namespace doyou { ...@@ -15,7 +16,7 @@ namespace doyou {
class SelectServer : public Server class SelectServer : public Server
{ {
public: public:
// 在释放子类对象时,就先自己关闭onrun执行线程,就不会出现onrun线程在当前对象析构后还来调用当前类对象的方法了(会直接出错) // 分析:在释放子类对象时,就先自己关闭onrun执行线程,就不会出现onrun线程在当前对象析构后还来调用当前类对象的方法了(会直接出错),对象已析构,再调用对象方法或属性会直接导致程序报错。
~SelectServer() ~SelectServer()
{ {
Close(); // 调用之后会关闭onrun函数所在执行线程 Close(); // 调用之后会关闭onrun函数所在执行线程
...@@ -74,11 +75,12 @@ namespace doyou { ...@@ -74,11 +75,12 @@ namespace doyou {
} }
} }
///nfds 是一个整数值 是指fd_set集合中所有描述符(socket)的范围,而不是数量 /// nfds 是一个整数值 是指fd_set集合中所有描述符(socket)的范围,而不是数量
///既是所有文件描述符最大值+1 在Windows中这个参数可以写0 /// 既是所有文件描述符最大值+1 在Windows中这个参数可以写0
timeval t{ 0, 1 }; // 结构体初始化方式 timeval t{ 0, 1 }; // 结构体初始化方式
int ret = 0; int ret = 0;
// 可写入集合校验,在无数据可写的时候可写入集合为空,阻塞会生效,可以节省系统资源开销 // 可写入集合校验,在无数据可写的时候可写入集合为空,阻塞会生效,可以节省系统资源开销
// 分析:采用select网络通信模型非阻塞模式,有事件函数立刻执行结束,没有事件阻塞到指定时间后,函数执行返回,不会一直阻塞在此行
if (bNeedWrite) if (bNeedWrite)
{ {
ret = select(_maxSock + 1, _fdRead.fdset(), _fdWrite.fdset(), nullptr, &t); ret = select(_maxSock + 1, _fdRead.fdset(), _fdWrite.fdset(), nullptr, &t);
...@@ -100,8 +102,10 @@ namespace doyou { ...@@ -100,8 +102,10 @@ namespace doyou {
{ {
return true; return true;
} }
ReadData(); ReadData();
WriteData(); WriteData();
return true; return true;
} }
......
...@@ -46,7 +46,7 @@ namespace doyou { ...@@ -46,7 +46,7 @@ namespace doyou {
_pNetEvent = event; _pNetEvent = event;
} }
//关闭Socket // 关闭Socket
void Close() void Close()
{ {
CELLLog_Info("Server%d.Close begin", _id); CELLLog_Info("Server%d.Close begin", _id);
...@@ -199,10 +199,11 @@ namespace doyou { ...@@ -199,10 +199,11 @@ namespace doyou {
void addClient(Client* pClient) void addClient(Client* pClient)
{ {
// 分析:采用自解锁可以避免出现死锁情况
std::lock_guard<std::mutex> lock(_mutex); std::lock_guard<std::mutex> lock(_mutex);
//_mutex.lock(); // _mutex.lock();
_clientsBuff.push_back(pClient); _clientsBuff.push_back(pClient);
//_mutex.unlock(); // _mutex.unlock();
} }
void Start() void Start()
...@@ -271,7 +272,7 @@ namespace doyou { ...@@ -271,7 +272,7 @@ namespace doyou {
protected: protected:
// //
int _id = -1; int _id = -1;
//客户列表是否有变化 // 客户列表是否有变化
bool _clients_change = true; bool _clients_change = true;
......
#ifndef _DOYOU_IO_TCP_HTTP_SERVER_HPP_ #ifndef _DOYOU_IO_TCP_HTTP_SERVER_HPP_
#define _DOYOU_IO_TCP_HTTP_SERVER_HPP_ #define _DOYOU_IO_TCP_HTTP_SERVER_HPP_
// [2024-6-30-ok]
// 分析:文件包含顺序不对会导致编译错误。 // 分析:文件包含顺序不对会导致编译错误。
// 需要,先包含[TcpServerMgr.hpp], 再包含[HttpClient.hpp], 反之编译报错。 // 需要,先包含[TcpServerMgr.hpp], 再包含[HttpClient.hpp], 反之编译报错。
// 原因,文件[TcpServerMgr.hpp]定义宏[CELL_USE_IOCP], 文件[HttpClient.hpp]使用宏[CELL_USE_IOCP]。 // 原因,文件[TcpServerMgr.hpp]定义宏[CELL_USE_IOCP], 文件[HttpClient.hpp]使用宏[CELL_USE_IOCP]。
...@@ -10,7 +11,7 @@ ...@@ -10,7 +11,7 @@
namespace doyou { namespace doyou {
namespace io { namespace io {
// 可使用服务模型(三选一):1-TcpSelectServer 2-TcpEpollServer 3-TcpIocpServer // 可使用服务模型(三选一):1-TcpSelectServer 2-TcpEpollServer 3-TcpIocpServer
class TcpHttpServer : public TcpServerMgr // 根据不同操作系统自动选择最佳网络通信模型 class TcpHttpServer : public TcpServerMgr // 根据不同操作系统自动选择最佳网络通信模型
{ {
public: public:
......
#ifndef _EasySelectServer_hpp_ #ifndef _EasySelectServer_hpp_
#define _EasySelectServer_hpp_ #define _EasySelectServer_hpp_
// [2024-6-30-ok]
#include "TcpServer.hpp" #include "TcpServer.hpp"
#include "SelectServer.hpp" #include "SelectServer.hpp"
...@@ -38,7 +39,7 @@ namespace doyou { ...@@ -38,7 +39,7 @@ namespace doyou {
/// nfds 是一个整数值 是指fd_set集合中所有描述符(socket)的范围,而不是数量 /// nfds 是一个整数值 是指fd_set集合中所有描述符(socket)的范围,而不是数量
/// para1-既是所有文件描述符最大值+1 在Windows中这个参数可以写0 /// para1-既是所有文件描述符最大值+1 在Windows中这个参数可以写0
timeval t = { 0, 1 }; timeval t = { 0, 1 };
int ret = select(Sockfd() + 1, fdRead.fdset(), 0, 0, &t); // int ret = select(Sockfd() + 1, fdRead.fdset(), 0, 0, &t); // no block model
if (ret < 0) if (ret < 0)
{ {
if (errno == EINTR) { // 处理可能出现的系统终端导致的程序终止 if (errno == EINTR) { // 处理可能出现的系统终端导致的程序终止
......
#ifndef _EasyTcpServer_hpp_ #ifndef _EasyTcpServer_hpp_
#define _EasyTcpServer_hpp_ #define _EasyTcpServer_hpp_
#include"CELL.hpp" // [2024-7-4-ok]
#include"Client.hpp" #include "CELL.hpp"
#include"Server.hpp" #include "Client.hpp"
#include"INetEvent.hpp" #include "Server.hpp"
#include"NetWork.hpp" #include "INetEvent.hpp"
#include"Config.hpp" #include "NetWork.hpp"
#include "Config.hpp"
// 分析:项目中不必要的头文件不要包含进来,会增大可执行文件大小 // 分析:项目中不必要的头文件不要包含进来,会增大可执行文件大小
//#include"FDSet.hpp" // 封装的fd_set集合 //#include "FDSet.hpp" // 封装的fd_set集合
#include<thread> #include <thread>
#include<mutex> #include <mutex>
#include<atomic> #include <atomic>
namespace doyou { namespace doyou {
namespace io { // 增加两层命令空间,避免在其它项目应用时类名出现冲突 namespace io { // 增加两层命令空间,避免在其它项目应用时类名出现冲突
...@@ -25,7 +26,7 @@ namespace doyou { ...@@ -25,7 +26,7 @@ namespace doyou {
// //
Thread _thread; Thread _thread;
// 消息处理对象,内部会创建线程 // 消息处理对象,内部会创建线程
std::vector<Server*> _cellServers; std::vector<Server*> _cellServers; // 动态数组数据类型为指针,避免栈爆炸
// 每秒消息计时 // 每秒消息计时
Timestamp _tTime; Timestamp _tTime;
// 服务端套接字,功能:接收新的客户端加入 // 服务端套接字,功能:接收新的客户端加入
...@@ -61,10 +62,12 @@ namespace doyou { ...@@ -61,10 +62,12 @@ namespace doyou {
_nRecvBuffSize = Config::Instance().getInt("nRecvBuffSize", RECV_BUFF_SZIE); _nRecvBuffSize = Config::Instance().getInt("nRecvBuffSize", RECV_BUFF_SZIE);
_nMaxClient = Config::Instance().getInt("nMaxClient", FD_SETSIZE); _nMaxClient = Config::Instance().getInt("nMaxClient", FD_SETSIZE);
} }
virtual ~TcpServer()
virtual ~TcpServer() // 虚析构函数作用:避免可能出现的内存泄露
{ {
Close(); Close();
} }
// 初始化Socket(服务端程序) // 初始化Socket(服务端程序)
SOCKET InitSocket(int af = AF_INET) // 参数默认值-IPV4 SOCKET InitSocket(int af = AF_INET) // 参数默认值-IPV4
{ {
...@@ -86,6 +89,7 @@ namespace doyou { ...@@ -86,6 +89,7 @@ namespace doyou {
NetWork::make_reuseaddr(_sock); // 暂时注释,测试打印错误信息 NetWork::make_reuseaddr(_sock); // 暂时注释,测试打印错误信息
CELLLog_Info("create socket<%d> success...", (int)_sock); CELLLog_Info("create socket<%d> success...", (int)_sock);
} }
return _sock; return _sock;
} }
...@@ -100,7 +104,7 @@ namespace doyou { ...@@ -100,7 +104,7 @@ namespace doyou {
sin.sin_port = htons(port); // host to net unsigned short sin.sin_port = htons(port); // host to net unsigned short
#ifdef _WIN32 // 采用宏来区分window和linux系统 #ifdef _WIN32 // 采用宏来区分window和linux系统
if (ip){ if (ip) {
sin.sin_addr.S_un.S_addr = inet_addr(ip); sin.sin_addr.S_un.S_addr = inet_addr(ip);
} }
else { else {
...@@ -147,7 +151,7 @@ namespace doyou { ...@@ -147,7 +151,7 @@ namespace doyou {
return ret; return ret;
} }
//监听端口号 // 监听端口号
int Listen(int n) int Listen(int n)
{ {
// 3 listen 监听网络端口 // 3 listen 监听网络端口
...@@ -159,6 +163,7 @@ namespace doyou { ...@@ -159,6 +163,7 @@ namespace doyou {
else { else {
CELLLog_Info("listen port<%d> success...", _sock); CELLLog_Info("listen port<%d> success...", _sock);
} }
return ret; return ret;
} }
...@@ -266,14 +271,14 @@ namespace doyou { ...@@ -266,14 +271,14 @@ namespace doyou {
} }
// 创建client对象 // 创建client对象
virtual Client* MakeClientObj(SOCKET cSock) // 虚方法方便子类进行函数重写 virtual Client* MakeClientObj(SOCKET cSock) // 虚方法方便子类进行函数重写,虚方法可实现多态
{ {
return new Client(cSock, _nSendBuffSize, _nRecvBuffSize); return new Client(cSock, _nSendBuffSize, _nRecvBuffSize);
} }
void addClientToCELLServer(Client* pClient) void addClientToCELLServer(Client* pClient)
{ {
//查找客户数量最少的Server消息处理对象 // 查找客户数量最少的Server消息处理对象
auto pMinServer = _cellServers[0]; auto pMinServer = _cellServers[0];
for (auto pServer : _cellServers) for (auto pServer : _cellServers)
{ {
...@@ -282,10 +287,11 @@ namespace doyou { ...@@ -282,10 +287,11 @@ namespace doyou {
pMinServer = pServer; pMinServer = pServer;
} }
} }
pMinServer->addClient(pClient); pMinServer->addClient(pClient);
} }
// 函数模:区分使用SelectServer和EpollServer // 函数模:区分使用SelectServer和EpollServer
template<class ServerT> template<class ServerT>
void Start(int nCELLServer) void Start(int nCELLServer)
{ {
...@@ -296,9 +302,9 @@ namespace doyou { ...@@ -296,9 +302,9 @@ namespace doyou {
ser->SetClientNum(_nMaxClient / nCELLServer + 1); // +1兼容没整除存在余数的场景 ser->SetClientNum(_nMaxClient / nCELLServer + 1); // +1兼容没整除存在余数的场景
_cellServers.push_back(ser); _cellServers.push_back(ser);
//注册网络事件接受对象 // 注册网络事件接受对象
ser->setEventObj(this); ser->setEventObj(this);
//启动消息处理线程 // 启动消息处理线程
ser->Start(); ser->Start();
} }
_thread.Start(nullptr, _thread.Start(nullptr,
...@@ -307,7 +313,7 @@ namespace doyou { ...@@ -307,7 +313,7 @@ namespace doyou {
}); });
} }
//关闭Socket // 关闭Socket
void Close() void Close()
{ {
CELLLog_Info("TcpServer.Close begin"); CELLLog_Info("TcpServer.Close begin");
...@@ -316,8 +322,10 @@ namespace doyou { ...@@ -316,8 +322,10 @@ namespace doyou {
{ {
for (auto s : _cellServers) for (auto s : _cellServers)
{ {
delete s; delete s; // new/delete配套使用,释放内存
s = nullptr; // 避免出现野指针
} }
_cellServers.clear(); _cellServers.clear();
NetWork::destroy_socket(_sock); NetWork::destroy_socket(_sock);
_sock = INVALID_SOCKET; _sock = INVALID_SOCKET;
......
#ifndef _EasyServerMgr_hpp_ #ifndef _EasyServerMgr_hpp_
#define _EasyServerMgr_hpp_ #define _EasyServerMgr_hpp_
// [2024-6-30-ok]
// 在不同操作系统下面选择最佳网络通信模型 // 在不同操作系统下面选择最佳网络通信模型
#if _WIN32 // windows系统下面会定义此宏 #if _WIN32 // windows系统下面会定义此宏
#include "TcpIocpServer.hpp" // using iocp, only windows. #include "TcpIocpServer.hpp" // using iocp, only windows.
......
...@@ -41,7 +41,7 @@ namespace doyou { ...@@ -41,7 +41,7 @@ namespace doyou {
} }
} }
//关闭线程 // 关闭线程
void Close() void Close()
{ {
std::lock_guard<std::mutex> lock(_mutex); std::lock_guard<std::mutex> lock(_mutex);
......
...@@ -30,7 +30,7 @@ namespace doyou { ...@@ -30,7 +30,7 @@ namespace doyou {
~Timestamp() ~Timestamp()
{} {}
void update() void update()
{ {
//QueryPerformanceCounter(&_startCount); //QueryPerformanceCounter(&_startCount);
_begin = high_resolution_clock::now(); _begin = high_resolution_clock::now();
......
#ifndef _BASE64_H
#define _BASE64_H
#include <string>
namespace doyou {
namespace io {
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool IsBase64(unsigned char c) {
return (isalnum(c) || (c == '+') || (c == '/'));
}
std::string Base64Encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
std::string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
while (in_len--) {
char_array_3[i++] = *(bytes_to_encode++);
if (3 == i) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (i = 0; (i < 4); i++)
ret += base64_chars[char_array_4[i]];
i = 0;
}
}
if (i) {
for (j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++)
ret += base64_chars[char_array_4[j]];
while ((i++ < 3))
ret += '=';
}
return ret;
}
std::string Base64Decode(std::string const& encoded_string) {
std::size_t in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string ret;
while (in_len-- && (encoded_string[in_] != '=') && IsBase64(encoded_string[in_])) {
char_array_4[i++] = encoded_string[in_]; in_++;
if (4 == i) {
for (i = 0; i < 4; i++)
char_array_4[i] = base64_chars.find(char_array_4[i]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++)
ret += char_array_3[i];
i = 0;
}
}
if (i) {
for (j = i; j < 4; j++)
char_array_4[j] = 0;
for (j = 0; j < 4; j++)
char_array_4[j] = base64_chars.find(char_array_4[j]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
}
return ret;
}
}
}
#endif //#define _BASE64_H
/*
Copyright (c) 2006-2017 by Jakob Schröter <js@camaya.net>
This file is part of the gloox library. http://camaya.net/gloox
This software is distributed under a license. The full license
agreement can be found in the file LICENSE in this distribution.
This software may not be copied, modified, sold or distributed
other than expressed in the named license agreement.
This software is distributed without any warranty.
*/
#ifndef SHA_H__
#define SHA_H__
#include <string>
namespace gloox
{
/**
* @brief An implementation of SHA1.
*
* @author Jakob Schröter <js@camaya.net>
* @since 0.9
*/
class SHA
{
public:
/**
* Constructs a new SHA object.
*/
SHA();
/**
* Virtual Destructor.
*/
virtual ~SHA();
/**
* Resets the internal state.
*/
void reset();
/**
* Finalizes the hash computation.
*/
void finalize();
/**
* Returns the message digest in hex notation. Finalizes the hash if finalize()
* has not been called before.
* @return The message digest.
*/
const std::string hex();
/**
* Returns the raw binary message digest. Finalizes the hash if finalize()
* has not been called before.
* @return The message raw binary digest.
*/
const std::string binary();
/**
* Provide input to SHA1.
* @param data The data to compute the digest of.
* @param length The size of the data in bytes.
*/
void feed(const unsigned char* data, unsigned length);
/**
* Provide input to SHA1.
* @param data The data to compute the digest of.
*/
void feed(const std::string& data);
private:
void process();
void pad();
inline unsigned shift(int bits, unsigned word);
void init();
unsigned H[5];
unsigned Length_Low;
unsigned Length_High;
unsigned char Message_Block[64];
int Message_Block_Index;
bool m_finished;
bool m_corrupted;
};
}
/*
Copyright (c) 2006-2017 by Jakob Schröter <js@camaya.net>
This file is part of the gloox library. http://camaya.net/gloox
This software is distributed under a license. The full license
agreement can be found in the file LICENSE in this distribution.
This software may not be copied, modified, sold or distributed
other than expressed in the named license agreement.
This software is distributed without any warranty.
*/
#include <cstdio>
namespace gloox
{
SHA::SHA()
{
init();
}
SHA::~SHA()
{
}
void SHA::init()
{
Length_Low = 0;
Length_High = 0;
Message_Block_Index = 0;
H[0] = 0x67452301;
H[1] = 0xEFCDAB89;
H[2] = 0x98BADCFE;
H[3] = 0x10325476;
H[4] = 0xC3D2E1F0;
m_finished = false;
m_corrupted = false;
}
void SHA::reset()
{
init();
}
const std::string SHA::hex()
{
if (m_corrupted)
return "";
if (!m_finished)
finalize();
char buf[41];
for (int i = 0; i < 20; ++i)
sprintf(buf + i * 2, "%02x", static_cast<unsigned char>(H[i >> 2] >> ((3 - (i & 3)) << 3)));
return std::string(buf, 40);
}
const std::string SHA::binary()
{
if (!m_finished)
finalize();
unsigned char digest[20];
for (int i = 0; i < 20; ++i)
digest[i] = static_cast<unsigned char>(H[i >> 2] >> ((3 - (i & 3)) << 3));
return std::string(reinterpret_cast<char*>(digest), 20);
}
void SHA::finalize()
{
if (!m_finished)
{
pad();
m_finished = true;
}
}
void SHA::feed(const unsigned char* data, unsigned length)
{
if (!length)
return;
if (m_finished || m_corrupted)
{
m_corrupted = true;
return;
}
while (length-- && !m_corrupted)
{
Message_Block[Message_Block_Index++] = (*data & 0xFF);
Length_Low += 8;
Length_Low &= 0xFFFFFFFF;
if (Length_Low == 0)
{
Length_High++;
Length_High &= 0xFFFFFFFF;
if (Length_High == 0)
{
m_corrupted = true;
}
}
if (Message_Block_Index == 64)
{
process();
}
++data;
}
}
void SHA::feed(const std::string& data)
{
feed(reinterpret_cast<const unsigned char*>(data.c_str()), static_cast<int>(data.length()));
}
void SHA::process()
{
const unsigned K[] = { 0x5A827999,
0x6ED9EBA1,
0x8F1BBCDC,
0xCA62C1D6
};
int t;
unsigned temp;
unsigned W[80];
unsigned A, B, C, D, E;
for (t = 0; t < 16; t++)
{
W[t] = static_cast<unsigned int>(Message_Block[t * 4]) << 24;
W[t] |= static_cast<unsigned int>(Message_Block[t * 4 + 1]) << 16;
W[t] |= static_cast<unsigned int>(Message_Block[t * 4 + 2]) << 8;
W[t] |= static_cast<unsigned int>(Message_Block[t * 4 + 3]);
}
for (t = 16; t < 80; ++t)
{
W[t] = shift(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]);
}
A = H[0];
B = H[1];
C = H[2];
D = H[3];
E = H[4];
for (t = 0; t < 20; ++t)
{
temp = shift(5, A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = shift(30, B);
B = A;
A = temp;
}
for (t = 20; t < 40; ++t)
{
temp = shift(5, A) + (B ^ C ^ D) + E + W[t] + K[1];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = shift(30, B);
B = A;
A = temp;
}
for (t = 40; t < 60; ++t)
{
temp = shift(5, A) + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = shift(30, B);
B = A;
A = temp;
}
for (t = 60; t < 80; ++t)
{
temp = shift(5, A) + (B ^ C ^ D) + E + W[t] + K[3];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = shift(30, B);
B = A;
A = temp;
}
H[0] = (H[0] + A) & 0xFFFFFFFF;
H[1] = (H[1] + B) & 0xFFFFFFFF;
H[2] = (H[2] + C) & 0xFFFFFFFF;
H[3] = (H[3] + D) & 0xFFFFFFFF;
H[4] = (H[4] + E) & 0xFFFFFFFF;
Message_Block_Index = 0;
}
void SHA::pad()
{
Message_Block[Message_Block_Index++] = 0x80;
if (Message_Block_Index > 56)
{
while (Message_Block_Index < 64)
{
Message_Block[Message_Block_Index++] = 0;
}
process();
}
while (Message_Block_Index < 56)
{
Message_Block[Message_Block_Index++] = 0;
}
Message_Block[56] = static_cast<unsigned char>((Length_High >> 24) & 0xFF);
Message_Block[57] = static_cast<unsigned char>((Length_High >> 16) & 0xFF);
Message_Block[58] = static_cast<unsigned char>((Length_High >> 8) & 0xFF);
Message_Block[59] = static_cast<unsigned char>((Length_High) & 0xFF);
Message_Block[60] = static_cast<unsigned char>((Length_Low >> 24) & 0xFF);
Message_Block[61] = static_cast<unsigned char>((Length_Low >> 16) & 0xFF);
Message_Block[62] = static_cast<unsigned char>((Length_Low >> 8) & 0xFF);
Message_Block[63] = static_cast<unsigned char>((Length_Low) & 0xFF);
process();
}
unsigned SHA::shift(int bits, unsigned word)
{
return ((word << bits) & 0xFFFFFFFF) | ((word & 0xFFFFFFFF) >> (32 - bits));
}
}
namespace doyou {
namespace io {
static int SHA1_String(const unsigned char* inputString, unsigned long len, unsigned char* pOutSHA1Buf)
{
if (!inputString || !pOutSHA1Buf)
return -1;
gloox::SHA sha1;
sha1.feed(inputString, len);
std::string s1 = sha1.binary();
if (s1.length() != 20)
return -2;
memcpy(pOutSHA1Buf, s1.c_str(), 20);
return 1;
}
}
}
#endif // SHA_H__
...@@ -1035,6 +1035,41 @@ engine2.0: 构建项目整体的服务端架构,服务端不同模块间,服 ...@@ -1035,6 +1035,41 @@ engine2.0: 构建项目整体的服务端架构,服务端不同模块间,服
1)增加计算机去部署相同的业务的同一服务器。换言之,同一服务去多态计算机上重复部署,以提高服务承载量。 1)增加计算机去部署相同的业务的同一服务器。换言之,同一服务去多态计算机上重复部署,以提高服务承载量。
2)易于计算。增加用户,应该增加匹配的服务器。 2)易于计算。增加用户,应该增加匹配的服务器。
【188】集群与分布式部署服务器系统后,高并发的能力会有很大提高。
【189】代理服务器特点总结:
1)提高访问效率,临时缓冲数据,便于访问。当前,可以将此项功能采用分布式设计思维将此业务分离出来为一个独立的服务器来做。
2)提供防火墙作用,保护服务器信息安全。客户端只知道网关服务器,并不知道内网的服务器信息;
3)突破访问限制。内部服务器可以通过网关服务器,实现一些被限制的访问等。
【189】服务者消费者设计区别:服务者进行服务注册,提供服务。消费者进行服务发现,消费服务。
【190】websocket通信握手过程:websocket客户端发送http消息,请求升级通信协议为websocket通信,
websocket服务端收到消息后对其key键值按计算公式加密后,进行数据应答。websocket客户端收到消息后
进行校验,校验通过,即成功建立websocket通信前的握手过程。
......
// 分析:当前工程是httpclient(简易的web客户端) // 分析:当前工程是httpclient(简易的web客户端)
// [2024-6-23-ok]
#include "Config.hpp" #include "Config.hpp"
#include "TcpHttpClient.hpp" #include "TcpHttpClient.hpp"
...@@ -16,7 +16,7 @@ public: ...@@ -16,7 +16,7 @@ public:
void Test() void Test()
{ {
static int i = 0; // 静态局部变量, 只会被初始化一次 static int i = 0; // 静态局部变量, 只会被初始化一次
++i; ++i; // 表达式的值等于变量i自增后的值
if (i > 100) { if (i > 100) {
return; return;
...@@ -29,7 +29,7 @@ public: ...@@ -29,7 +29,7 @@ public:
// para1: www.baidu.com/; para2: callback // para1: www.baidu.com/; para2: callback
this->Get(reqBuff, [this](HttpClientC* pHttpClient){ // lambda表达式作为实参 this->Get(reqBuff, [this](HttpClientC* pHttpClient){ // lambda表达式作为实参
if (pHttpClient != nullptr) { // httpclient正确收到应答消息场景 if (nullptr != pHttpClient) { // httpclient正确收到应答消息场景
CELLLog_Info("[httpclient][Test] recv http web server msg [bodyLen = %s] [id = %d].", CELLLog_Info("[httpclient][Test] recv http web server msg [bodyLen = %s] [id = %d].",
pHttpClient->HeaderGetStr("Content-Length", "?"), i); pHttpClient->HeaderGetStr("Content-Length", "?"), i);
CELLLog_Info("[httpclient][Test] recv http web server msg [content = %s] [id = %d].", pHttpClient->Content(), i); CELLLog_Info("[httpclient][Test] recv http web server msg [content = %s] [id = %d].", pHttpClient->Content(), i);
...@@ -47,7 +47,7 @@ public: ...@@ -47,7 +47,7 @@ public:
sprintf(reqBuff, "http://192.168.56.101:4568/sub?a=%d&b=1", i); sprintf(reqBuff, "http://192.168.56.101:4568/sub?a=%d&b=1", i);
this->Get(reqBuff, [this](HttpClientC* pHttpClient){ // lambda表达式作为实参 this->Get(reqBuff, [this](HttpClientC* pHttpClient){ // lambda表达式作为实参
if (pHttpClient != nullptr) { // httpclient正确收到应答消息场景 if (nullptr != pHttpClient) { // httpclient正确收到应答消息场景
CELLLog_Info("[httpclient][Test] recv http web server msg [bodyLen = %s] [id = %d].", CELLLog_Info("[httpclient][Test] recv http web server msg [bodyLen = %s] [id = %d].",
pHttpClient->HeaderGetStr("Content-Length", "?"), i); pHttpClient->HeaderGetStr("Content-Length", "?"), i);
CELLLog_Info("[httpclient][Test] recv http web server msg [content = %s] [id = %d].", pHttpClient->Content(), i); CELLLog_Info("[httpclient][Test] recv http web server msg [content = %s] [id = %d].", pHttpClient->Content(), i);
...@@ -65,7 +65,7 @@ public: ...@@ -65,7 +65,7 @@ public:
this->Post("http://192.168.56.101:4568/jsonTest", reqBuff, [this](HttpClientC* pHttpClient){ // lambda表达式作为实参 this->Post("http://192.168.56.101:4568/jsonTest", reqBuff, [this](HttpClientC* pHttpClient){ // lambda表达式作为实参
if (pHttpClient != nullptr) { // httpclient正确收到应答消息场景 if (nullptr != pHttpClient) { // httpclient正确收到应答消息场景
CELLLog_Info("[httpclient][Test] recv http web server json msg2 to way2: [bodyLen = %s] [id = %d].", CELLLog_Info("[httpclient][Test] recv http web server json msg2 to way2: [bodyLen = %s] [id = %d].",
pHttpClient->HeaderGetStr("Content-Length", "?"), i); pHttpClient->HeaderGetStr("Content-Length", "?"), i);
CELLLog_Info("[httpclient][Test] recv http web server json msg2 to way2: [content = %s] [id = %d].", pHttpClient->Content(), i); CELLLog_Info("[httpclient][Test] recv http web server json msg2 to way2: [content = %s] [id = %d].", pHttpClient->Content(), i);
...@@ -85,7 +85,7 @@ public: ...@@ -85,7 +85,7 @@ public:
}; };
int main(int argc, char* args[]) int main(int argc, char* args[]) // [2024-6-22]
{ {
// 设置window系统-控制台打印输出支持UTF-8格式字符串 // 设置window系统-控制台打印输出支持UTF-8格式字符串
#if _WIN32 && _CONSOLE #if _WIN32 && _CONSOLE
...@@ -119,7 +119,7 @@ int main(int argc, char* args[]) ...@@ -119,7 +119,7 @@ int main(int argc, char* args[])
} }
CELLLog_Info("[httpclient] recv http web server msg1: \n"); CELLLog_Info("[httpclient] recv http web server msg1: \n");
// BUG分析:存在空指针访问风险 // BUG分析:存在空指针访问风险-已解决:指针已判空
auto responseStr = pHttpClient->Content(); auto responseStr = pHttpClient->Content();
CELLLog_Info("[Content=%s]\n", responseStr); CELLLog_Info("[Content=%s]\n", responseStr);
}); // 获取外网域名IP列表 }); // 获取外网域名IP列表
......
// 分析:当前工程是httpserver(简易的web服务器) // 分析:当前工程是httpserver(简易的web服务器)
#pragma execution_character_set("utf-8") #pragma execution_character_set("utf-8")
// [2024-6-30-ok]
#include "TcpHttpServer.hpp" #include "TcpHttpServer.hpp"
#include "Log.hpp" #include "Log.hpp"
#include "Config.hpp" #include "Config.hpp"
...@@ -16,7 +16,7 @@ public: ...@@ -16,7 +16,7 @@ public:
virtual void OnNetMsg(Server* pServer, Client* pClient, netmsg_DataHeader* header) virtual void OnNetMsg(Server* pServer, Client* pClient, netmsg_DataHeader* header)
{ {
// 收到消息 // 收到消息
HttpClientS* pHttpClient = dynamic_cast<HttpClientS*>(pClient); // 将父类指针变量强转为子类指针变量 HttpClientS* pHttpClient = dynamic_cast<HttpClientS*>(pClient); // 将父类指针变量强转为子类指针变量[确保此时父类指针装的是被强转的子类指针对象,否则可能出现访问属性或方法的错误]
if (nullptr == pHttpClient) { if (nullptr == pHttpClient) {
CELLLog_Error("nullptr == pHttpClient"); CELLLog_Error("nullptr == pHttpClient");
return; return;
...@@ -38,7 +38,7 @@ public: ...@@ -38,7 +38,7 @@ public:
int b = pHttpClient->ArgsGetInt("b", 0); int b = pHttpClient->ArgsGetInt("b", 0);
int c = a + b; int c = a + b;
char respBodyBuff[32] = {0}; char respBodyBuff[32] = {0}; // 编程规范:变量在使用前都应该初始化
sprintf(respBodyBuff, "a + b = %d", c); sprintf(respBodyBuff, "a + b = %d", c);
pHttpClient->Resp200OK(respBodyBuff, strlen(respBodyBuff)); pHttpClient->Resp200OK(respBodyBuff, strlen(respBodyBuff));
...@@ -103,7 +103,7 @@ public: ...@@ -103,7 +103,7 @@ public:
} }
FILE* file = fopen(filePath.c_str(), "rb"); // para2-二进制格式读取文件,采用c风格读取文件 FILE* file = fopen(filePath.c_str(), "rb"); // para2-二进制格式读取文件,采用c风格读取文件
if (file == nullptr) { if (nullptr == file) {
return false; return false;
} }
...@@ -122,7 +122,7 @@ public: ...@@ -122,7 +122,7 @@ public:
// 分析:推荐读取的文件不能太大,发送缓冲区很小,超过之后,目前也发不出去, // 分析:推荐读取的文件不能太大,发送缓冲区很小,超过之后,目前也发不出去,
// 大文件的发送,后面会补充进来。 // 大文件的发送,后面会补充进来。
// 根据当前读取文件大小申请堆内存,存储文件内容缓存区buff // 根据当前读取文件大小申请堆内存,存储文件内容缓存区buff
char* buff = new char[bytesize]; char* buff = new char[bytesize]; // 数组指针,本质是一个指针,但这个指针指向了一个数组
auto readsize = fread(buff, 1, bytesize, file); // 读取的是二进制数据形式-rb auto readsize = fread(buff, 1, bytesize, file); // 读取的是二进制数据形式-rb
if (readsize != bytesize) { if (readsize != bytesize) {
CELLLog_Warring("readsize != bytesize, [url = %s]", filePath.c_str()); CELLLog_Warring("readsize != bytesize, [url = %s]", filePath.c_str());
...@@ -141,13 +141,13 @@ public: ...@@ -141,13 +141,13 @@ public:
} }
// //
void SetWwwRoot(const char* wwwRoot) void SetWwwRoot(char const* wwwRoot)
{ {
_wwwRoot = wwwRoot; _wwwRoot = wwwRoot;
} }
// //
void SetIndexPage(const char* indexPage) void SetIndexPage(char const* indexPage)
{ {
_indexPage = indexPage; _indexPage = indexPage;
} }
......
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{2A3173AA-CB78-44E3-A38E-61BC0D5ECCA2}</ProjectGuid>
<RootNamespace>HelloHttp</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(SolutionDir)../bin/$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)../tmp/$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)../bin/$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)../tmp/$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>false</SDLCheck>
<AdditionalIncludeDirectories>..\Depends\include</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>false</SDLCheck>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<None Include="..\..\bin\Debug\HelloHttp_HttpServer.sh" />
<None Include="..\..\bin\Debug\TcpEasyServer_linux_ipv4.sh" />
<None Include="config\WebEasyServer_wins_ipv4.bat" />
<None Include="www\websocket_test.html" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="server.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="源文件">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="头文件">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="资源文件">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="config\WebEasyServer_wins_ipv4.bat">
<Filter>头文件</Filter>
</None>
<None Include="..\..\bin\Debug\TcpEasyServer_linux_ipv4.sh">
<Filter>头文件</Filter>
</None>
<None Include="..\..\bin\Debug\HelloHttp_HttpServer.sh">
<Filter>头文件</Filter>
</None>
<None Include="www\websocket_test.html">
<Filter>头文件</Filter>
</None>
</ItemGroup>
<ItemGroup>
<ClCompile Include="server.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>
\ No newline at end of file
@echo off
::::::::::::::::::
::key-val
::字典
::std::map<k,v>
::::::::::::::::::
::服务端IP地址
set cmd="strIP=any"
::服务端端口
set cmd=%cmd% nPort=4568
::消息处理线程数量
set cmd=%cmd% nThread=1
::客户端连接上限
set cmd=%cmd% nMaxClient=100064
::客户端发送缓冲区大小(字节)
set cmd=%cmd% nSendBuffSize=20480
::客户端接收缓冲区大小(字节)
set cmd=%cmd% nRecvBuffSize=20480
:: 收到消息后将返回应答消息
set cmd=%cmd% -sendback
::提示发送缓冲区已写满
::当出现sendfull提示时,表示当次消息被丢弃
set cmd=%cmd% -sendfull
::检查接收到的客户端消息ID是否连续
set cmd=%cmd% -checkMsgID
::自定义标志 未使用
set cmd=%cmd% -p
:: 配置web服务器响应页面默认root目录和默认页面
set cmd=%cmd% wwwroot=D:/c++code/engine2.0研究/engine2.0/engine2.0/engine2.0/HelloHttp/www
set cmd=%cmd% indexpage=index.html
::启动程序 传入参数
HelloHttp %cmd%
pause
// 分析:当前工程是websocket服务端(简易的web服务器)
#pragma execution_character_set("utf-8")
#include "TcpHttpServer.hpp"
#include "Log.hpp"
#include "Config.hpp"
#include "sha1.hpp"
#include "base64.hpp"
using namespace doyou::io; // 命名空间
class MyServer : public TcpHttpServer
{
public:
// 处理网路消息
virtual void OnNetMsg(Server* pServer, Client* pClient, netmsg_DataHeader* 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;
}
auto strUpgrade = pHttpClient->HeaderGetStr("Upgrade", "");
if (0 != strcmp(strUpgrade, "websocket")) {
CELLLog_Error("not found Upgrade: websocket");
return;
}
auto cKey = pHttpClient->HeaderGetStr("Sec-WebSocket-Key", nullptr); // 客户端key
if (nullptr == cKey) {
CELLLog_Error("not fount Sec-WebSocket-Key");
return;
}
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);
}
private:
};
int main(int argc, char* args[])
{
// 设置运行日志名称
Log::Instance().setLogPath("ServerLog", "w", false);
Config::Instance().Init(argc, args);
// 解析配置
const char* strIP = Config::Instance().getStr("strIP", "any");
uint16_t nPort = Config::Instance().getInt("nPort", 4568);
int nThread = Config::Instance().getInt("nThread", 1);
if (strcmp(strIP, "any") == 0)
{
strIP = nullptr;
}
MyServer server; // 在栈空间实例化对象
if (Config::Instance().hasKey("-ipv6")) {
CELLLog_Info("-ipv6");
server.InitSocket(AF_INET6);
}
else {
CELLLog_Info("-ipv4");
server.InitSocket();
}
// 解析http配置
// 分析:调试模式读取不到配置文件配置信息, 就采用默认值
const char* wwwroot = Config::Instance().getStr("wwwroot", "./www");
const char* indexpage = Config::Instance().getStr("indexpage", "index.html");
server.SetWwwRoot(wwwroot);
server.SetIndexPage(indexpage);
server.Bind(strIP, nPort);
// 分析:服务器同一时刻能监听的最大客户端数量,可以提高服务器连接客户端的效率
server.Listen(SOMAXCONN); // 64
server.Start(nThread);
// 在主线程中等待用户输入命令
while (true)
{
char cmdBuf[256] = {};
scanf("%s", cmdBuf); // 等待用户输入,当前函数为阻塞函数
if (0 == strcmp(cmdBuf, "exit"))
{
server.Close();
break;
}
else {
CELLLog_Info("undefine cmd");
}
}
CELLLog_Info("exit.");
return 0;
}
/*
// html脚本字符串, c/c++中逻辑换行符[\]: 当前行和下面一行逻辑合并为同一行
char htmlStr[] =
"\
<!DOCTYPE html>\
<html>\
<head>\
<title>hello web</title>\
</head>\
<body>\
<button>GET</button>\
<button>POST</button>\
</body>\
</html>\
";
*/
<!DOCTYPE html>
<html>
<head>
<title>hello web</title>
</head>
<body>
<button>GET</button>
<button>POST</button>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<title>websocket-client</title>
</head>
<body>
<button onclick="_createWebSocket()">connect</button>
<button onclick="_send('hello web')">send</button>
<button onclick="_close()">close</button>
<script>
function _createWebSocket() {
var serverAddress = 'ws://127.0.0.1:4568/';
try {
_websocket = new WebSocket(serverAddress);
} catch (evt) {
console.log("new websocket error:" + evt.data);
return;
}
_websocket.onopen = _onOpen;
_websocket.onclose = _onClose;
_websocket.onmessage = _onMessage;
_websocket.onerror = _onError;
}
function _onOpen(evt) {
console.log("Connected to WebSocket Server.");
}
function _onClose(evt) {
console.log("Disconnected.");
}
function _onMessage(evt) {
console.log("_onMessage.");
}
function _onError(evt) {
console.log("_onError.");
}
</script>
</body>
</html>
\ No newline at end of file
...@@ -67,6 +67,7 @@ ...@@ -67,6 +67,7 @@
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\Depends\include\base64.hpp" />
<ClInclude Include="..\Depends\include\Buffer.hpp" /> <ClInclude Include="..\Depends\include\Buffer.hpp" />
<ClInclude Include="..\Depends\include\ByteStream.hpp" /> <ClInclude Include="..\Depends\include\ByteStream.hpp" />
<ClInclude Include="..\Depends\include\CELL.hpp" /> <ClInclude Include="..\Depends\include\CELL.hpp" />
...@@ -78,6 +79,7 @@ ...@@ -78,6 +79,7 @@
<ClInclude Include="..\Depends\include\HttpClientC.hpp" /> <ClInclude Include="..\Depends\include\HttpClientC.hpp" />
<ClInclude Include="..\Depends\include\HttpClientS.hpp" /> <ClInclude Include="..\Depends\include\HttpClientS.hpp" />
<ClInclude Include="..\Depends\include\KeyString.hpp" /> <ClInclude Include="..\Depends\include\KeyString.hpp" />
<ClInclude Include="..\Depends\include\sha1.hpp" />
<ClInclude Include="..\Depends\include\SplitString.hpp" /> <ClInclude Include="..\Depends\include\SplitString.hpp" />
<ClInclude Include="..\Depends\include\TcpClientMgr.hpp" /> <ClInclude Include="..\Depends\include\TcpClientMgr.hpp" />
<ClInclude Include="..\Depends\include\TcpHttpClient.hpp" /> <ClInclude Include="..\Depends\include\TcpHttpClient.hpp" />
......
...@@ -13,6 +13,9 @@ ...@@ -13,6 +13,9 @@
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter> </Filter>
<Filter Include="third">
<UniqueIdentifier>{f15de6e4-01cb-4591-8f34-5a2b4bbd3db6}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\Depends\include\Buffer.hpp"> <ClInclude Include="..\Depends\include\Buffer.hpp">
...@@ -126,5 +129,11 @@ ...@@ -126,5 +129,11 @@
<ClInclude Include="..\Depends\include\HttpClientS.hpp"> <ClInclude Include="..\Depends\include\HttpClientS.hpp">
<Filter>源文件</Filter> <Filter>源文件</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\Depends\include\base64.hpp">
<Filter>third</Filter>
</ClInclude>
<ClInclude Include="..\Depends\include\sha1.hpp">
<Filter>third</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>
\ No newline at end of file
...@@ -24,6 +24,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EasyHttpClient", "EasyHttpC ...@@ -24,6 +24,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EasyHttpClient", "EasyHttpC
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenAI", "OpenAI\OpenAI.vcxproj", "{2512751B-C22A-4E16-84B8-8B94CDA63114}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenAI", "OpenAI\OpenAI.vcxproj", "{2512751B-C22A-4E16-84B8-8B94CDA63114}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WebSocketServer", "WebSocketServer\WebSocketServer.vcxproj", "{2A3173AA-CB78-44E3-A38E-61BC0D5ECCA2}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32 Debug|Win32 = Debug|Win32
...@@ -62,6 +64,10 @@ Global ...@@ -62,6 +64,10 @@ Global
{2512751B-C22A-4E16-84B8-8B94CDA63114}.Debug|Win32.Build.0 = Debug|Win32 {2512751B-C22A-4E16-84B8-8B94CDA63114}.Debug|Win32.Build.0 = Debug|Win32
{2512751B-C22A-4E16-84B8-8B94CDA63114}.Release|Win32.ActiveCfg = Release|Win32 {2512751B-C22A-4E16-84B8-8B94CDA63114}.Release|Win32.ActiveCfg = Release|Win32
{2512751B-C22A-4E16-84B8-8B94CDA63114}.Release|Win32.Build.0 = Release|Win32 {2512751B-C22A-4E16-84B8-8B94CDA63114}.Release|Win32.Build.0 = Release|Win32
{2A3173AA-CB78-44E3-A38E-61BC0D5ECCA2}.Debug|Win32.ActiveCfg = Debug|Win32
{2A3173AA-CB78-44E3-A38E-61BC0D5ECCA2}.Debug|Win32.Build.0 = Debug|Win32
{2A3173AA-CB78-44E3-A38E-61BC0D5ECCA2}.Release|Win32.ActiveCfg = Release|Win32
{2A3173AA-CB78-44E3-A38E-61BC0D5ECCA2}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册