前言
evpp是一个基于libevent开发的现代化C++11高性能网络服务器,自带TCP/UDP/HTTP等协议的异步非阻塞式的服务器和客户端库。来自于奇虎360公司github,star: 2.7k。
使用方面,因为支持跨平台,通过vcpkg install evpp安装很方便,故在团队内推广,最近希望扩大其使用范围,奈何其不支持openssl和websocket,还需要自己动手。
本教程很多思路借鉴了 不败青铜: websocket协议实现及基于muduo库的功能扩展 https/ws/wss 的教程,因为evpp的设计学习自muduo,使得增加openssl的过程中非常顺利。
修改说明
本分支基于 evpp 8984ca6b
- 增加build.md文档
- 修改tcp_conn,SendInLoop(),HandleRead(),HandleWrite(),HandleClose()更改为虚函数以方便实现SslConn,WebSocketConn
- 增加evpp/ssl目录,支持SSL over TCP,使用方法见evpp/ssl/ssl_server.h的类注释
- 增加evpp/ws和evpp/sha1目录,支持WebSocket(ws协议),使用方法见evpp/ws/web_socket_server.h的类注释
传送门:Github
使用
OpenSSL
详细代码参考:/evpp/examples/tls目录。
Server
#include <evpp/ssl/ssl_server.h>
#include <evpp/tcp_conn.h>
#ifdef WIN32
struct OnApp {
OnApp() {
// Initialize net work.
WSADATA wsaData;
// Initialize Winsock 2.2
int nError = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (nError) {
std::cout << "WSAStartup() failed with error: %d" << nError;
}
}
~OnApp() {
system("pause");
}
} __s_onexit_pause;
#endif
int main() {
std::string addr = "0.0.0.0:8433";
int thread_num = 4;
evpp::EventLoop loop;
if (!evpp::ssl::SSL_CTX_Init("google.com.pem", "google.com.key")) {
LOG_ERROR << "SSL_CTX_Init error";
return 0;
}
evpp::ssl::SSLServer server(&loop, addr, "TlsServer", thread_num, evpp::ssl::SSL_CTX_Get());
server.SetMessageCallback([](const evpp::TCPConnPtr &conn,
evpp::Buffer *msg) {
LOG_INFO << "recv client msg:len=" << msg->length() << ",content=" << msg->ToString();
// Do something with the received message
conn->Send(msg); // At here, we just send the received message back.
});
server.SetConnectionCallback([](const evpp::TCPConnPtr &conn) {
if (conn->IsConnected()) {
LOG_INFO << "A new connection from " << conn->remote_addr();
} else {
LOG_INFO << "Lost the connection from " << conn->remote_addr();
}
});
server.Init();
server.Start();
loop.Run();
evpp::ssl::SSL_CTX_free();
return 0;
}
Client
/** @file tls_client.h
* @brief
* @author xmcy0011@sina.com
* @date 5/17/21
*/
#include "evpp/ssl/ssl_client.h"
#ifdef WIN32
struct OnApp {
OnApp() {
// Initialize net work.
WSADATA wsaData;
// Initialize Winsock 2.2
int nError = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (nError) {
std::cout << "WSAStartup() failed with error: %d" << nError;
}
}
~OnApp() {
system("pause");
}
} __s_onexit_pause;
#endif
int main(int argc, char *argv[]) {
std::string addr = "127.0.0.1:8433";
//std::string addr = "1127.0.0.1:8433";
if (argc == 2) {
addr = argv[1];
}
evpp::EventLoop loop;
evpp::ssl::SSLClient client(&loop, addr, "TCPPingPongClient");
client.SetMessageCallback([&loop, &client](const evpp::TCPConnPtr &conn,
evpp::Buffer *msg) {
LOG_TRACE << "Receive a message [" << msg->ToString() << "]";
client.Disconnect();
});
client.SetConnectionCallback([](const evpp::TCPConnPtr &conn) {
if (conn->IsConnected()) {
LOG_INFO << "Connected to " << conn->remote_addr();
conn->Send("hello");
} else {
conn->loop()->Stop();
}
});
client.Connect();
loop.Run();
return 0;
}
WebSocket
详细代码参考:/evpp/examples/ws目录。
/** @file websocket_server.h
* @brief WebSocketServer示例
* @author teng.qing
* @date 2021/5/23
*/
#include "evpp/event_loop.h"
#include "evpp/tcp_callbacks.h"
#include "evpp/ws/web_socket_conn.h"
#include "evpp/ws/web_socket_server.h"
#include "evpp/logging.h"
int main() {
std::string addr = "0.0.0.0:8002";
int thread_num = 4;
evpp::EventLoop loop;
evpp::ws::WebSocketServer server(&loop, addr, "TlsServer", thread_num);
server.SetMessageCallback([](const evpp::TCPConnPtr &conn,
evpp::Buffer *msg) {
LOG_INFO << "recv client msg:len=" << msg->length();
conn->Send(msg); // At here, we just send the received message back.
}
});
server.SetConnectionCallback([](const evpp::TCPConnPtr &conn) {
if (conn->IsConnected()) {
LOG_INFO << "A new connection from " << conn->remote_addr();
} else {
LOG_INFO << "Lost the connection from " << conn->remote_addr();
}
});
server.Init();
server.Start();
loop.Run();
return 0;
}
OpenSSL入门
可以参考我写的:OpenSSL API入门和踩坑大全