acl  3.5.3.0
websocket.hpp
浏览该文件的文档.
1 /**
2  * Copyright (C) 2015-2018
3  * All rights reserved.
4  *
5  * AUTHOR(S)
6  * niukey@qq.com
7  * shuxin.zheng@qq.com
8  *
9  * VERSION
10  * Sun 18 Sep 2016 05:15:52 PM CST
11  */
12 
13 #pragma once
14 #include "../acl_cpp_define.hpp"
15 #include "../stdlib/noncopyable.hpp"
16 
17 namespace acl
18 {
19 
20 class socket_stream;
21 class aio_socket_stream;
22 
23 enum
24 {
26  FRAME_TEXT = 0x01,
27  FRAME_BINARY = 0x02,
28  FRAME_RSV3 = 0x03,
29  FRAME_RSV4 = 0x04,
30  FRAME_RSV5 = 0x05,
31  FRAME_RSV6 = 0x06,
32  FRAME_RSV7 = 0x07,
33  FRAME_CLOSE = 0x08,
34  FRAME_PING = 0x09,
35  FRAME_PONG = 0x0A,
41 };
42 
44 {
45  bool fin;
46  bool rsv1;
47  bool rsv2;
48  bool rsv3;
49  unsigned char opcode:4;
50  bool mask;
51  unsigned long long payload_len;
52  unsigned int masking_key;
53 
54  frame_header(void) {
55  fin = false;
56  rsv1 = false;
57  rsv2 = false;
58  rsv3 = false;
60  mask = false;
61  payload_len = 0;
62  masking_key = 0;
63  }
64 };
65 
66 class string;
67 
68 /**
69  * websocket 基础类
70  */
72 {
73 public:
74  /**
75  * 构造方法
76  * @param client {socket_stream&}
77  */
78  websocket(socket_stream& client);
79  ~websocket(void);
80 
81  /**
82  * 当类对象被重复使用时,需要通过本方法将状态重重
83  */
84  websocket& reset(void);
85 
86  /**
87  * 获得本类对象所绑定的 socket_stream 对象
88  * @return {socket_stream&}
89  */
91  {
92  return client_;
93  }
94 
95  /**
96  * 设置是否结束的标志位
97  * @param yes {bool}
98  * @return {websocket&}
99  */
100  websocket& set_frame_fin(bool yes);
101 
102  /**
103  * 设置保留标志位
104  * @param yes {bool}
105  * @return {websocket&}
106  */
107  websocket& set_frame_rsv1(bool yes);
108 
109  /**
110  * 设置保留标志位
111  * @param yes {bool}
112  * @return {websocket&}
113  */
114  websocket& set_frame_rsv2(bool yes);
115 
116  /**
117  * 设置保留标志位
118  * @param yes {bool}
119  * @return {websocket&}
120  */
121  websocket& set_frame_rsv3(bool yes);
122 
123  /**
124  * 设置数据帧类型,参见上面定义:FRAME_XXX
125  * @param type {unsigned char}
126  * @return {websocket&}
127  */
128  websocket& set_frame_opcode(unsigned char type);
129 
130  /**
131  * 设置本数据帧数据载体的总长度
132  * @param len {unsigned long long}
133  * @return {websocket&}
134  */
135  websocket& set_frame_payload_len(unsigned long long len);
136 
137  /**
138  * 设置数据帧数据的掩码值,客户端模式下必须设置此项
139  * @param mask {unsigned int}
140  * @return {websocket&}
141  */
142  websocket& set_frame_masking_key(unsigned int mask);
143 
144  /**
145  * 发送数制帧中的数据体,可以循环调用本方法发送本帧的数据,发送数据
146  * 总长度(即多次调用本方法的数据长度之和)应与 set_frame_payload_len
147  * 方法设置的值相同
148  * @param data {const void*}
149  * @param len {size_t}
150  * @return {bool} 发送是否成功
151  */
152  bool send_frame_data(const void* data, size_t len);
153  bool send_frame_data(void* data, size_t len);
154  bool send_frame_data(const char* str);
155  bool send_frame_data(char* str);
156 
157  /**
158  * 发送 PONG 数据帧
159  * @param data {const void*} PONG 数据帧的数据载体,可以为 NULL
160  * @param len {size_t} data 数据长度,当 data 为 NULL 或 len 为 0 时,
161  * 表示没有数据载荷
162  * @return {bool} 发送是否成功
163  */
164  bool send_frame_pong(const void* data, size_t len);
165  bool send_frame_pong(void* data, size_t len);
166  bool send_frame_pong(const char* str);
167  bool send_frame_pong(char* str);
168 
169  /**
170  * 发送 PING 数据帧
171  * @param data {const void*} PING 数据帧的数据载体,可以为 NULL
172  * @param len {size_t} data 数据长度,当 data 为 NULL 或 len 为 0 时,
173  * 表示没有数据载荷
174  * @return {bool} 发送是否成功
175  */
176  bool send_frame_ping(const void* data, size_t len);
177  bool send_frame_ping(void* data, size_t len);
178  bool send_frame_ping(const char* str);
179  bool send_frame_ping(char* str);
180 
181  /**
182  * 调用非阻塞发送接口异步发送数据,当发送完数据后,应用层应该调用
183  * reset() 方法重置状态,在发送一个数据包前,应用层需要调用以上的
184  * set_frame_xxx 方法用来设置每一个数据包的帧头信息
185  * @param conn {aio_socket_stream&}
186  * @param data {void*} 要发送的数据,内部会被修改
187  * @param len {size_t} data 数据长度
188  * @return {bool} 是否出错
189  */
190  bool send_frame_data(aio_socket_stream& conn, void* data, size_t len);
191 
192  /**
193  * 异步发送一个 FRAME_TEXT 类型的数据帧
194  * @param conn {aio_socket_stream&}
195  * @param data {char*}
196  * @param len {size_t}
197  * @return {bool}
198  */
199  bool send_frame_text(aio_socket_stream& conn, char* data, size_t len);
200 
201  /**
202  * 异步发送一个 FRAME_BINARY 类型的数据帧
203  * @param conn {aio_socket_stream&}
204  * @param data {char*}
205  * @param len {size_t}
206  * @return {bool}
207  */
208  bool send_frame_binary(aio_socket_stream& conn, void* data, size_t len);
209 
210  /**
211  * 异步发送一个 FRAME_PING 类型的数据帧
212  * @param conn {aio_socket_stream&}
213  * @param data {char*}
214  * @param len {size_t}
215  * @return {bool}
216  */
217  bool send_frame_ping(aio_socket_stream& conn, void* data, size_t len);
218 
219  /**
220  * 异步发送一个 FRAME_PONG 类型的数据帧
221  * @param conn {aio_socket_stream&}
222  * @param data {char*}
223  * @param len {size_t}
224  * @return {bool}
225  */
226  bool send_frame_pong(aio_socket_stream& conn, void* data, size_t len);
227 
228  /**
229  * 读取数据帧帧头
230  * @return {bool}
231  */
232  bool read_frame_head(void);
233 
234  /**
235  * 读取数据帧数据体,需要循环调用本方法直至正常结束或出错
236  * @param buf {void*} 存放数据的缓冲区
237  * @param size {size_t} buf 数据缓冲区大小
238  * @return {int} 返回值 > 0 表示读到的数据长度需再次读,== 0 表示读结束,
239  * < 0 表示读出错
240  */
241  int read_frame_data(void* buf, size_t size);
242 
243  /**
244  * 用在非阻塞网络通信中,尝试读取 websocket 数据头,可以循环调用本方法
245  * 走到该方法返回 true 表示读到了完整的 websocket 头;如果返回 false,
246  * 则需通过 eof() 方法来判断网络连接是否已经断开,如 eof() 返回 true,
247  * 则应释放本对象
248  * @return {bool} 返回 true 表示读到了完整的 websocket 头,可以通过调用
249  * read_frame_data() 来读取数据体
250  */
251  bool peek_frame_head(void);
252 
253  /**
254  * 用在非阻塞网络通信中,尝试读取 websocket 数据体,可以循环调用本方法
255  * @param buf {char*} 存放读到的数据
256  * @param size {size_t} buf 的空间大小
257  * @return {int} 读到的数据长度,当返回值为:
258  * 0: 表示本帧的数据体读完毕
259  * -1: 表示读出错,需通过调用 eof() 判断连接是否已经关闭
260  * >0: 表示本次读到的数据长度
261  */
262  int peek_frame_data(char* buf, size_t size);
263  int peek_frame_data(string& buf, size_t size);
264 
265  /**
266  * 判断当前是否已读完 websocket 帧头数据
267  * @return {bool}
268  */
269  bool is_head_finish(void) const;
270 
271  /**
272  * 判断当前网络连接是否已经断开
273  * @return {bool}
274  */
275  bool eof(void);
276 
277  /**
278  * 获得读到的数据帧的帧头
279  * @return {const frame_header&}
280  */
281  const frame_header& get_frame_header(void) const
282  {
283  return header_;
284  }
285 
286  /**
287  * 判断本帧是否为结束帧
288  * @return {bool}
289  */
290  bool frame_is_fin(void) const
291  {
292  return header_.fin;
293  }
294 
295  /**
296  * 判断本帧是否设置了保留标志位
297  * @return {bool}
298  */
299  bool frame_is_rsv1(void) const
300  {
301  return header_.rsv1;
302  }
303 
304  /**
305  * 判断本帧是否设置了保留标志位
306  * @return {bool}
307  */
308  bool frame_is_rsv2(void) const
309  {
310  return header_.rsv2;
311  }
312 
313  /**
314  * 判断本帧是否设置了保留标志位
315  * @return {bool}
316  */
317  bool frame_is_rsv3(void) const
318  {
319  return header_.rsv3;
320  }
321 
322  /**
323  * 获得本数据帧的状态码,参见上面:FRAME_XXX
324  * @return {unsigned char}
325  */
326  unsigned char get_frame_opcode(void) const
327  {
328  return header_.opcode;
329  }
330 
331  /**
332  * 获得本数据帧是否设置了掩码
333  * @return {bool}
334  */
335  bool frame_has_mask(void) const
336  {
337  return header_.mask;
338  }
339 
340  /**
341  * 获得本数据帧的数据体长度
342  * @return {unsigned long long}
343  */
344  unsigned long long get_frame_payload_len(void) const
345  {
346  return header_.payload_len;
347  }
348 
349  /**
350  * 获得本数据帧的掩码值
351  * @return {unsigned int}
352  */
353  unsigned int get_frame_masking_key(void) const
354  {
355  return header_.masking_key;
356  }
357 
358  /**
359  * 获得本数据帧已读到的数据长度
360  * @return {unsigned long long}
361  */
362  unsigned long long get_frame_payload_nread(void) const
363  {
364  return payload_nread_;
365  }
366 
367 private:
368  socket_stream& client_;
369  struct frame_header header_;
370  char* header_buf_;
371  size_t header_size_;
372  size_t header_len_;
373  unsigned long long payload_nread_;
374  unsigned long long payload_nsent_;
375  bool header_sent_;
376 
377  unsigned status_;
378  string* peek_buf_;
379 
380  void make_frame_header(void);
381 
382  void update_head_2bytes(unsigned char ch1, unsigned ch2);
383  bool peek_head_2bytes(void);
384  bool peek_head_len_2bytes(void);
385  bool peek_head_len_8bytes(void);
386  bool peek_head_masking_key(void);
387 
388 };
389 
390 } // namespace acl
const frame_header & get_frame_header(void) const
Definition: websocket.hpp:281
unsigned int get_frame_masking_key(void) const
Definition: websocket.hpp:353
socket_stream & get_stream(void) const
Definition: websocket.hpp:90
unsigned long long payload_len
Definition: websocket.hpp:51
bool frame_is_rsv1(void) const
Definition: websocket.hpp:299
bool frame_is_rsv3(void) const
Definition: websocket.hpp:317
unsigned char get_frame_opcode(void) const
Definition: websocket.hpp:326
bool frame_is_rsv2(void) const
Definition: websocket.hpp:308
bool frame_has_mask(void) const
Definition: websocket.hpp:335
unsigned int masking_key
Definition: websocket.hpp:52
unsigned char opcode
Definition: websocket.hpp:49
#define ACL_CPP_API
unsigned long long get_frame_payload_nread(void) const
Definition: websocket.hpp:362
unsigned long long get_frame_payload_len(void) const
Definition: websocket.hpp:344
bool frame_is_fin(void) const
Definition: websocket.hpp:290