在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

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++
    +關注

    關注

    22

    文章

    2117

    瀏覽量

    74854
  • WebSocket
    +關注

    關注

    0

    文章

    30

    瀏覽量

    4048

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

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

收藏 人收藏

    評論

    相關推薦
    熱點推薦

    Django3如何使用WebSocket實現WebShell

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

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

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

    C++教程之函數的遞歸調用

    C++教程之函數的遞歸調用 在執行函數 f 的過程中,又要調用 f 函數本身,稱為函數的遞歸調用;形式上:一個正在執行的
    發表于 05-15 18:00 ?35次下載

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

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

    如何在中斷C函數中調用C++

    之前,我們在單片機程序開發時都會面對中斷函數。眾所周知的,這個中斷函數肯定是要用C函數來定義的。我在用C++進行程序開發的時候就發現了一個需
    發表于 05-09 18:17 ?0次下載
    如何在中斷<b class='flag-5'>C</b><b class='flag-5'>函數</b>中調用<b class='flag-5'>C++</b>

    WebSocket有什么優點

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

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

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

    EE-128:C++中的DSP:從C++調用匯編類成員函數

    EE-128:C++中的DSP:從C++調用匯編類成員函數
    發表于 04-16 17:04 ?2次下載
    EE-128:<b class='flag-5'>C++</b>中的DSP:從<b class='flag-5'>C++</b>調用匯編類成員<b class='flag-5'>函數</b>

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

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

    C++ C語言函數查詢電子版下載

    C++ C語言函數查詢電子版下載
    發表于 01-18 10:15 ?0次下載

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

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

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

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

    C++基礎知識之函數1

    函數C++ 中的一個重要概念,它可以讓我們將一段代碼封裝起來,然后在需要的時候調用它。C++ 中的函數有以下幾個特點: * 函數
    的頭像 發表于 04-03 10:34 ?797次閱讀

    websocket協議的原理

    WebSocket協議是基于TCP的一種新的網絡協議。它實現了瀏覽器與服務器全雙工(full-duplex)通信——允許服務器主動發送信息給客戶端。
    的頭像 發表于 11-09 15:13 ?1642次閱讀
    <b class='flag-5'>websocket</b><b class='flag-5'>協議</b>的原理

    同樣是函數,在CC++中有什么區別

    同樣是函數,在 CC++ 中有什么區別? 第一個返回值。 C語言的函數可以不寫返回值類型,編譯器會默認為返回 int。 但是
    的頭像 發表于 11-29 10:25 ?824次閱讀
    主站蜘蛛池模板: 精品国产中文一级毛片在线看 | 98pao强力打造高清免费 | 四虎影视在线播放 | 国产片91人成在线观看 | 欧洲精品不卡1卡2卡三卡四卡 | 色视频在线看 | 日日噜噜噜噜人人爽亚洲精品 | 曰曰摸天天摸人人看久久久 | 三级欧美在线 | 182tv免费视视频线路一二三 | 91啪在线视频 | 女人张开腿等男人桶免费视频 | 欧美黑人换爱交换乱理伦片 | 午夜精品网站 | 99pao强力打造免费高清色 | 27pao强力打造高清免费高 | 国产理论在线 | 国产在线欧美精品卡通动漫 | 国模在线视频一区二区三区 | 五月天婷婷在线观看高清 | 99免费观看视频 | 狠狠干精品| 国产三级毛片视频 | 九七婷婷狠狠成人免费视频 | 国产女主播在线播放一区二区 | 69xxx网站| 久久综合偷偷噜噜噜色 | 午夜免费r级伦理片 | 7086bt伙计 福利一区 | 综合色综合| 免费一区二区三区 | 手机看片神马午夜 | 高清视频在线观看+免费 | 午夜大片在线观看 | 欧美日韩一区二区三区视频 | 亚洲综合在线观看一区www | 色五婷婷 | 爱爱小视频免费看 | 亚洲天堂视频一区 | 六月丁香六月婷婷 | 丁香激情综合 |