c++实现websocket服务端与JavaScript通讯
来源:互联网 发布:战争雷霆手机数据库 编辑:程序博客网 时间:2024/05/22 13:16
c++实现websocket服务端与JavaScript通讯
注意点如下:
- 首先的理解什么是websocket,这里不做描述
- 清楚websocket的交互协议
目录
用 [TOC]
来生成目录:
- c实现websocket服务端与JavaScript通讯
- 目录
- 握手协议和协议的解析
- 一首先来建一个普通的socket
- 二握手协议
- 三工作线程处理客户端响应信息的字节码
- 四最后就是响应客户端了
- 五最后就是响应客户端了
握手协议和协议的解析
很多资料里面有详细的介绍websocket的握手协议,这里我就不多说了,直接上代码吧。
一、首先来建一个普通的socket
void Initsocket(){ WORD imgrequest; WSADATA wsadata; imgrequest = MAKEWORD(1, 1); int err; err = WSAStartup(imgrequest, &wsadata); if (!err){ printf("服务已经启动\n"); }else{ printf("服务未启动\n"); return; } SOCKET sersocket = socket(AF_INET, SOCK_STREAM, 0); SOCKADDR_IN addr; addr.sin_family = AF_INET; addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //ip地址 addr.sin_port = htons(8899); //绑定端口 bind(sersocket, (SOCKADDR*)&addr, sizeof(SOCKADDR));//绑定完成 listen(sersocket, 10); //其中第二个参数代表能够接收的最多的连接数 SOCKADDR_IN clientsocket; int len = sizeof(SOCKADDR); boolean isConnected = false; int i = 0; while (true){ SOCKET serConn = accept(sersocket, (SOCKADDR*)&clientsocket, &len); printf("客户端连接\n"); //我这里起了一个线程来处理协议 HANDLE hThread1 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WorkThread, (LPVOID)serConn, 0, 0); if (hThread1 != NULL) { CloseHandle(hThread1); } Sleep(1000); closesocket(serConn); }}
二、握手协议
/*获取key和协议*/void requestInfo(SOCKET sockClient, char * request){ char recev[1024] = ""; recv(sockClient, recev, 2048, 0); //cout << recev << endl; string s = recev; int i = s.find("Sec-WebSocket-Key"); s = s.substr(i + 19, 24); //以上是为了得到客户端请求信息的key,关于key的作用可以去了解握手协议 //以下是服务器拼接协议返回给客户端 getKey(request,s);}/*协议这个过程就是拿到客户端的key然后经过sha加密,再拼接返回的协议发给客户端*/void getKey(char *request, string clientkey){ strcat(request, "HTTP/1.1 101 Switching Protocols\r\n"); strcat(request, "Connection: upgrade\r\n"); strcat(request, "Sec-WebSocket-Accept: "); string server_key = clientkey; server_key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; SHA1 sha; unsigned int message_digest[5]; cout <<"server_key:"<< server_key << endl; sha.Reset(); sha << server_key.c_str(); sha.Result(message_digest); for (int i = 0; i < 5; i++) { message_digest[i] = htonl(message_digest[i]); } server_key = base64_encode(reinterpret_cast<const unsigned char*>(message_digest), 20); server_key += "\r\n"; strcat(request, server_key.c_str()); strcat(request, "Upgrade: websocket\r\n\r\n"); cout << "shalserver_key:" << server_key << endl;}
三、工作线程处理客户端响应信息的字节码
/*工作线程*/void WorkThread(SOCKET sockClient){ char request[1024] = ""; //请求信息 char clieninfo[2048]= ""; //握手后响应信息 int len = 0; //返回的长度 int point = 0; //字节指针位置 int tmppoint = 0; //临时指针变量 //握手协议 requestInfo(sockClient, request); respondInfo(sockClient, request); //以上是握手协议 //握手协议结束后,也就是服务返回给客户端后,客户端再一次返回 //数据给服务器,下面就是解析客户端的返回数据 //将数据全部读取出来 len=recv(sockClient, clieninfo, 2048, 0); string ss = clieninfo; cout << "数据长度\n:"<<len <<"乱码数据:"<< ss << endl; if (len>0){ /*这里b字节数组是客户端的请求信息,需要注意point这个指针的变化,具体需要去理解它的协议,协议中每段字节里面包含了什么信息需要把 它解析出来*/ byte b[4096] = ""; //转为字节来处理 memcpy(b, clieninfo, 2048); cout << "字节数据:" << b << endl; for (int i = 0; i <= 33; i++){ printf("%d\t", b[i]); } printf("\n"); //取第一个字节 int first = b[point] & 0xFF; printf("第一个:%d,%d,%d\n", point, b[point], first); byte opCode = (byte)(first & 0x0F); //0000 1111 后四位为opCode 00001111 if (opCode == 8){ closesocket(sockClient); } //取第二个字节 first = b[++point]; //负载长度 int payloadLength = first & 0x7F; printf("第二个:%d,[%d],%d\n", point, b[point], payloadLength); if (payloadLength == 126) { byte extended[2] = ""; extended[0] = b[++point]; extended[1] = b[++point]; int shift = 0; payloadLength = 0; for (int i = 2- 1; i >= 0; i--) { payloadLength = payloadLength + ((extended[i] & 0xFF) << shift); shift += 8; } }else if (payloadLength == 127) { byte extended[8] = ""; tmppoint = ++point; //保存临时指针 point = --point; for (int i = 0; i < 8;i++){ extended[i] = b[tmppoint + i]; point++; } int shift = 0; payloadLength = 0; for (int i = 8 - 1; i >= 0; i--) { payloadLength = payloadLength + ((extended[i] & 0xFF) << shift); shift += 8; } } //非126和127置回来 if ((payloadLength != 126) || (payloadLength != 127)){ point = 1; } cout << "负载长度:" << payloadLength << endl; //第三个字节,掩码 byte mask[4] = ""; tmppoint = ++point; //因为自增了一次,这里需要减掉 point = --point; //取掩码值 for (int i = 0; i < 4; i++){ mask[i] = b[tmppoint + i]; point++; printf("第三mask个:%d,[%d],%d\t\n", point, mask[i], payloadLength); } byte changeb[4096] = ""; //内容的长度保留,循环里面已经被改变 int length = payloadLength; int readThisFragment = 1; //通过掩码计算真实的数据 while (payloadLength > 0){ int maskbyte = b[++point]; int index = (readThisFragment - 1) % 4; maskbyte = maskbyte ^ (mask[index] & 0xFF); changeb[readThisFragment-1] = (byte)maskbyte; printf("内容:%d,[%d],%d\n", point, maskbyte, readThisFragment); payloadLength--; readThisFragment++; } char a[4096] = "1231"; byte test[1024] = ""; memcpy(test, a, strlen(a)); Sleep(5000);//这里是模拟处理其他事情 //响应客户端 //respondClient(sockClient, changeb, length, true); respondClient(sockClient, test, strlen(a), true); //打印客户端的数据 char charb[4096] = ""; memcpy(charb, changeb, length); //charb[length] = 0; for (int i = 0; i < length;i++){ printf("%d\t", charb[i]); } printf("%d\n"); string s = charb; cout << "客户端数据:" << s << endl; //closesocket(sockClient); }}/*发送协议*/void respondInfo(SOCKET sockClient, char * request){ send(sockClient, request, strlen(request), 0);}
四、最后就是响应客户端了
/*给客户端发送数据也需要进行加密处理,就是保持通讯协议*/void respondClient(SOCKET sockClient, byte charb[],int length, boolean finalFragment){ byte buf[1024] = ""; int first = 0x00; int tmp = 0; if (finalFragment) { first = first + 0x80; first = first + 0x1; } buf[0] = first; tmp = 1; cout <<"数组长度:"<< length << endl; unsigned int nuNum = (unsigned)length; if (length < 126) { buf[1] = length; tmp = 2; }else if (length < 65536) { buf[1] = 126; buf[2] = nuNum >> 8; buf[3] = length & 0xFF; tmp = 4; }else { //数据长度超过65536 buf[1] = 127; buf[2] = 0; buf[3] = 0; buf[4] = 0; buf[5] = 0; buf[6] = nuNum >> 24; buf[7] = nuNum >> 16; buf[8] = nuNum >> 8; buf[9] = nuNum & 0xFF; tmp = 10; } for (int i = 0; i < length;i++){ buf[tmp+i]= charb[i]; printf("要发送的数据字节:%d\n", charb[i]); } char charbuf[1024] = ""; memcpy(charbuf, buf, length + tmp); send(sockClient, charbuf, 1024, 0);}
五、最后就是响应客户端了
非常简单的测试代码
(function(){ var $ = function(id){return document.getElementById(id) || null;} var wsServer = 'ws://127.0.0.1:8080'; var ws = new WebSocket(wsServer); var isConnect = false; ws.onopen = function (evt) { onOpen(evt) }; ws.onclose = function (evt) { onClose(evt) }; ws.onmessage = function (evt) { onMessage(evt) }; ws.onerror = function (evt) { onError(evt) }; function onOpen(evt) { console.log("连接服务器成功"); isConnect = true; } function onClose(evt) { //console.log("Disconnected"); } function onMessage(evt) { console.log('Retrieved data from server: ' + evt.data); } function onError(evt) { //console.log('Error occured: ' + evt.data); } function sendMsg() { if(isConnect){ ws.send('hello'); } }})();
0 0
- c++实现websocket服务端与JavaScript通讯
- Java Websocket实例【服务端与客户端实现全双工通讯】
- android与服务端websocket通讯示例
- [C#] WebSocket 客户端+服务端 轻松实现
- webSocket与html区别,以及服务端与客户端消息通讯利用webSocket
- socket实现服务端与客户端的通讯
- WebSocket 服务端实现
- C# 实现WebSocket服务端
- Java WebSocket服务端实现
- websocket实现语音通讯
- [C#] 使用WebSocket进行通讯
- Websocket服务端实现的方法
- WebSocket 协议及服务端实现
- C# 实现WebSocket服务端实例
- Linux C 服务端同时与多个客户端进行通讯
- java socket与 c socket通讯 java服务端
- iOS websocket 及时通讯实现
- C++ socket编程 实现服务端与客户端的通讯
- myeclipse设置tab键两个空格
- 关于热修复
- RNN与反向传播算法(BPTT)的理解
- 【Hibernate】——由持久化和映射文件创建表
- 入门训练 Fibonacci数列
- c++实现websocket服务端与JavaScript通讯
- 《iPhone 4开发基础教程》读书笔记
- Android 系列 4.4使用Intent.putExtra()推送字符串值
- JavaScript中的window.open()打开一个新的网页
- POJ3280——Cheapest Palindrome(动态规划)
- Android逆向中的常用调试方法和使用代码总结
- linux c头文件#include<sys/types.h>和#include<fcntl.h>头文件总结
- TSMessages,非HUD风格的iOS提示框
- 15 个 Android 通用流行框架大全