<acronym id="s8ci2"><small id="s8ci2"></small></acronym>
<rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
<acronym id="s8ci2"></acronym>
<acronym id="s8ci2"><center id="s8ci2"></center></acronym>
0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

根據WebSocket協議完全使用C++實現函數

C語言專家集中營 ? 來源:未知 ? 2018-11-28 14:29 ? 次閱讀

由于需要在項目中增加Websocket協議,與客戶端進行通信,不想使用開源的庫,比如WebSocketPP,就自己根據WebSocket協議實現一套函數,完全使用C++實現。

代碼已經實現,放在個人github上面,下面進行解釋說明:

一、原理

Websocket協議解析,可以參考博客http://www.cnblogs.com/jice1990/p/5435419.html,這里就不詳細細說。

服務器端實現就是使用TCP協議,使用傳統的socket流程進行綁定監聽,使用epoll控制多路并發,收到Websocket握手包時候進行握手處理,握手成功便可進行數據收發。

二、實現

1、服務器監聽

該部分使用的是TCP socket流程,首先是通過socket函數建立socket,通過bind函數綁定到某個端口,本例使用的是9000,然后通過listen函數開啟監聽,代碼如下:

listenfd_ = socket(AF_INET, SOCK_STREAM, 0); if(listenfd_ == -1){

DEBUG_LOG("創建套接字失敗!"); return -1; } struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(sockaddr_in)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(PORT); if(-1 == bind(listenfd_, (struct sockaddr *) (&server_addr), sizeof(server_addr))){ DEBUG_LOG("綁定套接字失敗!"); return -1; } if(-1 == listen(listenfd_, 5)){ DEBUG_LOG("監聽失敗!"); return -1; }

2、epoll控制多路并發

該部分使用的是epoll流程,首先在初始化時候使用epoll_create創建epoll句柄

epollfd_ = epoll_create(1024);

然后通過epoll_wait等待fd事件來臨,當監聽到是listenfd事件時候,說明是客戶端連接服務器,就使用accept接受連接,然后注冊該連接EPOLLIN事件,當epoll監聽到EPOLLIN事件時候,即可進行握手和數據讀取。代碼如下:

void ctl_event(int fd, bool flag){ struct epoll_event ev; ev.data.fd = fd; ev.events = flag ? EPOLLIN : 0; epoll_ctl(epollfd_, flag ? EPOLL_CTL_ADD : EPOLL_CTL_DEL, fd, &ev); if(flag){ set_noblock(fd); websocket_handler_map_[fd] = new Websocket_Handler(fd); if(fd != listenfd_) DEBUG_LOG("fd: %d 加入epoll循環", fd); } else{ close(fd); delete websocket_handler_map_[fd]; websocket_handler_map_.erase(fd); DEBUG_LOG("fd: %d 退出epoll循環", fd); } }int epoll_loop(){ struct sockaddr_in client_addr; socklen_t clilen; int nfds = 0; int fd = 0; int bufflen = 0; struct epoll_event events[MAXEVENTSSIZE]; while(true){ nfds = epoll_wait(epollfd_, events, MAXEVENTSSIZE, TIMEWAIT); for(int i = 0; i < nfds; i++){ ? ? ? ? ? if(events[i].data.fd == listenfd_){ ?? ? ? ? ? ? ? fd = accept(listenfd_, (struct sockaddr *)&client_addr, &clilen); ? ? ? ? ? ? ? ?ctl_event(fd, true); ? ? ? ? ? ?} ? ? ? ? ? ?else if(events[i].events & EPOLLIN){ ? ? ?? ? ? ? ? ? ? ?if((fd = events[i].data.fd) < 0) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? continue; ? ? ? ? ? ? ? ?Websocket_Handler *handler = websocket_handler_map_[fd]; ?? ? ? ? ? ? ? if(handler == NULL) ? ? ? ? ? ? ? ? ? ?continue; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if((bufflen = read(fd, handler->getbuff(), BUFFLEN)) <= 0) { ? ? ? ? ? ? ? ?ctl_event(fd, false); ? ? ? ? ? ? ? ?} ? ? ? ? ? ? ? ?else{ ? ? ? ? ? ? ? ? ? ?handler->process(); } } } } return 0; }

3、Websocket握手連接

握手部分主要是根據Websocket握手包進行解析,然后根據Sec-WebSocket-Key進行SHA1哈希,生成相應的key,返回給客戶端,與客戶端進行握手。代碼如下:

