WebSocket 1 2 3 WebSocket 协议在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了。 它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。
返回的状态码是101,这个东西在看直播的时候非常常见,弹幕八成就是这个东西,个人感觉比心跳包好用一些,减轻了比较多的压力。
简单的编写一个websocket服务端,首先先下载一个websocketd
作为服务端:http://websocketd.com 其实自己写一个也是可以的,但是可能要对这个协议了解深入,我这里就不写了,有了这个服务端之后,我们需要指定一个开放的端口号:–port=8888 然后放一个自己写的程序上去。
1 2 3 4 5 6 7 8 9 10 11 12 #include <stdio.h> #include "stdafx.h" #include <Windows.h> int main () { int i; for (i = 1 ; i <= 10 ; i++) { printf ("%d\n" , i); Sleep(3000 ); } return 0 ; }
执行这个软件websocketd.exe --port=8888 test.exe
服务端开启之后。回显:
1 2 Sat, 07 Nov 2020 13:51:30 +0800 | INFO | server | | Serving using application : test.exe Sat, 07 Nov 2020 13:51:30 +0800 | INFO | server | | Starting WebSocket server : ws://XXXXXXX:8888/
这样子就可以了,我们要在前端进行调用的话呢,是很简单的:
1 2 3 4 5 var ws = new WebSocket('ws://127.0.0.1:8888/' );ws.onmessage = function (event ) { console .log(event.data); };
前段时间有个爬虫需求就是写websocket的,然后不得不在应用程序中调用WebSocket,但是在网上找寻C++关于websocket的代码都是一些别人写好了的库,我不太喜欢自己不能控制的东西,出现了问题也不知道如何解决,所以我就自己写了一个websocket的函数作为调用,方便之后的开发,代码会放在文章底部。
先看一下效果: 和在浏览器控制台的效果是一样的。
首先我们包含写好的:Ws.h
#include "Ws.h"
然后定义三个回调函数。
分别是:
websocket连接成功的
websocket断开连接的
websocket收到消息的
1 2 3 4 5 6 7 8 9 10 11 12 void recThread (char * recmessage,WINHTTP_WEB_SOCKET_BUFFER_TYPE rectype) { printf_s("type:%d message:%s\n" ,rectype,recmessage); } void acceptThread () { printf_s("wait message\n" ); } void destoryThread () { printf_s("WebSocket Destory\n" ); }
连接成功和连接失败的回调函数格式就是没有返回值,没有参数,只是通知。 收到消息的回调函数有两个参数,一个是收到的消息,还有一个是消息的类型。 这个消息的类型是一个枚举:
1 2 3 4 5 6 7 typedef enum _WINHTTP_WEB_SOCKET_BUFFER_TYPE { WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE, WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE, WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE, WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE, WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE } WINHTTP_WEB_SOCKET_BUFFER_TYPE;
看看名字就能了解个大半了。
写好回调函数之后就是开启我们的websocket:
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 int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]){ CString url; url.Format(L"ws://127.0.0.1:8888" ); int res = WebSocket(url,recThread,acceptThread,destoryThread); switch (res) { case WEBSOCKET_SUCCESS: printf ("WebSocket success\n" ); break ; case WEBSOCKET_URLPARSEERROR: printf ("Error %u in WinHttpCrackUrl.\n" , GetLastError()); break ; case WEBSOCKET_CONNECTERROR: wprintf(L"WinHttpConnect error :%d\n" ,GetLastError()); break ; case WEBSOCKET_OPENREQUESTERROR: wprintf(L"WinHttpOpenRequest error :%d\n" ,GetLastError()); break ; case WEBSOCKET_SENDREQUESTERROR: wprintf(L"WinHttpSendRequest error :%d\n" ,GetLastError()); break ; case WEBSOCKET_RECVREQUESTERROR: wprintf(L"WinHttpReceiveResponse error :%d\n" ,GetLastError()); break ; case WEBSOCKET_COMPLETEUPGRADEERROR: wprintf(L"WinHttpWebSocketCompleteUpgrade error :%d\n" ,GetLastError()); break ; default : wprintf(L"error\n" ); break ; } system("pause" ); return res; }
参数很简单,就是一个URL地址,然后将我们的三个回调函数传递进去就可以了。 WebSocket函数返回代表了WebSocket的状态,可以通过GetLastError获取错误信息。 这里的话呢还是有一个功能需要注意的,就是我们有的时候是需要给服务端发消息的,这个你们可以在websocket函数内部进行添加,使用类似的语句:
1 tmpMyWinHttpWebSocketSend(hWebSocket,WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE,"wker" ,strlen ("wker));
其实在些这个websocket的时候出现了一个问题,我在文章的顶部写到,是2008年出现的ws,2011年正式的,但是我用的VS是2010的,所以lib库里面根本没有ws的相关函数,并且在winhttp.h
中没有定义相关的结构和函数,所以实际上我的VS并不支持我编写websocket的相关功能,所以我不得不自己定义websocket的相关函数,然后从系统的dll文件中拉取ws相关的函数:
1 2 3 4 5 6 7 8 9 MyWinHttpWebSocketCompleteUpgrade tmpWinHttpWebSocketCompleteUpgrade; MyWinHttpWebSocketReceive tmpMyWinHttpWebSocketReceive; MyWinHttpWebSocketClose tmpMyWinHttpWebSocketClose; MyWinHttpWebSocketSend tmpMyWinHttpWebSocketSend; HMODULE hmodle = LoadLibrary(L"winhttp.dll" ); tmpWinHttpWebSocketCompleteUpgrade = (MyWinHttpWebSocketCompleteUpgrade)GetProcAddress(hmodle,"WinHttpWebSocketCompleteUpgrade" ); tmpMyWinHttpWebSocketReceive = (MyWinHttpWebSocketReceive)GetProcAddress(hmodle,"WinHttpWebSocketReceive" ); tmpMyWinHttpWebSocketClose = (MyWinHttpWebSocketClose)GetProcAddress(hmodle,"WinHttpWebSocketClose" ); tmpMyWinHttpWebSocketSend = (MyWinHttpWebSocketSend)GetProcAddress(hmodle,"WinHttpWebSocketSend" );
如果在高版本的VS中出现重定义的情况,那么就把我在头文件中的定义删除掉,然后将tmpMy的函数替换成他的函数就可以了。 winhttp.dll在Windows环境变量目录下,所以直接就可以用。