C++ WebSocket服务端客户端示例代码

使用过标准的libwebsockets服务端库测试过,主要是短小精悍,相对于libwebsockets不需要依赖zlib和openssl 以及其他库,直接make就可以使用了,linux跟windows都可以使用。

测试用例:

#include "easywsclient.hpp"
#include <assert.h>
#include <stdio.h>
#include <string>

using easywsclient::WebSocket;
static WebSocket::pointer ws = NULL;

void handle_message(const std::string & message)
{
  printf(">>> %s\n", message.c_str());
  if (message == "world") { ws->close(); }
}

int main()
{
  ws = WebSocket::from_url("ws://localhost:8126/foo");
  assert(ws);//判断ws对象是否为空null
  ws->send("goodbye");
  ws->send("hello");
  //如果你需要多线程,可以在一个thread 维护该ws的连接重连机制
  while (ws->getReadyState() != WebSocket::CLOSED) //判断ws是否正常连接
  {
    ws->poll();//这个必须要调用,否则不能发送,发送跟接收都是异步的,都是在这个poll函数里监测处理的
    ws->dispatch(handle_message);
  }
  delete ws;
  return 0;
}
//线程thread  维护重连连接
void run()
{
  bool conn = FLASE;
  ws = WebSocket::from_url("ws://localhost:8126/foo");
 
  //如果你需要多线程,可以在一个thread 维护该ws的连接重连机制
  while (1) //判断ws是否正常连接
  {
    if(ws != NULL)
    {
        ws->poll(0);//这个必须要调用,否则不能发送,发送跟接收都是异步的,都是在这个poll函数里监测处    理的
        ws->dispatch(handle_message);
        if(ws->getReadyState() == WebSocket::CLOSED)  
        {
           //ws连接断开 重连
           delete ws;
           ws = NULL;
           ws = WebSocket::from_url("ws://localhost:8126/foo");
        }
        else if(wss->getReadyState()== WebSocket::OPEN)
        {
           //ws连接ok
           //    ws->send("goodbye");
           ws->send("hello");
        }
        
    }
    else
    {
      ws = WebSocket::from_url("ws://localhost:8126/foo");
      sleep(1);
    }
    usleep(100);
  }
  if(ws!=NULL)
  delete ws;
}

有细心的朋友发现在发送中文GBK 的时候与服务端会断开

//GBK -> UTF-8 
//遇到发送的字符串里有中文的话需要send 前进行转换一下,
//这个是网友提供的在windows下的转换函数
std::string Server_Stream::GBKToUTF8(const std::string& strGBK)
{
std::string strOutUTF8 = "";
WCHAR * str1;
int n = MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), -1, NULL, 0);
str1 = new WCHAR[n];
MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), -1, str1, n);
n = WideCharToMultiByte(CP_UTF8, 0, str1, -1, NULL, 0, NULL, NULL);
char * str2 = new char[n];
WideCharToMultiByte(CP_UTF8, 0, str1, -1, str2, n, NULL, NULL);
strOutUTF8 = str2;
delete[]str1;
str1 = NULL;
delete[]str2;
str2 = NULL;
return strOutUTF8;
}

下面是C++实现的WebSocket客户端,写好后这里记一下,免得以后忘记。

本示例共有三个文件组成,依赖Websocket++第三方库

其中main.cpp是使用示例

#include <iostream>
#include <string>
#include <sstream>

#include "websocket_endpoint.h"

int main(int argc, char **argv)
{
bool done = false;
std::string input;
kagula::websocket_endpoint endpoint;

endpoint.connect("ws://localhost:9002");

while (!done) {
std::cout << "Enter Command: ";
std::getline(std::cin, input);

if (input == "quit") {
 done = true;
}
else if (input.substr(0, 4) == "send") {
 std::stringstream ss(input);

 std::string cmd;
 std::string message;

 ss >> cmd;
 std::getline(ss, message);

 endpoint.send(message);
}
else if (input.substr(0, 4) == "show") {
 endpoint.show();
}
else {
 std::cout << "> Unrecognized Command" << std::endl;
}
}

endpoint.close();

return 0;
}