//該函數是獲取websocket握手包的信息,按照分割字符進行解析int fetch_http_info(){ std::istringstream s(buff_); std::string request; std::getline(s, request); if (request[request.size()-1] == '\r') { request.erase(request.end()-1); } else { return -1; } std::string header; std::string::size_type end; while (std::getline(s, header) && header != "\r") { if (header[header.size()-1] != '\r') { continue; //end } else { header.erase(header.end()-1); //remove last char } end = header.find(": ",0); if (end != std::string::npos) { std::string key = header.substr(0,end); std::string value = header.substr(end+2); header_map_[key] = value; } } return 0; }//該函數是根據websocket返回包的格式拼接相應的返回包void parse_str(char *request){ strcat(request, "HTTP/1.1 101 Switching Protocols\r\n"); strcat(request, "Connection: upgrade\r\n"); strcat(request, "Sec-WebSocket-Accept: "); std::string server_key = header_map_["Sec-WebSocket-Key"]; server_key += MAGIC_KEY; SHA1 sha; unsigned int message_digest[5]; 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(message_digest),20); server_key += "\r\n"; strcat(request, server_key.c_str()); strcat(request, "Upgrade: websocket\r\n\r\n"); }

4、數據讀取

當服務器與客戶端握手成功后,就可以進行正常的通信,讀取數據了。使用的是TCP協議的方法,解析Websocket包根據協議格式,在前面博客里面有詳細分析,這里只把實現代碼貼出來。

int fetch_websocket_info(char *msg){ int pos = 0; fetch_fin(msg, pos); fetch_opcode(msg, pos); fetch_mask(msg, pos); fetch_payload_length(msg, pos); fetch_masking_key(msg, pos); return fetch_payload(msg, pos); } int fetch_fin(char *msg, int &pos){ fin_ = (unsigned char)msg[pos] >> 7; return 0; }int fetch_opcode(char *msg, int &pos){ opcode_ = msg[pos] & 0x0f; pos++; return 0; }int fetch_mask(char *msg, int &pos){ mask_ = (unsigned char)msg[pos] >> 7; return 0; }int fetch_masking_key(char *msg, int &pos){ if(mask_ != 1) return 0; for(int i = 0; i < 4; i++) ? ? ? ?masking_key_[i] = msg[pos + i]; ? ?pos += 4; ? ?return 0; }int fetch_payload_length(char *msg, int &pos){ ? ?payload_length_ = msg[pos] & 0x7f; ? ?pos++; ? ?if(payload_length_ == 126){ ? ? ? ?uint16_t length = 0; ? ? ? ?memcpy(&length, msg + pos, 2); ? ? ? ?pos += 2; ? ? ? ?payload_length_ = ntohs(length); ? ?} ?? ?else if(payload_length_ == 127){ ? ? ? ?uint32_t length = 0; ? ? ? ?memcpy(&length, msg + pos, 4); ? ? ? ?pos += 4; ? ? ? ?payload_length_ = ntohl(length); ? ?} ?? ?return 0; }int fetch_payload(char *msg, int &pos){ ? ?memset(payload_, 0, sizeof(payload_)); ? ?if(mask_ != 1){ ? ? ? ?memcpy(payload_, msg + pos, payload_length_); ? ?} ?? ?else { ?? ? ? ?for(uint i = 0; i < payload_length_; i++){ ? ? ? ? ? ?int j = i % 4; ? ? ? ? ? ?payload_[i] = msg[pos + i] ^ masking_key_[j]; ? ? ? ?} ? ?} ? ?pos += payload_length_; ?? ?return 0; }

5、總結

到此為止,完整實現了使用C++對Websocket協議進行解析,握手,數據收發,不借助開源庫就實現了websocket相關功能,最大程度的與項目保存兼容。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • C++
    C++
    +關注

    關注

    21

    文章

    2066

    瀏覽量

    72950
  • WebSocket
    +關注

    關注

    0

    文章

    24

    瀏覽量

    3662

原文標題:WebSocket的C++服務器端實現

