本次创建一个c++ 的websocket客户端,不依赖于其他库
头文件#ifndef _WS_CLIENT_H
#define _WS_CLIENT_H
#ifdef _WIN32
#define _CRT_SECURE_NO_WARNINGS
#define WIN32_LEAN_AND_MEAN
#include
#include
#include
#pragma comment( lib, "ws2_32" )
#include
#include
#include
#include
#include
#ifndef _SSIZE_T_DEFINED
typedef int ssize_t;
#define _SSIZE_T_DEFINED
#endif
#ifndef _SOCKET_T_DEFINED
typedef SOCKET socket_t;
#define _SOCKET_T_DEFINED
#endif
#ifndef snprintf
#define snprintf _snprintf_s
#endif
#include
#define socketerrno WSAGetLastError()
#define SOCKET_EAGAIN_EINPROGRESS WSAEINPROGRESS
#define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK
#else
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifndef _SOCKET_T_DEFINED
typedef int socket_t;
#define _SOCKET_T_DEFINED
#endif
#ifndef INVALID_SOCKET
#define INVALID_SOCKET (-1)
#endif
#ifndef SOCKET_ERROR
#define SOCKET_ERROR (-1)
#endif
#define closesocket(s) ::close(s)
#include
#define socketerrno errno
#define SOCKET_EAGAIN_EINPROGRESS EAGAIN
#define SOCKET_EWOULDBLOCK EWOULDBLOCK
#endif
#include
#include
#include
#include
#include
using namespace std;
typedef void(*callback_message_recv)(void * pUser,
const char * message, int len, int type);
#define ws_text 1
#define ws_binary 2
typedef enum readyStateValues
{
CLOSING,
CLOSED,
CONNECTING,
OPEN
}readyStateValues;
class WebSocket
{
struct wsheader_type {
unsigned header_size = 0;
bool fin = true;
bool mask = true;
enum opcode_type {
CONTINUATION = 0x0,
TEXT_FRAME = 0x1,
BINARY_FRAME = 0x2,
CLOSE = 8,
PING = 9,
PONG = 0xa,
} opcode;
int N0 = 0;
uint64_t N = 0;
uint8_t masking_key[4];
};
private:
bool useMask = true;
socket_t sockfd = INVALID_SOCKET;
std::vector rxbuf;
std::vector txbuf;
template
void sendData(wsheader_type::opcode_type type, uint64_t message_size, Iterator message_begin, Iterator message_end);
public:
readyStateValues readyState = OPEN;
// http://tools.ietf.org/html/rfc6455#section-5.2 Base Framing Protocol
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-------+-+-------------+-------------------------------+
// |F|R|R|R| opcode|M| Payload len | Extended payload length |
// |I|S|S|S| (4) |A| (7) | (16/64) |
// |N|V|V|V| |S| | (if payload len==126/127) |
// | |1|2|3| |K| | |
// +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
// | Extended payload length continued, if payload len == 127 |
// + - - - - - - - - - - - - - - - +-------------------------------+
// | |Masking-key, if MASK set to 1 |
// +-------------------------------+-------------------------------+
// | Masking-key (continued) | Payload Data |
// +-------------------------------- - - - - - - - - - - - - - - - +
// : Payload Data continued ... :
// + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
// | Payload Data continued ... |
// +---------------------------------------------------------------+
readyStateValues getReadyState() const {
return readyState;
}
void initSize(int sendsize, int recvsize);
void pollRecv(int timeout);
void sendPing();
void send(const char *message);
void sendBinary(uint8_t *data, int len);
void close();
int connect(const std::string& url);
void dispatch(callback_message_recv callable);
protected:
void pollSend(int timeout);
};
实现cpp
#include "wsclient.h"
#include
#include
socket_t hostname_connect(const std::string& hostname, int port) {
struct addrinfo hints;
struct addrinfo *result;
struct addrinfo *p;
int ret;
socket_t sockfd = INVALID_SOCKET;
char sport[16];
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
snprintf(sport, 16, "%d", port);
if ((ret = getaddrinfo(hostname.c_str(), sport, &hints, &result)) != 0)
{
printf("error get addrinfo\n");
//fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret));
return -1;
}
for (p = result; p != NULL; p = p->ai_next)
{
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (sockfd == INVALID_SOCKET) { continue; }
if (connect(sockfd, p->ai_addr, (int)p->ai_addrlen) != SOCKET_ERROR) {
break;
}
closesocket(sockfd);
sockfd = INVALID_SOCKET;
}
freeaddrinfo(result);
return sockfd;
}
void WebSocket::initSize(int sendsize, int recvsize)
{
if (sendsize == 0)
sendsize = 1024 * 1024 * 2;
if (recvsize == 0)
recvsize = 1024 * 1024 * 2;
rxbuf.reserve(recvsize);
}
void WebSocket::pollSend(int timeout)
{
if (readyState == CLOSED) {
if (timeout > 0) {
timeval tv = { timeout / 1000, (timeout % 1000) * 1000 };
select(0, NULL, NULL, NULL, &tv);
}
return;
}
if (timeout != 0) {
//fd_set rfds;
fd_set wfds;
timeval tv = { timeout / 1000, (timeout % 1000) * 1000 };
//FD_ZERO(&rfds);
FD_ZERO(&wfds);
//FD_SET(sockfd, &rfds);
if (txbuf.size()) { FD_SET(sockfd, &wfds); }
select(sockfd + 1, NULL, &wfds, 0, timeout > 0 ? &tv : 0);
}
while (txbuf.size()) {
int ret = ::send(sockfd, (char*)&txbuf[0], txbuf.size(), 0);
if (ret 0 ? &tv : 0);
}
while (true) {
// FD_ISSET(0, &rfds) will be true
int N = rxbuf.size();
ssize_t ret;
//钱波 64K 一个IP包长
rxbuf.resize(N + 64000);
ret = recv(sockfd, (char*)&rxbuf[0] + N, 64000, 0);
if (false) {}
else if (ret
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?