其它两个文件是封装

websocket_endpoint.h文件清单

#ifndef _WEBSOCKET_ENDPOINT_
#define _WEBSOCKET_ENDPOINT_

#include <string>

/*
Title: Web Socket Client
Author: kagula
Date: 2016-11-21
Dependencies: Websocket++、Boost::ASIO
Test Environment: VS2013 Update5, WebSocket++ 0.70, Boost 1.61
Description:
[1]Support connect a web socket server.
[2]If server is crash, client will not follow crash.
*/

namespace kagula
{
class websocket_endpoint {
public:
websocket_endpoint();
~websocket_endpoint();

int connect(std::string const & uri);
void close();

void send(std::string message);
void show();
};
}

#endif

websocket_endpoint.cpp文件清单

#include <websocketpp/config/asio_no_tls_client.hpp>
#include <websocketpp/client.hpp>

#include <websocketpp/common/thread.hpp>
#include <websocketpp/common/memory.hpp>

#include <cstdlib>
#include <iostream>
#include <map>
#include <string>
#include <sstream>

#include "websocket_endpoint.h"

typedef websocketpp::client<websocketpp::config::asio_client> ws_client;

namespace kagula
{

class connection_metadata {
public:
typedef websocketpp::lib::shared_ptr<connection_metadata> ptr;

connection_metadata(websocketpp::connection_hdl hdl, std::string uri)
 : m_hdl(hdl)
 , m_status("Connecting")
 , m_uri(uri)
 , m_server("N/A")
{}

void on_open(ws_client *client, websocketpp::connection_hdl hdl) {
 m_status = "Open";

 ws_client::connection_ptr con = client->get_con_from_hdl(hdl);
 m_server = con->get_response_header("Server");
}

// if connection failed, the function will be invoke.
void on_fail(ws_client *client, websocketpp::connection_hdl hdl) {
 m_status = "Failed";

 ws_client::connection_ptr con = client->get_con_from_hdl(hdl);
 m_server = con->get_response_header("Server");
 m_error_reason = con->get_ec().message();
}

void on_close(ws_client *client, websocketpp::connection_hdl hdl) {
 m_status = "Closed";
 ws_client::connection_ptr con = client->get_con_from_hdl(hdl);
 std::stringstream s;
 s << "close code: " << con->get_remote_close_code() << " ("
  << websocketpp::close::status::get_string(con->get_remote_close_code())
  << "), close reason: " << con->get_remote_close_reason();
 m_error_reason = s.str();
}

void on_message(websocketpp::connection_hdl, ws_client::message_ptr msg) {
 if (msg->get_opcode() == websocketpp::frame::opcode::text) {
  m_messages.push_back("<< " + msg->get_payload());
 }
 else {
  m_messages.push_back("<< " + websocketpp::utility::to_hex(msg->get_payload()));
 }
}

websocketpp::connection_hdl get_hdl() const {
 return m_hdl;
}

std::string get_status() const {
 return m_status;
}

std::string get_uri() const {
 return m_uri;
}

void record_sent_message(std::string message) {
 m_messages.push_back(">> " + message);
}

friend std::ostream & operator<< (std::ostream & out, connection_metadata const & data);
private:
websocketpp::connection_hdl m_hdl;
std::string m_status;
std::string m_uri;
std::string m_server;
std::string m_error_reason;
std::vector<std::string> m_messages;
};

std::ostream & operator<< (std::ostream & out, connection_metadata const & data) {
out << "> URI: " << data.m_uri << "\n"
 << "> Status: " << data.m_status << "\n"
 << "> Remote Server: " << (data.m_server.empty() ? "None Specified" : data.m_server) << "\n"
 << "> Error/close reason: " << (data.m_error_reason.empty() ? "N/A" : data.m_error_reason) << "\n";
out << "> Messages Processed: (" << data.m_messages.size() << ") \n";

std::vector<std::string>::const_iterator it;
for (it = data.m_messages.begin(); it != data.m_messages.end(); ++it) {
 out << *it << "\n";
}

return out;
}

ws_client g_wsEndPoint;
connection_metadata::ptr g_wsClientConnection;

websocketpp::lib::shared_ptr<websocketpp::lib::thread> g_threadWS;

websocket_endpoint::websocket_endpoint(){
 g_wsEndPoint.clear_access_channels(websocketpp::log::alevel::all);
 g_wsEndPoint.clear_error_channels(websocketpp::log::elevel::all);

 g_wsEndPoint.init_asio();
 g_wsEndPoint.start_perpetual();

 g_threadWS = websocketpp::lib::make_shared<websocketpp::lib::thread>(&ws_client::run, &g_wsEndPoint);
}

websocket_endpoint::~websocket_endpoint() {
g_wsEndPoint.stop_perpetual();

if (g_wsClientConnection->get_status() == "Open") {
 // Only close open connections
 websocketpp::lib::error_code ec;
 g_wsEndPoint.close(g_wsClientConnection->get_hdl(), websocketpp::close::status::going_away, "", ec);
 if (ec) {
  std::cout << "> Error closing ws connection " << g_wsClientConnection->get_uri() << " :" << ec.message() << std::endl;
 }
}

g_threadWS->join();
}

int websocket_endpoint::connect(std::string const & uri) {
websocketpp::lib::error_code ec;

ws_client::connection_ptr pConnection = g_wsEndPoint.get_connection(uri, ec);

if (ec) {
 std::cout << "> Connect initialization error: " << ec.message() << std::endl;
 return -1;
}

g_wsClientConnection = websocketpp::lib::make_shared<connection_metadata>(pConnection->get_handle(), uri);

pConnection->set_open_handler(websocketpp::lib::bind(
 &connection_metadata::on_open,
 g_wsClientConnection,
 &g_wsEndPoint,
 websocketpp::lib::placeholders::_1
 ));
pConnection->set_fail_handler(websocketpp::lib::bind(
 &connection_metadata::on_fail,
 g_wsClientConnection,
 &g_wsEndPoint,
 websocketpp::lib::placeholders::_1
 ));
pConnection->set_close_handler(websocketpp::lib::bind(
 &connection_metadata::on_close,
 g_wsClientConnection,
 &g_wsEndPoint,
 websocketpp::lib::placeholders::_1
 ));
pConnection->set_message_handler(websocketpp::lib::bind(
 &connection_metadata::on_message,
 g_wsClientConnection,
 websocketpp::lib::placeholders::_1,
 websocketpp::lib::placeholders::_2
 ));

g_wsEndPoint.connect(pConnection);

return 0;
}

void close(websocketpp::close::status::value code, std::string reason) {
websocketpp::lib::error_code ec;

g_wsEndPoint.close(g_wsClientConnection->get_hdl(), code, reason, ec);
if (ec) {
 std::cout << "> Error initiating close: " << ec.message() << std::endl;
}
}

void websocket_endpoint::close()
{
if (g_wsClientConnection->get_status()=="Open")
{
 int close_code = websocketpp::close::status::normal;
 kagula::close(close_code, "");
}
} 

void websocket_endpoint::send(std::string message) {
websocketpp::lib::error_code ec;

g_wsEndPoint.send(g_wsClientConnection->get_hdl(), message, websocketpp::frame::opcode::text, ec);
if (ec) {
 std::cout << "> Error sending message: " << ec.message() << std::endl;
 return;
}

g_wsClientConnection->record_sent_message(message);
} 

void websocket_endpoint::show()
{
std::cout << * g_wsClientConnection << std::endl;
}
}

关于C++编写的WebSocket客户端实现示例代码的文章就介绍至此,更多相关C++ WebSocket客户端内容请搜索编程宝库以前的文章,希望大家多多支持编程宝库

在c语言中实参和形参之间的数据传输是单向的“值传递”方式,也就是实参可以影响形参,而形参不能影响实参。指针变量作为参数也不例外,但是可以改变实参指针变量所指向的变量的值。#include <stdio.h> ...