文章出處:【微信號:C_Expert,微信公眾號:C語言專家集中營】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    Django3如何使用WebSocket實現WebShell

    websocket 服務。 大致看了下覺得這不夠有趣,翻了翻 django 的官方文檔發現 django 原生是不支持 websocket 的,但 django3 之后支持了 asgi 協議可以自己
    的頭像 發表于 11-17 09:58 ?3991次閱讀

    一文詳解WebSocket協議

    在效率和網絡帶寬利用率方面存在諸多問題。WebSocket協議應運而生,對外提供了簡單的雙向數據傳輸能力。
    的頭像 發表于 01-07 11:26 ?1996次閱讀
    一文詳解<b class='flag-5'>WebSocket</b><b class='flag-5'>協議</b>

    關于C++中的函數重載機制

    重載機制是一種"假的"多態.(因為他是在編譯階段就進行分配的機制).另外,C++中還有一種"假的"多態機制就是模板機制,同樣只是改變函數參數的類型,并不會改變函數具體的實現方式.
    發表于 10-01 17:18

    如何完備地實現C++多態性?

    如何完備地實現C++多態性?虛函數怎么使用?
    發表于 04-28 06:44

    上位機通信協議控制電機上位機C++實現上位機6

    常見的上位機通信協議控制電機上位機C++實現上位機6:網絡通訊類CCommnicationC++實現上位機5:實現串口控制類之派生類CSer
    發表于 09-16 06:22

    基于TCP的一種新的網絡協議WebSocket

    開啟 WebSocket 服務WebSocket 服務是網頁程序、安卓 App、微信小程序等獲得數據和服務的接口,是基于TCP 的一種新的網絡協議,它實現了瀏覽器與服務器全雙工通信。通
    發表于 12-16 07:38

    基于C++的modbus通訊協議模型實現

    基于C++的modbus通訊協議模型實現,很好的資料,快來下載學習吧。
    發表于 03-21 17:27 ?54次下載

    WebSocket有什么優點

    WebSocket是一種在單個TCP連接上進行全雙工通信的協議。WebSocket通信協議于2011年被IETF定為標準RFC 6455,并由RFC7936補充規范。
    的頭像 發表于 02-15 15:53 ?8004次閱讀
    <b class='flag-5'>WebSocket</b>有什么優點

    WebSocket工作原理及使用方法

    它有很多名字; WebSocket,WebSocket協議WebSocket API。從首選的消息傳遞應用程序到流行的在線多人游戲,WebSock
    的頭像 發表于 05-05 22:12 ?7585次閱讀
    <b class='flag-5'>WebSocket</b>工作原理及使用方法

    C++之重載函數學習總結

    函數重載是c++對c的一個重要升級;函數重載通過參數列表區分不同的同名函數;extern關鍵字能夠實現c和
    的頭像 發表于 12-24 17:10 ?652次閱讀

    C++中如何用虛函數實現多態

    01 — C++函數探索 C++是一門面向對象語言,在C++里運行時多態是由虛函數和純虛函數
    的頭像 發表于 09-29 14:18 ?1498次閱讀

    函數,C++開發者如何有效利用

    函數是基類中聲明的成員函數,且使用者期望在派生類中將其重新定義。那么,在 C++ 中,什么是虛函數呢?在 C++ 中,通常將虛
    的頭像 發表于 02-11 09:39 ?690次閱讀

    深度解析C++中的虛函數

    函數作為C++的重要特性,讓人又愛又怕,愛它功能強大,但又怕駕馭不好,讓它反咬一口,今天我們用CPU的角度,撕掉語法的偽裝,重新認識一下虛函數。 虛函數
    的頭像 發表于 02-15 11:14 ?615次閱讀
    深度解析<b class='flag-5'>C++</b>中的虛<b class='flag-5'>函數</b>

    鴻蒙上WebSocket的使用方法

    WebSocket 是一種網絡通訊協議,很多網絡開發工作者都需要它。本文介紹在 OpenHarmony 上 WebSocket 協議的使用方法。
    的頭像 發表于 03-08 14:17 ?1071次閱讀

    websocket協議的原理

    WebSocket協議是基于TCP的一種新的網絡協議。它實現了瀏覽器與服務器全雙工(full-duplex)通信——允許服務器主動發送信息給客戶端。
    的頭像 發表于 11-09 15:13 ?487次閱讀
    <b class='flag-5'>websocket</b><b class='flag-5'>協議</b>的原理
    亚洲欧美日韩精品久久_久久精品AⅤ无码中文_日本中文字幕有码在线播放_亚洲视频高清不卡在线观看
    <acronym id="s8ci2"><small id="s8ci2"></small></acronym>
    <rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
    <acronym id="s8ci2"></acronym>
    <acronym id="s8ci2"><center id="s8ci2"></center></acronym>