本程序是VC++实现windows上程序内嵌WebSocket的部分代码,因为想让浏览器和本地程序直接交互,最好的办法就是websocket,windows的exe程序内嵌一个websocket服务器端程序,浏览器访问localhost,建立交互,这种办法比做成插件更好,所以我采用这种办法来联通桌面程序和浏览器。VC++实现WebSocket的服务器代码,网上还是有示例的,不过基本上不能用,我找到的两个,一个是基于MinGW编译,还有一个是基于VC++2010编译的,还有一个libwebsocket,C语言实现的库,实在是大的惊人,最后,我决定自己实现,实现WebSocket其实不复杂,在普通的socket的服务器上添加一个握手协议,这个握手协议如果用脚本语言实现,非常简单,但用户C++实现就不容易了,我这里实现的基本上是C语言的版本,因为不想使用C++庞大的类库和模板。
完整的windows版本socket握手实现:
bool WebSocket::handshake(const char* src, struct handshake* hs){ size_t src_len = strlen(src), i = 0 ; hs->resource = match_string(src, "GET ", 0x20); // 提取空格之前 hs->host = match_string(src, "Host: ", '\0'); hs->origin = match_string(src, "Origin: ", '\0'); hs->protocol = match_string(src, "Sec-WebSocket-Protocol: ", '\0'); hs->key1 = match_string(src, "Sec-WebSocket-Key1: ", '\0'); hs->key2 = match_string(src, "Sec-WebSocket-Key2: ", '\0'); char key3[8]="\0"; // 获取 key3,即最后的8位字符 for (i = 0; i < 8; i++) key3[i] = src[src_len-8+i]; char digits1[64]="\0", digits2[64]="\0", c='\0'; size_t spaces1 = 0, spaces2 = 0; size_t key1_len = strlen(hs->key1); size_t key2_len = strlen(hs->key2); short d1 = 0, d2 = 0; unsigned int result1, result2; for (i = 0; i < key1_len; i++){ c = hs->key1[i]; if (c == 0x20) spaces1++; else if(c>='0' && c<='9') digits1[d1++]=c; } for (i = 0; i < key2_len; i++){ c = hs->key2[i]; if (c == 0x20) spaces2++; else if(c>='0' && c<='9') digits2[d2++]=c; } result1 = (unsigned int) (strtoul(digits1, NULL, 10) / spaces1); result2 = (unsigned int) (strtoul(digits2, NULL, 10) / spaces2); char chrkey1[4]="\0", chrkey2[4]="\0"; for (i = 0; i < 4; i++) chrkey1[i] = result1 << (8 * i) >> (8 * 3); for (i = 0; i < 4; i++) chrkey2[i] = result2 << (8 * i) >> (8 * 3); unsigned char raw[16]="\0", dig[16]="\0"; // raw 表示未md5之前的字符串,规则就是前4位key1中的数字/空格数的整数值, // 连接上key2的最后连接上头信息中的最后8位字符。 memcpy(raw, chrkey1, 4); memcpy(&raw[4], chrkey2, 4); memcpy(&raw[8], key3, 8); //计算的md5值 md5_state_t state; md5_init(&state); md5_append(&state, raw, 16); md5_finish(&state, dig); char handshake_str[BUFSIZ]; memset(handshake_str, 0x00, BUFSIZ); char* handshakeFormat = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" "Upgrade: WebSocket\r\n" "Connection: Upgrade\r\n" "Sec-WebSocket-Origin: %s\r\n" "Sec-WebSocket-Location: ws://%s%s\r\n" "Sec-WebSocket-Protocol: %s\r\n\r\n"; sprintf(handshake_str, handshakeFormat, hs->origin, hs->host, hs->resource, hs->protocol); free_handshake(hs); // 释放handshake指针,已经不用了! char response[BUFSIZ]; memset(response,0,BUFSIZ); size_t j=0, handshake_len=strlen(handshake_str); for (i = 0; i < handshake_len; i++) response[i] = handshake_str[i]; for (j = 0; j < 16; i++, j++) response[i] = dig[j]; // 这里的clientSocket就是连接好的socket对象了。 int sent = send(clientSocket, response, strlen(response), 0); return sent>0; }
目录结构:
socket/ socket.c md5/ md5.h md5.c
库文件下载位置: http://sourceforge.net/projects/libmd5-rfc/files/ 总共3个文件,
编译命令: gcc socket.c md5/md5.c -o socket.o
GCC 4.3编译通过,执行 ./socket.o 可以看到打出的raw和md5后的字符串信息。 这里使用了一个网友用nodejs写的websocket实现版本,打出详细的头信息,然后复制到程序里,以测试生成的握手字符串是否一样。
// socket.c 代码。
// web-socket example #include <stdio.h> #include <stdlib.h> #include <string.h> #include <inttypes.h> #include "md5/md5.h" // #define BUFSIZ 512 //定义handshake结构体变量 struct handshake { char *resource; char *host; char *origin; char *protocol; char *key1; char *key2; }; //释放握手后不再使用的部分变量 void free_handshake(struct handshake* hs){ if( hs->resource != NULL ) free(hs->resource); if( hs->host != NULL ) free(hs->host); if( hs->origin != NULL ) free(hs->origin); if( hs->protocol != NULL ) free(hs->protocol); if( hs->key1 != NULL ) free(hs->key1); if( hs->key2 != NULL ) free(hs->key2); } // 这里对上一篇的match_string做了点修改, // 增加了一个end参数,这样不必提取出字符串后,再做剔除处理 char* match_string(const char* src, const char* pattern, char end){ char buf[BUFSIZ]; memset(buf, 0, BUFSIZ); size_t src_len = strlen(src); size_t ptn_len = strlen(pattern); unsigned short b=0, p=0, i=0; char c='\0'; for(i=0; i<src_len; i++){ c = src[i]; if(p==ptn_len){ // p==ptn_len 表示正在匹配中 if(c=='\r' || c=='\n' || (end !='\0' && c==end) ) p++; // 匹配结束 else buf[b++]=c; // 匹配到的字符 }else if(p<ptn_len){ // 为达到匹配要求 if(c==pattern[p]) p++; else p=0; } } size_t ret_len = strlen(buf); char *ret_p; if( ret_len>0 ){ ret_p = (char*)calloc(ret_len+1,sizeof(char)); // 加 1 为了存储 '\0' memcpy(ret_p, buf, ret_len); }else ret_p = NULL; return ret_p; } // md5 加密函数,用的是网上一个实现的比较通用的版本。 void md5(const char* src, size_t size, char* digest) { md5_state_t state; md5_init(&state); md5_append(&state, src, size); md5_finish(&state, digest); } void p(char*s, int len){ unsigned short i=0; for(i=0; i<len; i++) printf("%c",s[i]); printf("%c", '\n'); } void handshake(const char* src, struct handshake* hs){ size_t src_len = strlen(src), i = 0 ; hs->resource = match_string(src, "GET ", 0x20); // 提取空格之前 hs->host = match_string(src, "Host: ", '\0'); hs->origin = match_string(src, "Origin: ", '\0'); hs->protocol = match_string(src, "Sec-WebSocket-Protocol: ", '\0'); hs->key1 = match_string(src, "Sec-WebSocket-Key1: ", '\0'); hs->key2 = match_string(src, "Sec-WebSocket-Key2: ", '\0'); // 获取 key3,即最后的8位字符 char key3[8]="\0"; for (i = 0; i < 8; i++) key3[i] = src[src_len - 8 + i]; char digits1[64]="\0", digits2[64]="\0", c='\0'; size_t spaces1 = 0, spaces2 = 0; size_t key1_len = strlen(hs->key1); size_t key2_len = strlen(hs->key2); short d1 = 0, d2 = 0; unsigned int result1, result2; for (i = 0; i < key1_len; i++){ c = hs->key1[i]; if (c == 0x20) spaces1++; else if(c>='0' && c<='9') digits1[d1++]=c; } for (i = 0; i < key2_len; i++){ c = hs->key2[i]; if (c == 0x20) spaces2++; else if(c>='0' && c<='9') digits2[d2++]=c; } result1 = (unsigned int) (strtoul(digits1, NULL, 10) / spaces1); result2 = (unsigned int) (strtoul(digits2, NULL, 10) / spaces2); printf("ch1:%s\nch2:%s\n",digits1, digits2); printf("sp1:%d\nsp2:%d\n",spaces1, spaces2); printf("d1:%d\nd2:%d\n" ,result1, result2); unsigned char chrkey1[4]="\0", chrkey2[4]="\0"; for (i = 0; i < 4; i++) chrkey1[i] = result1 << (8 * i) >> (8 * 3); for (i = 0; i < 4; i++) chrkey2[i] = result2 << (8 * i) >> (8 * 3); printf("ch-key1:"); p(chrkey1,4); for(i=0; i<4;i++)printf("0x%02x ",chrkey1[i]); printf("ch-key2:"); p(chrkey2,4); for(i=0; i<4;i++)printf("0x%02x ",chrkey2[i]); unsigned char raw[16]="\0", dig[16]="\0"; memcpy(raw, chrkey1, 4); memcpy(&raw[4], chrkey2, 4); memcpy(&raw[8], key3, 8); //计算的md5值 printf("\nraw:"); for(i=0; i<16; i++) printf("0x%02x ",raw[i]); md5(raw, 16, dig); printf("\nmd5:"); for(i=0; i<16; i++) printf("0x%02x ",dig[i]); } int main() { unsigned char msg[512] = "GET /pub/chat?q=me HTTP/1.1\r\n\ Upgrade: WebSocket\r\n\ Connection: Upgrade\r\n\ Host: localhost:4400\r\n\ Origin: null\r\n\ Sec-WebSocket-Protocol: my-custom-chat-protocol\r\n\ Sec-WebSocket-Key1: x EO2 59186 4 28\\dY 0+\r\n\ Sec-WebSocket-Key2: 1 9 3 57695W 0\r\n\r\n"; size_t len = strlen(msg); msg[len] =0x1f; msg[len+1]=0xf6; msg[len+2]=0xf3; msg[len+3]=0x3f; msg[len+4]=0xc7; msg[len+5]=0x17; msg[len+6]=0x20; msg[len+7]=0x88; struct handshake hs = {NULL, NULL, NULL, NULL, NULL, NULL}; handshake(msg, &hs); free_handshake(&hs); return 0; }
测试的结果:
raw:0x19 0xbf 0x73 0xa4 0x01 0x27 0x5f 0xff 0x1f 0xf6 0xf3 0x3f 0xc7 0x17 0x20 0x88
md5:0x61 0x30 0x1e 0xe8 0x8a 0x17 0xaf 0x39 0xd6 0xad 0xef 0xb9 0x6f 0x00 0x0f 0x68
对比了nodejs的版本,握手部分生成没有错误。
转自:http://www.kindcent.com/blog/view/vc-plus-plus-websocket-handshake
相关推荐
这个代码例子使用了c c++实现了websocket 开发 包含了websocket服务器和websocket客户端,拥有详细的解释 这个库比libwebsocket更加简单方便,比libsocket更加高效便捷.
利用C++实现了websocket server, 使用libuv作为实现tcp的基础,另外使用gbase作为工具
修改了 一个BUG 直接覆盖吧 博文链接:https://lchshu001.iteye.com/blog/1184428
WebSocket服务器端+Html5客户端,服务器端dotnet framework2.0,3.5,4.0,4.5都支持。
WebSocket服务器端和客户端示例,服务器端程序为.NetFrameWork4.5 WinForm,Websocket客户端示例为html+js(支持所有Websocket客户端)。
这个代码例子使用了c c++实现了websocket 开发 包含了websocket服务器和websocket客户端,拥有详细的解释 这个库比libwebsocket更加简单方便,比libsocket更加高效便捷.
SuperWebSocket是WebSocket协议服务器端的.NET实现. 作为HTML5的一个重要新特性,WebSocket 规范的目标是在浏览器中实现和服务器端双向通信.双向通信可以拓展浏览器上的应用类型,例如实时的数据推送(股票行情),...
(1)建立在 TCP 协议之上,服务器端的实现比较容易。 (2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。 (3)数据格式...
Senparc.WebSocket 为微信小程序等提供独立的WebSocket服务器端环境
使用Qt实现WebSocket客户端与服务端之间的通信,可供初学者学习或使用
netty搭建tcp自定义协议websocket服务器, 支持ssl demo. 适用于netty初学者, netty搭建自定义协议, websocket服务器, 聊天室, 一个端口集成多协议,包括ssl协议
1、建立在 TCP 协议之上,服务器端的实现比较容易。 2、与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。 3、支持双向通信,...
websocket-sharp是WebSocket协议客户端和服务器的C#实现
websocket c++服务器,浏览器握手成功
利用C++ SOCKET编程,自我实现的一个websocket服务器,没有使用开源库,可以适用于学习使用
在网上查的资料,整理了一下 实现了wss协议的连接 和websocket的心跳,,在网上查的资料,整理了一下 实现了wss协议的连接 和websocket的心跳
主要介绍了C#实现WebSocket协议客户端和服务器websocket sharp组件实例解析,包括websocket sharp组件的概念及使用方法,需要的朋友可以参考下
nodejs-websocket 基于node创建websocket服务器 websocket 协议和 http 协议类似,http 协议有一个缺陷,只能由客户方端发起请求,服务端根据请求 url 和传过去的参数返回对应结果 websocket 是双向通信的,只要 ...
该资源用C语言实现的简易websocket测试程序,并附有web端的html页面辅助调试,供websocket学习者下载使用,理解websocket协议