Skip to content

Commit 517e126

Browse files
committed
update
1 parent 504af9f commit 517e126

File tree

11 files changed

+343
-62
lines changed

11 files changed

+343
-62
lines changed

README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
2+
C++实现的WebSocket协议,但采用的同步通信模型,不是异步的
3+
4+
## 依赖项目
5+
6+
* [tstream](https://github.com/luzhlon/tstream)
7+
8+
## 服务端
9+
10+
```cpp
11+
#include "websocket.h"
12+
13+
int main {
14+
tstream::server ser(5333);
15+
WebSocketHandler h = ser.accept();
16+
if (h) { // Open the connection successfully
17+
cout << "GET " << h.getPath() << endl;
18+
cout << "Host: " << h.getHost() << endl;
19+
cout << "Sec-WebSocket-Key: " << h.getKey() << endl;
20+
cout << "Sec-WebSocket-Protocol: " << h.getSubProtocol() << endl;
21+
while (1) {
22+
if (h.recv())
23+
cout << h.data() << endl,
24+
h.send(h.data()); // send string data
25+
h.send(h.data(), true); // send binary data
26+
getchar();
27+
}
28+
}
29+
return 0;
30+
}
31+
```
32+
33+
## 客户端
34+
35+
未实现

src/base64.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
#include <stdint.h>
3-
#include "base64.h"
3+
#include "base64.hpp"
44

55
// 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1a 0x1b 0x1c 0x1d 0x1e 0x1f 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2a 0x2b 0x2c 0x2d 0x2e 0x2f 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3a 0x3b 0x3c 0x3d 0x3e 0x3f
66
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
File renamed without changes.

src/main.cpp

Lines changed: 0 additions & 37 deletions
This file was deleted.

src/tstream.hpp

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
#ifndef __TSTREAM_H__
2+
#define __TSTREAM_H__
3+
4+
#include <streambuf>
5+
#include <iostream>
6+
7+
#if (defined _WIN32) || (defined _WIN64)
8+
#include <WinSock2.h>
9+
#pragma comment(lib, "ws2_32.lib")
10+
#define __INIT_SOCK_LIB ((tstream *)nullptr)->initsocklib()
11+
#define __CLOSE_SOCKET(S) ::closesocket(S), S = INVALID_SOCKET
12+
#else
13+
#include <sys/socket.h>
14+
#include <netinet/in.h>
15+
#include <netdb.h>
16+
#include <fcntl.h>
17+
#include <unistd.h>
18+
#include <sys/stat.h>
19+
#include <sys/types.h>
20+
#include <arpa/inet.h>
21+
typedef int SOCKET;
22+
//#pragma region define win32 const variable in linux
23+
#define INVALID_SOCKET -1
24+
#define SOCKET_ERROR -1
25+
#define __INIT_SOCK_LIB
26+
#define __CLOSE_SOCKET(S) ::close(S), S = INVALID_SOCKET
27+
//#pragma endregion
28+
#endif
29+
30+
using namespace std;
31+
32+
struct tstream : public iostream {
33+
34+
#if (defined _WIN32) || (defined _WIN64)
35+
void initsocklib() {
36+
static bool inited = false;
37+
WSADATA wsaData;
38+
if (!inited) WSAStartup(MAKEWORD(2, 2), &wsaData);
39+
}
40+
#endif
41+
42+
class tcpbuf : public streambuf {
43+
public:
44+
tcpbuf() {
45+
__INIT_SOCK_LIB;
46+
_sock = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
47+
}
48+
tcpbuf(SOCKET s) { _sock = s; }
49+
tcpbuf(tcpbuf&& other) {
50+
_sock = other._sock;
51+
other._sock = INVALID_SOCKET;
52+
}
53+
~tcpbuf() override { close(); }
54+
55+
bool connect(char *ip, unsigned short port) {
56+
sockaddr_in addr;
57+
memset(&addr, 0, sizeof(addr));
58+
addr.sin_addr.s_addr = inet_addr(ip);
59+
addr.sin_family = AF_INET;
60+
addr.sin_port = ::htons(port);
61+
int ret = ::connect(_sock, (sockaddr *)&addr, sizeof(addr));
62+
return ret != SOCKET_ERROR;
63+
}
64+
int close() { return __CLOSE_SOCKET(_sock); }
65+
66+
int recv(char *buf, size_t len) { return ::recv(_sock, buf, len, 0); }
67+
int send(const char *buf, size_t len) { return ::send(_sock, buf, len, 0); }
68+
69+
protected:
70+
// Unbuffered get
71+
int underflow() override {
72+
return 0;
73+
}
74+
int uflow() override {
75+
uint8_t c;
76+
return recv((char *)&c, sizeof(c)) < 0 ? EOF : c;
77+
}
78+
streamsize xsgetn(char *s, streamsize size) override {
79+
auto need = size;
80+
do {
81+
auto n = recv(s, need);
82+
if (n < 0)
83+
return size - need;
84+
need -= n;
85+
} while (need);
86+
return size;
87+
}
88+
// Unbuffered put
89+
int overflow(int c) override {
90+
if (c == EOF)
91+
return close(), 0;
92+
char b = c;
93+
return send(&b, 1) > 0 ? c : EOF;
94+
}
95+
streamsize xsputn(const char *s, streamsize size) override {
96+
auto need = size;
97+
do {
98+
auto n = send(s, need);
99+
if (n < 0)
100+
return size - need;
101+
need -= n;
102+
} while (need);
103+
return size;
104+
}
105+
// flush
106+
int sync() override {
107+
#if (defined _WIN32) || (defined _WIN64)
108+
return 0;
109+
#else
110+
return flush(_sock);
111+
#endif
112+
}
113+
114+
private:
115+
SOCKET _sock;
116+
117+
};
118+
119+
struct server {
120+
server() {
121+
__INIT_SOCK_LIB;
122+
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
123+
}
124+
// Bind and listen
125+
server(const char *addr, unsigned short port)
126+
: server() {
127+
bind(addr, port); listen();
128+
}
129+
// Bind and listen
130+
server(unsigned short port)
131+
: server() {
132+
bind(port); listen();
133+
}
134+
~server() { close(); }
135+
136+
bool bind(const char *addr, unsigned short port) {
137+
return bind(inet_addr(addr), port);
138+
}
139+
bool bind(int port) { return bind(ADDR_ANY, port); }
140+
bool bind(unsigned long addr, unsigned short port) {
141+
sockaddr_in svraddr;
142+
svraddr.sin_family = AF_INET;
143+
svraddr.sin_addr.s_addr = addr;
144+
svraddr.sin_port = htons(port);
145+
int ret = ::bind(sock, (struct sockaddr*)&svraddr, sizeof(svraddr));
146+
return ret != SOCKET_ERROR;
147+
}
148+
149+
bool listen(int backlog = 5) {
150+
int ret = ::listen(sock, backlog);
151+
return ret != SOCKET_ERROR;
152+
}
153+
154+
tstream accept() {
155+
sockaddr_in cliaddr;
156+
int addrlen = sizeof(cliaddr);
157+
return ::accept(sock,
158+
(struct sockaddr*)&cliaddr, &addrlen);
159+
}
160+
int close() { return __CLOSE_SOCKET(sock); }
161+
162+
SOCKET sock = INVALID_SOCKET;
163+
};
164+
165+
tstream() : iostream(&_buf) {}
166+
tstream(tstream&& s)
167+
: _buf(std::move(s._buf)), iostream(&_buf) {}
168+
tstream(SOCKET sock)
169+
: _buf(sock), iostream(&_buf) {
170+
if (sock == INVALID_SOCKET)
171+
setstate(ios_base::failbit);
172+
}
173+
tstream(char *ip, unsigned short port)
174+
: tstream() { connect(ip, port); }
175+
176+
bool connect(char *ip, unsigned short port) {
177+
if (_buf.connect(ip, port))
178+
return clear(ios_base::goodbit), true;
179+
return clear(ios_base::failbit), true;
180+
}
181+
182+
int close() { return _buf.close(); }
183+
// Raw 'send' function
184+
int send(const char *buf, size_t len) { return _buf.send(buf, len); }
185+
// Raw 'recv' function
186+
int recv(char *buf, size_t len) { return _buf.recv(buf, len); }
187+
188+
template <typename T>
189+
inline int recv2(T& t) { return recv((char *)&t, sizeof(T)); }
190+
template <typename T>
191+
inline tstream& read2(T& t) { read((char *)&t, sizeof(T)); return *this; }
192+
template <typename T>
193+
inline tstream& write2(T& t) { write((const char *)&t, sizeof(T)); return *this; }
194+
195+
private:
196+
tcpbuf _buf;
197+
};
198+
199+
#endif /* __TSTREAM_H__ */

src/websocket.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
#include "websocket.hpp"

src/websocket.h renamed to src/websocket.hpp

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,17 @@
55
#include <regex>
66
#include <stdint.h>
77

8-
#include "../third_party/tstream/src/tstream.h"
8+
#include "tstream.hpp"
99

10-
#include "base64.h"
10+
#include "base64.hpp"
1111
#include "sha1.hpp"
1212

13+
#ifdef _MSC_VER
14+
#define EXPORT __declspec(dllexport)
15+
#else
16+
#define EXPORT
17+
#endif
18+
1319
namespace websocket {
1420
enum OP_CODE {
1521
OP_ADDITIONAL = 0,
@@ -141,33 +147,21 @@ namespace websocket {
141147
uint8_t masking_key[4];
142148
};
143149

144-
class WebSocketHandler {
150+
class EXPORT WebSocketHandler {
145151
public:
146152
// Default as the server
147-
WebSocketHandler(tstream&& ts) : _ts(move(ts)) {}
148-
WebSocketHandler() { isServer(false); }
153+
WebSocketHandler(tstream&& ts)
154+
: _ts(move(ts)) { open(); }
155+
// As the client, uncomplete
156+
WebSocketHandler(const char *addr, uint16_t port) {}
157+
// Move constructor
149158
WebSocketHandler(WebSocketHandler&& other) = default;
150159

151160
bool isServer() { return _server; }
161+
bool isBinary() { return _bin; }
162+
// WebSocketHandler& isBinary(bool b) { _bin = b; return *this; }
152163
// Set the handler to be server-point or client-point
153-
WebSocketHandler& isServer(bool b) {
154-
_server = b;
155-
return *this;
156-
}
157-
// Open, make the connection
158-
bool open() {
159-
_state = STATE_CONNECTING;
160-
// Receive the protocol header
161-
readHeader();
162-
// Find key and response
163-
auto key = getKey();
164-
if (!key.empty()) {
165-
// response header
166-
responseHeader(getResponseKey(key));
167-
return _state = STATE_OPEN, true;
168-
}
169-
return _state = STATE_CLOSED, false;
170-
}
164+
WebSocketHandler& isServer(bool b) { _server = b; return *this; }
171165
// Get the header
172166
const string& header() { return _header; }
173167
// Get the path from header
@@ -201,8 +195,14 @@ namespace websocket {
201195
return _state = STATE_CLOSED, *this;
202196
switch (_frame.getOpcode()) {
203197
case OP_ADDITIONAL:
198+
while (!_frame.FIN())
199+
_frame.recv(_ts, _data);
204200
case OP_TEXT:
201+
_bin = false;
202+
while (!_frame.FIN())
203+
_frame.recv(_ts, _data);
205204
case OP_BINARY:
205+
_bin = true;
206206
while (!_frame.FIN())
207207
_frame.recv(_ts, _data);
208208
break;
@@ -234,6 +234,20 @@ namespace websocket {
234234
operator bool() { return STATE_OPEN == _state; }
235235

236236
private:
237+
// Open, make the connection
238+
bool open() {
239+
_state = STATE_CONNECTING;
240+
// Receive the protocol header
241+
readHeader();
242+
// Find key and response
243+
auto key = getKey();
244+
if (!key.empty()) {
245+
// response header
246+
responseHeader(getResponseKey(key));
247+
return _state = STATE_OPEN, true;
248+
}
249+
return _state = STATE_CLOSED, false;
250+
}
237251
string getResponseKey(const string& key) {
238252
static const char *GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
239253
SHA1 sha(key + GUID);
@@ -272,7 +286,8 @@ namespace websocket {
272286
string _data;
273287
Frame _frame;
274288
READY_STATE _state = STATE_CLOSED;
275-
bool _server = true;
289+
bool _server = true;// as the server role? no mask
290+
bool _bin = false; // last message is binary?
276291
};
277292

278293
}

src/xmake.lua

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
target 'websocket'
3+
set_kind 'static'
4+
add_headers '*.hpp'
5+
add_files '*.cpp'

0 commit comments

Comments
 (0)