boost asio实现的TCP客户端(同时支持ssl)
linux-dash
A beautiful web dashboard for Linux
项目地址:https://gitcode.com/gh_mirrors/li/linux-dash
免费下载资源
·
因为要开发TCP客户端用于网络通信,用c++来写,要实现跨平台在window和linux都能用的话,自己去封装原始的套接字操作,要兼容linux和window两个平台,有点困难,工作量也不小,于是用了现有的别人封装好的库,用boost的asio来封装一个TCP客户端。 boost 的asio是一个优秀的全异步跨平台的网络通信库,不过源码都是用模板来写的,看起来比较吃力。因为通信也有需要用到SSL的情况,所以设计的TcpClient兼容普通的套接字通信和ssl通信,可以作为初学者的借鉴,有不完善的地方希望大家多多指点。分为4个文件,代码如下:
TcpClient.h文件:
// boost的asio库实现的Tcp客户端类
#ifndef LY_BOOST_TCP_CLIENT
#define LY_BOOST_TCP_CLIENT
#include <string>
#include "boost/asio.hpp"
#include "boost/shared_ptr.hpp"
#include "boost/enable_shared_from_this.hpp"
#include "boost/bind.hpp"
#include "boost/asio/placeholders.hpp"
#include <boost/thread.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/function.hpp>
#include <vector>
#include <queue>
#include "Logdef.h"
using namespace std;
namespace TC
{
enum TCP_EVENT
{
TCP_EVENT_CONNECTED = 1,
TCP_EVENT_CONNECT_FAILED,
TCP_EVENT_WRITE_FAILED,
TCP_EVENT_READ_FAILED
};
// Tcp发送缓冲区
class TcpSendBuff
{
typedef boost::shared_lock<boost::shared_mutex> ReadLock;
typedef boost::unique_lock<boost::shared_mutex> WriteLock;
typedef boost::shared_ptr<string> StringPtr;
public:
TcpSendBuff();
~TcpSendBuff();
// 添加发送数据,如果未发送数据的总大小超过最大限制,会返回失败
bool Append(const char *buff, int len);
// 获取下一次发送的缓冲区数据及长度,如果已经发送完毕,返回空指针NULL, 并且len为0
const char *GetNextSendBuff(int &len);
// 每次发送完成后,需要调用这个函数来递减发送的数据,理论上,这个值不会超过发送队列头部的缓冲区大小
void SetCompleteSendBytes(int len);
void SetMaxBuffSize(int size) { m_maxSize = size; }
private:
std::queue<StringPtr> m_sendQueue; // 发送缓存区,使用队列来存放
boost::shared_mutex m_rwMutext; // 发送缓冲区队列要加锁
int m_sendBuffTotalSize; // 发送缓冲区的总大小(队列中所有string.size()的和)
int m_maxSize;
int m_topEleSendSize; // 队列第一个缓冲区已经发送的字节数
};
// Tcp接收缓冲区
class TcpRecvBuff
{
typedef boost::shared_lock<boost::shared_mutex> ReadLock;
typedef boost::unique_lock<boost::shared_mutex> WriteLock;
typedef boost::shared_ptr<string> StringPtr;
public:
TcpRecvBuff();
~TcpRecvBuff();
// 获取缓冲区首地址,获取失败返回NULL
// willRecvLen下次准备接收的数据长度,缓冲区内部会决定是否扩容
char *GetRecvBuff(int willRecvLen);
// 获取接收的所有数据,如果没有数据,返回NULL并且len为0
const char *GetRecvData(int &len);
void SetRecvDataSize(int len) { m_hasBeenRecvSize += len; }
// 清空接收到的所有数据
void ClearRecvData() { m_hasBeenRecvSize = 0; };
void SetMaxBuffSize(int size) { m_maxBuffSize = size; }
private:
vector<char> m_recvBuff; // 接收缓冲区使用vector
boost::shared_mutex m_rwMutext; // 接收缓冲区队列锁
int m_hasBeenRecvSize; // 当前缓冲区已经接收的数据长度
int m_maxBuffSize; // 缓冲区最大值
};
typedef boost::function<void(const char *, int)> TcpClientReadCallBack;
// 事件回调
typedef boost::function<void(TCP_EVENT, string)> TcpClientEventCallBack;
// 证书校验回调
typedef boost::function<bool(bool, boost::asio::ssl::verify_context &)> TcpClientVerifyCertificateCallBack;
class TcpClient : public boost::enable_shared_from_this<TcpClient>
{
typedef boost::asio::ip::tcp::endpoint endpoint_type;
typedef boost::asio::ip::address address_type;
typedef boost::asio::ip::tcp::socket socket_type;
typedef boost::shared_ptr<socket_type> sock_ptr;
typedef boost::asio::io_service io_service_type;
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> stream_sock_type;
typedef boost::shared_ptr<stream_sock_type> stream_sock_ptr;
typedef boost::asio::ssl::context ssl_context_type;
typedef boost::shared_ptr<ssl_context_type> ssl_context_ptr;
public:
TcpClient(io_service_type *pIoService);
~TcpClient();
// 本次将要接收的数据长度,直到接收到指定长度的数据后才会调用TcpClientReadCallBack函数回调
// 连接成功后必须调用此函数才会接收数据,切记
// bDelPreData 是否删除前面接收的数据,如果不删除,下次回调的时候继续保留
bool ContinueRecvData(int nRecvLen, bool bDelPreData = true);
// 设置读数据回调函数
void SetReadDataCallBack(TcpClientReadCallBack cb) { m_readCb = cb; }
// 设置事件回调函数,事件类型见TCP_EVENT
void SetEventCallBack(TcpClientEventCallBack cb) { m_eventCb = cb; }
// 设置ssl相关证书,bVerifyPeer为true表示需要校验对方,如果cb不为空,则会进行校验回调
void SetSslContext(string strCapem, string strClientPem, string strPrivateKey, bool bVerifyPeer = true, TcpClientVerifyCertificateCallBack cb = NULL);
// 异步发起连接,连接结果在事件回调时通知 成功时:TCP_EVENT_CONNECTED 失败时:TCP_EVENT_CONNECT_FAILED
bool AsyncConnect(string ip, unsigned short port);
// 异步写数据,如果出错会在事件回调时通知
bool AsyncWrite(const char *pBuff, int nLen);
// 关闭连接
bool Close();
private:
// 连接成功回调
void OnAsyncConnect(const boost::system::error_code &ec);
// 写数据回调
void OnAsyncWrite(const boost::system::error_code &ec, size_t bytes_transferred);
void DoWriteDataToTcp();
// 收数据回调
void OnAsyncRead(const boost::system::error_code &ec, size_t recvSize);
// // 校验对端证书回调函数
// bool OnVerifyCertificate(bool preverified, boost::asio::ssl::verify_context& ctx);
// SSL握手回调
void OnHandleHandshake(const boost::system::error_code &error);
private:
endpoint_type m_endPoint;
sock_ptr m_socketPtr; // 用于普通的TCP通信
stream_sock_ptr m_streamSockPtr; // 用于SSL通信
ssl_context_ptr m_sslContextPtr;
io_service_type *m_pIoService;
bool m_bUseSsl;
bool m_bConnected; // 是否成功建立连接
// 回调函数
TcpClientReadCallBack m_readCb; // 接收数据回调
TcpClientEventCallBack m_eventCb; // 事件回调
TcpRecvBuff m_recvBuff;
TcpSendBuff m_sendBuff;
};
typedef boost::shared_ptr<TcpClient> TcpClientPtr;
}
#endif
TcpClient.cpp
#include "WinDef.h"
#include "TcpClient.h"
#include <iostream>
#include <boost/lexical_cast.hpp>
using namespace TC;
using namespace boost;
using namespace boost::asio;
using namespace boost::asio::ip;
#define TCP_CLINET_SEND_BUFF_MAX_SIZE 1024 * 1024 * 4
TcpSendBuff::TcpSendBuff() : m_sendBuffTotalSize(0),
m_maxSize(TCP_CLINET_SEND_BUFF_MAX_SIZE),
m_topEleSendSize(0)
{
}
TcpSendBuff::~TcpSendBuff()
{
}
bool TcpSendBuff::Append(const char *buff, int len)
{
StringPtr ptr(new string(buff, len));
// 加锁
{
WriteLock writeLock(m_rwMutext);
if (m_sendBuffTotalSize + len > m_maxSize)
{
X_PRINT("Buffer size out of limit, currsize:%d maxsize:%d", m_sendBuffTotalSize, m_maxSize);
return false;
}
m_sendQueue.push(ptr);
m_sendBuffTotalSize += len;
}
return true;
}
const char *TcpSendBuff::GetNextSendBuff(int &len)
{
len = 0;
{
ReadLock writeLock(m_rwMutext);
if (m_sendQueue.empty())
{
return NULL;
}
StringPtr topBuffPtr = m_sendQueue.front();
len = topBuffPtr->size() - m_topEleSendSize;
const char *retPointer = topBuffPtr->c_str() + m_topEleSendSize;
return retPointer;
}
}
void TcpSendBuff::SetCompleteSendBytes(int len)
{
{
WriteLock writeLock(m_rwMutext);
if (m_sendQueue.empty())
{
X_PRINT("error: send queue is empty");
return;
}
StringPtr topBuffPtr = m_sendQueue.front();
if (m_topEleSendSize + len > topBuffPtr->size())
{
// 缓冲区错误
X_PRINT("error: send buff size incorrect");
return;
}
else if (m_topEleSendSize + len < topBuffPtr->size())
{
// 第一个缓冲区的数据还没发送完,下次要把剩下的数据发完
m_topEleSendSize += len;
return;
}
else // (m_topEleSendSize + len) == topBuffPtr->size()
{
// 第一个缓冲区的数据已经发完,删除
m_topEleSendSize = 0;
m_sendBuffTotalSize -= topBuffPtr->size();
m_sendQueue.pop();
X_PRINT("top buff has been send complete, current queue_size:%d", m_sendQueue.size());
return;
}
}
}
TcpRecvBuff::TcpRecvBuff() : m_recvBuff(1024, 0),
m_hasBeenRecvSize(0)
{
}
TcpRecvBuff::~TcpRecvBuff()
{
}
char *TcpRecvBuff::GetRecvBuff(int willRecvLen)
{
{
WriteLock writeLock(m_rwMutext);
if (willRecvLen + m_hasBeenRecvSize <= m_recvBuff.size())
{
return &m_recvBuff[0] + m_hasBeenRecvSize;
}
else if (willRecvLen + m_hasBeenRecvSize > m_maxBuffSize)
{
X_PRINT("Buffer size out of limit, currRecvSize:%d willRecvSize:%d maxsize:%d",m_hasBeenRecvSize, willRecvLen, m_maxBuffSize);
return NULL;
}
else
{
// 扩容
m_recvBuff.resize(willRecvLen + m_hasBeenRecvSize);
return &m_recvBuff[0] + m_hasBeenRecvSize;
}
}
}
const char *TcpRecvBuff::GetRecvData(int &len)
{
len = 0;
ReadLock readLock(m_rwMutext);
if (0 == m_hasBeenRecvSize)
{
return NULL;
}
else
{
len = m_hasBeenRecvSize;
return &m_recvBuff[0];
}
}
TcpClient::TcpClient(io_service_type *pIoService) : m_pIoService(pIoService),
m_bUseSsl(false),
m_bConnected(false)
{
}
TcpClient::~TcpClient()
{
}
void TcpClient::SetSslContext(string strCapem, string strClientPem, string strPrivateKey, bool bVerifyPeer, TcpClientVerifyCertificateCallBack cb)
{
m_bUseSsl = true;
m_sslContextPtr.reset(new ssl_context_type(boost::asio::ssl::context::sslv23)); // 初始化ssl context对象,也可以使用其他ssl版本
// 设置不压缩
m_sslContextPtr->set_options(boost::asio::ssl::context::no_compression);
// 加载ca证书
m_sslContextPtr->load_verify_file(strCapem);
// 加载客户端证书
m_sslContextPtr->use_certificate_file(strClientPem, boost::asio::ssl::context_base::file_format::pem);
// 加载客户端私钥
m_sslContextPtr->use_private_key_file(strPrivateKey, boost::asio::ssl::context_base::file_format::pem);
if (bVerifyPeer)
{
m_sslContextPtr->set_verify_mode(boost::asio::ssl::verify_peer);
}
m_streamSockPtr.reset(new stream_sock_type(*m_pIoService, *m_sslContextPtr)); // 初始化stream sock
if (bVerifyPeer)
{
// 设置校验对方
m_streamSockPtr->set_verify_mode(boost::asio::ssl::verify_peer);
}
if (!cb.empty())
{
// 设置校验回调函数
//m_streamSockPtr->set_verify_callback(boost::bind(&TcpClient::OnVerifyCertificate, this, _1, _2));
m_streamSockPtr->set_verify_callback(cb);
}
}
// bool TcpClient::OnVerifyCertificate(bool preverified, boost::asio::ssl::verify_context &ctx)
// {
// // The verify callback can be used to check whether the certificate that is
// // being presented is valid for the peer. For example, RFC 2818 describes
// // the steps involved in doing this for HTTPS. Consult the OpenSSL
// // documentation for more details. Note that the callback is called once
// // for each certificate in the certificate chain, starting from the root
// // certificate authority.
// // In this example we will simply print the certificate's subject name.
// char subject_name[256];
// X509 *cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
// X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);
// std::cout << "Verifying " << subject_name << "\n";
// return preverified;
// }
bool TcpClient::AsyncConnect(string ip, unsigned short port)
{
if (m_bConnected)
{
X_PRINT("socket has established");
return false;
}
if (m_bUseSsl)
{
string strPort = boost::lexical_cast<string>(port);
boost::asio::ip::tcp::resolver resolver(*m_pIoService);
boost::asio::ip::tcp::resolver::query query(ip.c_str(), strPort.c_str());
boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
boost::asio::async_connect(m_streamSockPtr->lowest_layer(), endpoint_iterator,
boost::bind(&TcpClient::OnAsyncConnect, shared_from_this(),
boost::asio::placeholders::error));
}
else
{
boost::asio::ip::tcp::endpoint peer_ep(boost::asio::ip::address::from_string(ip), short(port));
m_endPoint = peer_ep;
m_socketPtr.reset(new socket_type(*m_pIoService));
m_socketPtr->async_connect(m_endPoint, boost::bind(&TcpClient::OnAsyncConnect, shared_from_this(), boost::asio::placeholders::error));
}
return true;
}
void TcpClient::OnAsyncConnect(const boost::system::error_code &ec)
{
if (ec)
{
// 连接出现错误
X_PRINT("connect error:%s", ec.message().c_str());
if (!m_eventCb.empty())
{
m_eventCb(TCP_EVENT_CONNECT_FAILED, ec.message());
}
m_bConnected = false;
if (m_bUseSsl)
{
m_streamSockPtr->lowest_layer().cancel();
boost::system::error_code call_ec;
m_streamSockPtr->shutdown(call_ec);
}
else
{
boost::system::error_code call_ec;
if (m_socketPtr->is_open())
{
m_socketPtr->shutdown(boost::asio::ip::tcp::socket::shutdown_both, call_ec);
m_socketPtr->close(call_ec);
}
}
return;
}
if (m_bUseSsl)
{
// ssl握手
m_streamSockPtr->async_handshake(boost::asio::ssl::stream_base::client,
boost::bind(&TcpClient::OnHandleHandshake, shared_from_this(),
boost::asio::placeholders::error));
return;
}
m_bConnected = true;
if (!m_eventCb.empty())
{
m_eventCb(TCP_EVENT_CONNECTED, "");
}
}
void TcpClient::OnHandleHandshake(const boost::system::error_code &error)
{
if (!error)
{
X_PRINT("Handshake success");
m_bConnected = true;
if (!m_eventCb.empty())
{
m_eventCb(TCP_EVENT_CONNECTED, "");
}
return;
}
X_PRINT("Handshake failed: %s", error.message().c_str());
if (!m_eventCb.empty())
{
m_eventCb(TCP_EVENT_CONNECT_FAILED, error.message());
}
}
void TcpClient::OnAsyncWrite(const boost::system::error_code &ec, size_t bytes_transferred)
{
if (ec)
{
X_PRINT("write error:%s", ec.message().c_str());
if (!m_eventCb.empty())
{
m_eventCb(TCP_EVENT_WRITE_FAILED, ec.message());
}
if (!m_bConnected)
{
// 避免多次执行关闭操作而导致崩溃
return;
}
m_bConnected = false;
if (m_bUseSsl)
{
m_streamSockPtr->lowest_layer().cancel();
boost::system::error_code call_ec;
m_streamSockPtr->shutdown(call_ec);
}
else
{
boost::system::error_code call_ec;
if (m_socketPtr->is_open())
{
m_socketPtr->shutdown(boost::asio::ip::tcp::socket::shutdown_both, call_ec);
m_socketPtr->close(call_ec);
}
}
return;
}
X_PRINT("write success, len:%d", bytes_transferred);
// 通知缓冲区发送成功
m_sendBuff.SetCompleteSendBytes(bytes_transferred);
// 如果没有发送完成,继续发送
DoWriteDataToTcp();
}
void TcpClient::OnAsyncRead(const boost::system::error_code &ec, size_t recvSize)
{
if (ec)
{
X_PRINT("read error:%s", ec.message().c_str());
if (!m_eventCb.empty())
{
m_eventCb(TCP_EVENT_READ_FAILED, ec.message());
}
if (!m_bConnected)
{
// 避免多次执行关闭操作而导致崩溃
return;
}
m_bConnected = false;
if (m_bUseSsl)
{
m_streamSockPtr->lowest_layer().cancel();
boost::system::error_code call_ec;
m_streamSockPtr->shutdown(call_ec);
}
else
{
boost::system::error_code call_ec;
if (m_socketPtr->is_open())
{
m_socketPtr->shutdown(boost::asio::ip::tcp::socket::shutdown_both, call_ec);
m_socketPtr->close(call_ec);
}
}
return;
}
m_recvBuff.SetRecvDataSize(recvSize);
// 数据接收回调
if (!m_readCb.empty())
{
int dataLen;
const char *pBuff = m_recvBuff.GetRecvData(dataLen);
if (pBuff == NULL)
{
if (!m_eventCb.empty())
{
m_eventCb(TCP_EVENT_READ_FAILED, "RecvBuff error");
}
X_PRINT("RecvBuff error");
return;
}
m_readCb(pBuff, dataLen);
}
}
bool TcpClient::ContinueRecvData(int nRecvLen, bool bDelPreData)
{
if (!m_bConnected)
{
X_PRINT("not connected");
return false;
}
if (bDelPreData)
{
m_recvBuff.ClearRecvData();
}
char *buff = m_recvBuff.GetRecvBuff(nRecvLen);
if (buff == NULL)
{
X_PRINT("ContinueRecvData error");
return false;
}
if (m_bUseSsl)
{
boost::asio::async_read(
*m_streamSockPtr, boost::asio::buffer(buff, nRecvLen), boost::bind(&TcpClient::OnAsyncRead, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
else
{
boost::asio::async_read(
*m_socketPtr, boost::asio::buffer(buff, nRecvLen), boost::bind(&TcpClient::OnAsyncRead, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
return true;
}
bool TcpClient::AsyncWrite(const char *pBuff, int nLen)
{
if (!m_bConnected)
{
return false;
}
X_PRINT("add bytes to send buff, len:%d", nLen);
// 放入缓冲区
if (!m_sendBuff.Append(pBuff, nLen))
{
return false;
}
DoWriteDataToTcp();
return true;
}
void TcpClient::DoWriteDataToTcp()
{
int willSendLen;
const char *willSendBuff = m_sendBuff.GetNextSendBuff(willSendLen);
if (willSendBuff == NULL)
{
return;
}
if (m_bUseSsl)
{
boost::asio::async_write(*m_streamSockPtr,
boost::asio::buffer(willSendBuff, willSendLen),
boost::asio::transfer_at_least(willSendLen),
boost::bind(&TcpClient::OnAsyncWrite, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
{
boost::asio::async_write(*m_socketPtr,
boost::asio::buffer(willSendBuff, willSendLen),
boost::asio::transfer_at_least(willSendLen),
boost::bind(&TcpClient::OnAsyncWrite, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
}
bool TcpClient::Close()
{
if (!m_bConnected)
{
// 如果还没连接上,就不要走关闭流程,直接返回
return true;
}
m_bConnected = false;
if (m_bUseSsl)
{
if (m_streamSockPtr != NULL)
{
m_streamSockPtr->lowest_layer().cancel();
boost::system::error_code call_ec;
m_streamSockPtr->shutdown(call_ec);
}
}
else
{
if (m_socketPtr != NULL)
{
boost::system::error_code call_ec;
m_socketPtr->shutdown(boost::asio::ip::tcp::socket::shutdown_both, call_ec);
m_socketPtr->close(call_ec);
}
}
return true;
}
WinDef.h
#ifdef _MSC_VER
#define _WIN32_WINNT 0x0501
#endif
输出日志相关头文件 Logdef.h
#ifndef TCP_CLIENT_LOG_DEF
#define TCP_CLIENT_LOG_DEF
#include <time.h>
#include <stdio.h>
#include <string>
static std::string GetCurrentDateTime()
{
struct tm *stTm;
time_t tm = time(NULL);
stTm = localtime(&tm);
char buffer[50] = {0};
sprintf(buffer, "%04d-%02d-%02d %02d:%02d:%02d", stTm->tm_year + 1900, stTm->tm_mon + 1, stTm->tm_mday, stTm->tm_hour, stTm->tm_min, stTm->tm_sec);
return std::string(buffer);
}
#define __FILENAME__ (strrchr(__FILE__, '/') ? (strrchr(__FILE__, '/') + 1):__FILE__)
#define X_PRINT(...) do {\
fprintf(stdout, "%s[%s %s:%d]", GetCurrentDateTime().c_str(), __FILENAME__, __FUNCTION__, __LINE__);\
fprintf(stdout, __VA_ARGS__); \
fprintf(stdout, "\n"); \
fflush(stdout); \
}while(0);
#endif
下面是使用示例:
#include "WinDef.h"
#include "TcpClient.h"
#include "boost/thread.hpp"
#include "boost/date_time/posix_time/posix_time.hpp" //定时器
void OnRead(TcpClientPtr clientPtr, const char* pBuff, int len, bool &bClear)
{
cout << "recv data:" << string(pBuff, len) << endl;
clientPtr->ContinueRecvData(5);
}
void OnEvent(TcpClientPtr clientPtr, TCP_EVENT ev, string msg)
{
if (ev == TCP_EVENT_CONNECTED)
{
X_PRINT("connect success");
clientPtr->ContinueRecvData(5);
}
else
{
cout << "Event callback:" << msg << endl;
}
}
bool OnVerifyCertificate(bool preverified, boost::asio::ssl::verify_context &ctx)
{
// The verify callback can be used to check whether the certificate that is
// being presented is valid for the peer. For example, RFC 2818 describes
// the steps involved in doing this for HTTPS. Consult the OpenSSL
// documentation for more details. Note that the callback is called once
// for each certificate in the certificate chain, starting from the root
// certificate authority.
// In this example we will simply print the certificate's subject name.
char subject_name[256];
X509 *cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);
std::cout << "Verifying " << subject_name << "\n";
return preverified;
}
boost::asio::io_service io_service;
boost::asio::io_service::work work(io_service); // io_service如果没有用这个work托管,直接run(),在没有任务的时候会自动退出
void ThreadFun(boost::asio::io_service* pIoService)
{
cout << "run io_service..." << endl;
try
{
io_service.run();
}
catch (std::exception &e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
cout << "io_service run end" << endl;
}
int main(int argc, char** argv)
{
boost::thread thread(boost::bind(ThreadFun, &io_service));
TcpClientPtr clientPtr(new TcpClient(&io_service));
clientPtr->SetEventCallBack(boost::bind(OnEvent, clientPtr, _1, _2));
clientPtr->SetReadDataCallBack(boost::bind(OnRead, clientPtr, _1, _2, _3));
clientPtr->SetSslContext("ca.crt", "client.crt", "client.key", true, boost::bind(OnVerifyCertificate, _1, _2));
clientPtr->AsyncConnect("192.168.56.101", 6532);
string str;
while (cin >> str)
{
clientPtr->AsyncWrite(str.c_str(), str.size());
}
return 0;
}
关于编译
因为boost是支持ssl的,但是要包含openssl的头文件以及相应的库,windows下要包含动态库的导入库(libeay32.lib,ssleay32.lib)和运行时动态库(ssleay32.dll,libeay32.dll),linux下需要包含openssl相关的so库(libssl.so)。因此要先编译好openssl库才能使用
GitHub 加速计划 / li / linux-dash
10.39 K
1.2 K
下载
A beautiful web dashboard for Linux
最近提交(Master分支:1 个月前 )
186a802e
added ecosystem file for PM2 4 年前
5def40a3
Add host customization support for the NodeJS version 4 年前
更多推荐
已为社区贡献5条内容
所有评论(0)