您当前的位置: 首页 >  websocket

qianbo_insist

暂无认证

  • 0浏览

    0关注

    399博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

c++ websocket 客户端

qianbo_insist 发布时间:2021-07-23 22:29:47 ,浏览量:0

本次创建一个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             
关注
打赏
1663161521
查看更多评论
0.0489s