websocketc語言
❶ 用c語言寫一個http頭文件查找函數。
#include <stdio.h>
char * xxx(char *all, char *target){
int i,j,k;
static char t[80];
j = strlen(all);
k = strlen(target);
printf("j=%d k=%d\n",j,k);
for (i=0;i<j-k-1;i++){
if (strncmp(&all[i],target,k)==0) { sscanf( &all[i+k+1],"%s",t);
printf("t = %s\n",t);
break;}
}
return t;
}
main(){
char all[]="GET / HTTP/1.1 Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3 Sec-WebSocket-Key: mHCYmHhGCn44x+g6quuzYg== Cache-Control: no-cache";
char txt[]="Sec-WebSocket-Key:";
char trs[80];
printf("%s",xxx(all,txt));
}
---------
注意 char all[]=" ...." ; 寫在1行,或通過文件讀入。
char txt[]="Sec-WebSocket-Key:"; 字元串里的冒號不要漏掉,
若不寫冒號,計算sscanf位置 時要再加1。sscanf( &all[i+k+2],"%s",t);
❷ 如何使用WebSocket
引擎支持最新的WebSocket Version 13。
在C++中使用
詳細代碼可參考引擎目錄下的/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/WebSocketTest.cpp文件。
頭文件中的准備工作
首先需要include WebSocket的頭文件。
#include "network/WebSocket.h"
cocos2d::network::WebSocket::Delegate定義了使用WebScocket需要監聽的回調通知介面。使用WebSocket的類,需要public繼承這個Delegate。
class WebSocketTestLayer : public cocos2d::Layer, public cocos2d::network::WebSocket::Delegate
並Override下面的4個介面:
virtual void onOpen(cocos2d::network::WebSocket* ws);
virtual void onMessage(cocos2d::network::WebSocket* ws, const cocos2d::network::WebSocket::Data& data);
virtual void onClose(cocos2d::network::WebSocket* ws);
virtual void onError(cocos2d::network::WebSocket* ws, const cocos2d::network::WebSocket::ErrorCode& error);
後面我們再詳細介紹每個回調介面的含義。
新建WebSocket並初始化
WebSocket.org 提供了一個專門用來測試WebSocket的伺服器"ws://echo.websocket.org"。 測試代碼以鏈接這個伺服器為例,展示如何在Cocos2d-x中使用WebSocket。
新建一個WebSocket:
cocos2d::network::WebSocket* _wsiSendText = new network::WebSocket();
init第一個參數是delegate,設置為this,第二個參數是伺服器地址。 URL中的"ws://"標識是WebSocket協議,加密的WebSocket為"wss://".
_wsiSendText->init(*this, "ws://echo.websocket.org")
WebSocket消息監聽
在調用send發送消息之前,先來看下4個消息回調。
onOpen
init會觸發WebSocket鏈接伺服器,如果成功,WebSocket就會調用onOpen,告訴調用者,客戶端到伺服器的通訊鏈路已經成功建立,可以收發消息了。
void WebSocketTestLayer::onOpen(network::WebSocket* ws)
{
if (ws == _wsiSendText)
{
_sendTextStatus->setString("Send Text WS was opened.");
}
}
onMessage
network::WebSocket::Data對象存儲客戶端接收到的數據, isBinary屬性用來判斷數據是二進制還是文本,len說明數據長度,bytes指向數據。
void WebSocketTestLayer::onMessage(network::WebSocket* ws, const network::WebSocket::Data& data)
{
if (!data.isBinary)
{
_sendTextTimes++;
char times[100] = {0};
sprintf(times, "%d", _sendTextTimes);
std::string textStr = std::string("response text msg: ")+data.bytes+", "+times;
log("%s", textStr.c_str());
_sendTextStatus->setString(textStr.c_str());
}
}
onClose
不管是伺服器主動還是被動關閉了WebSocket,客戶端將收到這個請求後,需要釋放WebSocket內存,並養成良好的習慣:置空指針。
void WebSocketTestLayer::onClose(network::WebSocket* ws)
{
if (ws == _wsiSendText)
{
_wsiSendText = NULL;
}
CC_SAFE_DELETE(ws);
}
onError
客戶端發送的請求,如果發生錯誤,就會收到onError消息,游戲針對不同的錯誤碼,做出相應的處理。
void WebSocketTestLayer::onError(network::WebSocket* ws, const network::WebSocket::ErrorCode& error)
{
log("Error was fired, error code: %d", error);
if (ws == _wsiSendText)
{
char buf[100] = {0};
sprintf(buf, "an error was fired, code: %d", error);
_sendTextStatus->setString(buf);
}
}
send消息到伺服器
在init之後,我們就可以調用send介面,往伺服器發送數據請求。send有文本和二進制兩中模式。
發送文本
_wsiSendText->send("Hello WebSocket, I'm a text message.");
發送二進制數據(多了一個len參數)
_wsiSendBinary->send((unsigned char*)buf, sizeof(buf));
主動關閉WebSocket
這是讓整個流程變得完整的關鍵步驟, 當某個WebSocket的通訊不再使用的時候,我們必須手動關閉這個WebSocket與伺服器的連接。close會觸發onClose消息,而後onClose裡面,我們釋放內存。
_wsiSendText->close();
在Lua中使用
詳細代碼可參考引擎目錄下的/samples/Lua/TestLua/Resources/luaScript/ExtensionTest/WebProxyTest.lua文件。
創建WebSocket對象
腳本介面相對C++要簡單很多,沒有頭文件,創建WebSocket對象使用下面的一行代碼搞定。 參數是伺服器地址。
wsSendText = WebSocket:create("ws://echo.websocket.org")
定義並注冊消息回調函數
回調函數是普通的Lua function,4個消息回調和c++的用途一致,參考上面的說明。
local function wsSendTextOpen(strData)
sendTextStatus:setString("Send Text WS was opened.")
end
local function wsSendTextMessage(strData)
receiveTextTimes= receiveTextTimes + 1
local strInfo= "response text msg: "..strData..", "..receiveTextTimes
sendTextStatus:setString(strInfo)
end
local function wsSendTextClose(strData)
print("_wsiSendText websocket instance closed.")
sendTextStatus = nil
wsSendText = nil
end
local function wsSendTextError(strData)
print("sendText Error was fired")
end
Lua的消息注冊不同於C++的繼承 & Override,有單獨的介面registerScriptHandler。 registerScriptHandler第一個參數是回調函數名,第二個參數是回調類型。 每一個WebSocket實例都需要綁定一次。
if nil ~= wsSendText then
wsSendText:registerScriptHandler(wsSendTextOpen,cc.WEBSOCKET_OPEN)
wsSendText:registerScriptHandler(wsSendTextMessage,cc.WEBSOCKET_MESSAGE)
wsSendText:registerScriptHandler(wsSendTextClose,cc.WEBSOCKET_CLOSE)
wsSendText:registerScriptHandler(wsSendTextError,cc.WEBSOCKET_ERROR)
end
send消息
Lua中發送不區分文本或二進制模式,均使用下面的介面。
wsSendText:sendString("Hello WebSocket中文, I'm a text message.")
主動關閉WebSocket
當某個WebSocket的通訊不再使用的時候,我們必須手動關閉這個WebSocket與伺服器的連接,以釋放伺服器和客戶端的資源。close會觸發cc.WEBSOCKET_CLOSE消息。
wsSendText:close()
在JSB中使用
詳細代碼可參考引擎目錄下的/samples/Javascript/Shared/tests/ExtensionsTest/NetworkTest/WebSocketTest.js文件。
創建WebSocket對象
腳本介面相對C++要簡單很多,沒有頭文件,創建WebSocket對象使用下面的一行代碼搞定。 參數是伺服器地址。
this._wsiSendText = new WebSocket("ws://echo.websocket.org");
設置消息回調函數
JSB中的回調函數是WebSocket實例的屬性,使用匿名函數直接賦值給對應屬性。可以看出JS語言的特性,讓綁定回調函數更加優美。四個回調的含義,參考上面c++的描述。
this._wsiSendText.onopen = function(evt) {
self._sendTextStatus.setString("Send Text WS was opened.");
};
this._wsiSendText.onmessage = function(evt) {
self._sendTextTimes++;
var textStr = "response text msg: "+evt.data+", "+self._sendTextTimes;
cc.log(textStr);
self._sendTextStatus.setString(textStr);
};
this._wsiSendText.onerror = function(evt) {
cc.log("sendText Error was fired");
};
this._wsiSendText.onclose = function(evt) {
cc.log("_wsiSendText websocket instance closed.");
self._wsiSendText = null;
};
send消息
發送文本,無需轉換,代碼如下:
this._wsiSendText.send("Hello WebSocket中文, I'm a text message.");
發送二進制,測試代碼中,使用_stringConvertToArray函數來轉換string為二進制數據,模擬二進制的發送。 new Uint16Array創建一個16位無符號整數值的類型化數組,內容將初始化為0。然後,循環讀取字元串的每一個字元的Unicode編碼,並存入Uint16Array,最終得到一個二進制對象。
_stringConvertToArray:function (strData) {
if (!strData)
returnnull;
var arrData = new Uint16Array(strData.length);
for (var i = 0; i < strData.length; i++) {
arrData[i] = strData.charCodeAt(i);
}
return arrData;
},
send二進制介面和send文本沒有區別,區別在於傳入的對象,JS內部自己知道對象是文本還是二進制數據,然後做不同的處理。
var buf = "Hello WebSocket中文,\0 I'm\0 a\0 binary\0 message\0.";
var binary = this._stringConvertToArray(buf);
this._wsiSendBinary.send(binary.buffer);
主動關閉WebSocket
當某個WebSocket的通訊不再使用的時候,我們必須手動關閉這個WebSocket與伺服器的連接,以釋放伺服器和客戶端的資源。close會觸發onclose消息。
onExit: function() {
if (this._wsiSendText)
this._wsiSendText.close();
}
❸ vc怎麼載入websocket
就是一組已經完成的協議,調用new WebSocket(url)與伺服器握手,WebSocket.send()發送信息,onmessage事件處理得到的消息,很簡單的 附:伺服器端就不好做了,可以參考一下Torando(一個python語言的伺服器,支持websocket)
❹ 如何理解 TCP/IP,SPDY,WebSocket 三者之間的關系
我也不知道····只好復制一份···共同學習~~ 要寫網路程序就必須用Socket,這是程序員都知道的。而且,面試的時候,我們也會問對方會不會Socket編程?一般來說,很多人都會說,Socket編程基本就是listen,accept以及send,write等幾個基本的操作。是的,就跟常見的文件操作一樣,只要寫過就一定知道。對於網路編程,我們也言必稱TCP/IP,似乎其它網路協議已經不存在了。對於TCP/IP,我們還知道TCP和UDP,前者可以保證數據的正確和可靠性,後者則允許數據丟失。最後,我們還知道,在建立連接前,必須知道對方的IP地址和埠號。除此,普通的程序員就不會知道太多了,很多時候這些知識已經夠用了。最多,寫服務程序的時候,會使用多線程來處理並發訪問。我們還知道如下幾個事實:1。一個指定的埠號不能被多個程序共用。比如,如果IIS佔用了80埠,那麼Apache就不能也用80埠了。2。很多防火牆只允許特定目標埠的數據包通過。3。服務程序在listen某個埠並accept某個連接請求後,會生成一個新的socket來對該請求進行處理。於是,一個困惑了我很久的問題就產生了。如果一個socket創建後並與80埠綁定後,是否就意味著該socket佔用了80埠呢?如果是這樣的,那麼當其accept一個請求後,生成的新的socket到底使用的是什麼埠呢(我一直以為系統會默認給其分配一個空閑的埠號)?如果是一個空閑的埠,那一定不是80埠了,於是以後的TCP數據包的目標埠就不是80了--防火牆一定會組織其通過的!實際上,我們可以看到,防火牆並沒有阻止這樣的連接,而且這是最常見的連接請求和處理方式。我的不解就是,為什麼防火牆沒有阻止這樣的連接?它是如何判定那條連接是因為connet80埠而生成的?是不是TCP數據包里有什麼特別的標志?或者防火牆記住了什麼東西?後來,我又仔細研讀了TCP/IP的協議棧的原理,對很多概念有了更深刻的認識。比如,在TCP和UDP同屬於傳輸層,共同架設在IP層(網路層)之上。而IP層主要負責的是在節點之間(End to End)的數據包傳送,這里的節點是一台網路設備,比如計算機。因為IP層只負責把數據送到節點,而不能區分上面的不同應用,所以TCP和UDP協議在其基礎上加入了埠的信息,埠於是標識的是一個節點上的一個應用。除了增加埠信息,UPD協議基本就沒有對IP層的數據進行任何的處理了。而TCP協議還加入了更加復雜的傳輸控制,比如滑動的數據發送窗口(Slice Window),以及接收確認和重發機制,以達到數據的可靠傳送。不管應用層看到的是怎樣一個穩定的TCP數據流,下面傳送的都是一個個的IP數據包,需要由TCP協議來進行數據重組。所以,我有理由懷疑,防火牆並沒有足夠的信息判斷TCP數據包的更多信息,除了IP地址和埠號。而且,我們也看到,所謂的埠,是為了區分不同的應用的,以在不同的IP包來到的時候能夠正確轉發。TCP/IP只是一個協議棧,就像操作系統的運行機制一樣,必須要具體實現,同時還要提供對外的操作介面。就像操作系統會提供標準的編程介面,比如Win32編程介面一樣,TCP/IP也必須對外提供編程介面,這就是Socket編程介面--原來是這么回事啊!在Socket編程介面里,設計者提出了一個很重要的概念,那就是socket。這個socket跟文件句柄很相似,實際上在BSD系統里就是跟文件句柄一樣存放在一樣的進程句柄表裡。這個socket其實是一個序號,表示其在句柄表中的位置。這一點,我們已經見過很多了,比如文件句柄,窗口句柄等等。這些句柄,其實是代表了系統中的某些特定的對象,用於在各種函數中作為參數傳入,以對特定的對象進行操作--這其實是C語言的問題,在C++語言里,這個句柄其實就是this指針,實際就是對象指針啦。現在我們知道,socket跟TCP/IP並沒有必然的聯系。Socket編程介面在設計的時候,就希望也能適應其他的網路協議。所以,socket的出現只是可以更方便的使用TCP/IP協議棧而已,其對TCP/IP進行了抽象,形成了幾個最基本的函數介面。比如create,listen,accept,connect,read和write等等。現在我們明白,如果一個程序創建了一個socket,並讓其監聽80埠,其實是向TCP/IP協議棧聲明了其對80埠的佔有。以後,所有目標是80埠的TCP數據包都會轉發給該程序(這里的程序,因為使用的是Socket編程介面,所以首先由Socket層來處理)。所謂accept函數,其實抽象的是TCP的連接建立過程。accept函數返回的新socket其實指代的是本次創建的連接,而一個連接是包括兩部分信息的,一個是源IP和源埠,另一個是宿IP和宿埠。所以,accept可以產生多個不同的socket,而這些socket里包含的宿IP和宿埠是不變的,變化的只是源IP和源埠。這樣的話,這些socket宿埠就可以都是80,而Socket層還是能根據源/宿對來准確地分辨出IP包和socket的歸屬關系,從而完成對TCP/IP協議的操作封裝!而同時,放火牆的對IP包的處理規則也是清晰明了,不存在前面設想的種種復雜的情形。明白socket只是對TCP/IP協議棧操作的抽象,而不是簡單的映射關系,這很重要!
❺ websocket和socket可以互聯嗎
可以的
Socket 其實並不是一個協議。它工作在 OSI 模型會話層(第5層),是為了方便大家直接使用更底層協議(一般是 TCP 或 UDP )而存在的一個抽象層。
最早的一套 Socket API 是 Berkeley sockets ,採用 C 語言實現。它是 Socket 的事實標准,POSIX sockets 是基於它構建的,多種編程語言都遵循這套 API,在 JAVA、Python 中都能看到這套 API 的影子。
❻ C 實現的 WebSocket 伺服器握手失敗
WebSocket是HTML5開始提供的一種瀏覽器與伺服器間進行全雙工通訊的網路技術。在WebSocketAPI中,瀏覽器和伺服器只需要做一個握手的動作,然後,瀏覽器和伺服器之間就形成了一條快速通道。兩者之間就直接可以數據互相傳送。
❼ 有沒有比較易用的c++ websocket庫
就C++語言層面以及標准庫不提供WebSocket的API支持
可以依賴以下列的第三方實現
Webkit
客戶端
API實現必須你自己從源碼提取出來用
QtWebkits
客戶端/服務端
需Qt Framework支持
Wt
客戶端/服務端
依賴Boost asio
libwebsockets
客戶端/服務端
屬於C Lib, 調用簡單,文檔清晰 你可以自己封裝C++的Spec
還有很多第三方的實現, 可以自行網路
❽ websocket 怎麼實現消息隊列
列印1到5的階乘值。
int fac(int n)
{static int f=1;
f=f*n;
return(f);
}
main()
{int i;
for(i=1;i<=5;i++)
printf("%d!=%d\n",i,fac(i));
}
8.9.4 register變數
為了提高效率,C語言允許將局部變數得值放在CPU中的寄存器中,這種變數叫「寄存器變數」,用關鍵字register作聲明。
❾ c++ websocketpp 怎麼用
首先:在我們是要使用C++搭配現有的函數庫來開發的,所以不太適合使用一般的網站伺服器方案;而在稍微評估了一下後,後來是決定使用「WebSocket++」這個函數庫,來做為C++環境的WebSocket Server開發方案。
WebSocket++的官方網站是:http://www.zaphoyd.com/websocketpp,他是採用BSD License的OpenSource、跨平台函數庫,文件則都放在Github上(網頁)。他目前最新的版本是0.3.x,在Github上要切換到「experimental」這個brahch;而這個版本的WebSocket++基本上是使用C++11以及Boost C++ Libraries里的ASIO(官網)來實作的Header -Only的函數庫,所以在使用前不需要特別去建置這個函數庫、只要在需要時去include他的Header檔就可以了,相當地方便。
然後在WebSocket 的功能方面,他除了有提供Server 端的功能外,也可以用來開發Client 端的程序,算是相當地完整;雖然他的板號還在0.3,好像還很新,不過實際上功能應該算是夠用了~
1.文件准備
如果要使用WebSocket++ 的話,基本上就是先到GitHub 上0.3.x 這個分支:https://github.com/zaphoyd/websocketpp/tree/experimental去把文件下載下來。而下載下來的文件裡面,「websocketpp」這個文件夾,就是要使用這個函數庫時,所有需要的文件了~而文件的部分,則是要連到他的網頁(鏈結)去看,內容不算很完整,Heresy算是看著范常式序和原始碼寫出來的;這點算是Heresy覺得這個函數庫做的比較差一點的地方,不過考慮到現在還是0.3版,也就不要要求太多了。
另外,由於他是基於Boost ASIO來開發網路的功能,所以也必須要下載Boost C++ Libraries來使用;Boost的官方網站是:http://www.boost.org/。
而如果有需要用到TLS的加密連線的話,應該是會需要使用OpenSSL這個函數庫(官網);如果不打算做加密連線的話,基本上是可以跳過這個函數庫的。(Heresy沒試過這部分)
2.基本概念
WebSocket++的基本使用說明,可以參考《Building a program with WebSocket++》這份文件。Heresy這邊算是整理一下,自己玩過後的想法。
首先,要使用WebSocket++ 來開發程序的時候,基本上要include 兩種文件,一種是用來做組態設置(config)的,一種則是用來決定要開發的程序的腳色類型(Role)的。
Role
在Role 的部分,主要就是分成Server 和Client 兩種;Server 就是用來開發WebSocket 伺服器的,而Client 則是可以用來開發C++ 的WebSocket 的用戶端程序、連線到其他的??WebSocket Server 做數據的存取。
如果要建立Server 端的程序的話,就是要include server 用的header 檔:
#include <websocketpp/server.hpp>
而之後則是就可以建立出websocketpp::server<>的物件,拿來做操作。
如果是要建立Client 端程序的話,則是要include client 的header 檔:
#include <websocketpp/client.hpp>
之後則是建立出websocketpp::client<>的物件來做連線。
而WebSocket++的server或client這兩種類別,都是template的class,在建立時也需要指定要使用的config才可以。
Config
Config 的部分,WebSocket++ 主要提供了三種類型:
config::core
config::asio
config::asio_tls
上面這三種類型,在WebSocket++是不同的結構,,config::core基本上是提供有限功能的設置,相對的他只會用到C++11的功能。而config::asio則是使用Boost ASIO做基礎來提供完整的功能;config::asio_tls則是config::asio再加上TLS的連線加密功能。
而根據組合的不同,不同的config也需要include websocketpp/config的目錄下、不同的header檔:
Server
Client
core
core.hpp
core_client.hpp
asio
asio_no_tls.hpp
asio_no_tls_client.hpp
asio_tls
asio.hpp
asio_client.hpp
而如果是以要建立一個使用Boost ASIO、沒有TLS加密的Server的話,基本上就是要include
asio_no_tls.hpp
#include <websocketpp/config/asio_no_tls.hpp>
其他的組合,也可以依此類頂。
Endpoint
在決定要include 哪兩個文件後,接下來就可以在程序裡面,建立出需要使用的WebSocket++ 物件了。
如果是要建立使用Boost ASIO、沒有TLS 加密的Server 的話,基本上要include 的文件就是:
#include <websocketpp/server.hpp>
#include <websocketpp/config/asio_no_tls.hpp>
而在控制用的物件的部分,則就是:
websocketpp:: server <websocketpp::config:: asio > mServer;
之後,所有的功能就都是針對mServer這個物件進行操作。而在WebSocket++裡面,則是把它稱為「endpoint」;通過組合出不同的endpoint,就可以實作不同的功能了。
Server 的範例
基本上,因為Heresy的目的是要建立一個WebSocket Server讓網頁來連線,所以這邊就只講Server的部分了~而實際上,在《Building a program with WebSocket++》里,官方就有提供一個很簡單的使用範例了~他的源代碼如下:
#include <iostream>
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
typedef websocketpp:: server <websocketpp::config:: asio > server ;
void on_message(websocketpp:: connection_hdl hdl , server :: message_ptr msg )
{
std::cout << msg ->get_payload() << std::endl;
} int main()
{ server print_server;
print_server.set_message_handler(&on_message);
print_server.init_asio();
print_server. listen(9002);
print_server.start_accept(); print_server.run ();
}
在這個範例裡面,他是通過websocketpp:: server <websocketpp::config:: asio >這個Endpoint,來建立一個使用Boost ASIO、沒有TLS加密的WebSocket Server。這個server程序在執行後,會持續去監聽port 9002,當有信息傳遞進來的時候,就會觸發到on_message()這個函數、並把接到的信息輸出到命令提示字元的窗口上。
如果想要測試連線的話,可以考慮用 WebSocket.org 提供的
不過實際上,由於WebSocket++ 本身也有log 的功能,所以除了收到的信息會被輸出之外,還有很多紀錄用的信息,也都會被輸出在畫面上,看起來可能會有點雜亂就是了。
另外,由於這個范常式序,只會從client接收信息,並不會傳送數據給Server端,所以Echo Text的Log裡面,並不會像連到ws:// echo.websocket.org
在源代碼的地方,首先就是建立出一個endpoint的server物件print_server,用來做後續的操作。
而在建立出print_server後,接下來要做的事情,包括了:
初始化ASIO
調用init_asio()這個函數,初始化內部的Boost ASIO的io_service(官網),作為後續網路連線等功能之使用。
設置連接埠
調用listen()這個函數,指定要監聽的連接埠;這邊是設置成9002。
而如果系統上有多個網卡的話,默認會監聽所有的網路介面;如果需要的話也可以特別指定要針對哪個介面做監聽。
開始接受連線
調用start_accept()開始接受輸入。
進入主循環
調用run(),進入WebSocket++ Server的主循環。
之後程序就會進入主循環,直到Server 被停下來。
那要怎麼處理連線進來的信息呢?WebSocket++是通過提供各種「Handler」(callback function),來做事件的處理;在官方網站上,有列出可以使用的handler列表(頁面)。
而在這個範例里,則是通過set_message_handler(),來設置當Server收到信息時,要執行的callback function,這里就是on_message()這個函數;這也是一般來說,一定會用到的callback function 。
而message handler 的callback function,會收到兩個數據:
一個是websocketpp::connection_hdl型別的數據,是用來識別目前的連線用的;如果之後要傳送信息給client的話,就必須要通過這個物件,來設置要把信息傳送給誰。而如果有需要的話,也可以藉由server<>的get_con_fromhdl()來取得觸發這個 ??事件的連線、以及他的資訊。
第二個資訊,則是websocketpp::server<>::message_ptr,裡面儲存的是傳遞進來的信息。一般來說,這會通過他的get_payload()函數,來取得傳遞進來的信息,而得到的數據,會是const string&。不過由於WebSocket也有可能是傳遞非文字的binary數據,所以可能會需要通過 get_opcode()這個函數,來辨別傳遞進來的數據的形式。
而在這個範例裡面,on_message()這個函數,就是很單純地把街道的資訊,通過iostream做輸出了~
在網頁上的這個範例裡面,這個Server只有做接收的功能,並不會送信息給Client端。那如果要送信息給client端要怎麼做呢?基本上就是調用server<>的send()這個函數就可以了。
在官方的example文件夾里,有個echo_server的目錄,裡面的echo_server.cpp
而他送出數據的方法,就是:
s->send(hdl, msg->get_payload(), msg->get_opcode());
這邊可以看到,要調用sned()這個函數來傳遞數據,基本上是需要給他三個參數:
websocketpp::connection_hdl的物件,讓Server知道是要傳給哪個client。
要傳遞的數據,這邊就是直接把收到的信息(msg->get_payload())再傳出去;實際上send()有提供不同的介面,實際的數據型別可以是const void*或const string&。
最後,則是要有一個opcode,來指定要傳 ??遞的資訊的形式;如果是純文字的話,基本上可以直接指定websocketpp::frame::opcode::TEXT。
而這個范常式序在執行後,如果一樣使用 WebSocket.org 的 來測試的話,就可以發現他的功能和 WebSocket.org 測試用的 ws://echo.websocket.org
Windows / Visual Studio 上的問題
上面基本上就是WebSocket++ 使用上的基本用法。不過實際上,這樣的源代碼,在Heresy 這邊的Windows + Visual Studio 2010 / 2012,都是沒辦法正確建置的。
最主要的問題,基本上應該算是VC++ 本身對Boost C++ Library 的支援性問題吧…在Heresy 測試的結果是發現,如果希望在VisualStudio 2010 或2012 上使用的WebSocket++ 的話,有部分的功能??必須要強制讓WebSocket++ 去使用C++ 11 的內建函數庫,而不要去使用Boost 的版本。
設置的方法,可以參考官方的《C++11 Support》這頁。以Heresy這邊的測試來說,至少functional和memory兩個函數庫,是需要使用C++11 STL的版本才行的;也就是說,必須要加上_WEBSOCKETPP_CPP11_MEMORY_和_WEBSOCKETPP_CPP11_FUNCTIONAL_這兩個定義(因為MSVC不支援完整的C++11,所以不能直接用_WEBSOCKETPP_CPP11_STL_)。
但是,在加上這兩個定義後,實際上會產生另一個問題,那就是std::min()和巨集版本的min()沖到的問題(參考);這個問題,比較簡單的方法,就是在再額外定義一個NOMINMAX,來取消掉巨集版本的min()和max()了。
所以,實際上要讓上面的程序可以正常運作,一個方法就是在原始碼的一開始、include WebSocket++ 的Header 之前,先加上下面三行:
#define NOMINMAX
#define _WEBSOCKETPP_CPP11_FUNCTIONAL_
#define _WEBSOCKETPP_CPP11_MEMORY_
或是在VC的專案屬性的「組態屬性」裡面,找到「C/C++」的「前置處理器」,在「前置處理氣定義」的欄位裡面,加上「NOMINMAX;_WEBSOCKETPP_CPP11_FUNCTIONAL_;_WEBSOCKETPP_CPP11_MEMORY_」了。
理論上,這兩種方法應該都可以讓MSVC可以正確地建置上面的范常式序。而這個問題Heresy也有回報給作者了(鏈結),就看之後有沒有辦法修正吧。
另外,Heresy在使用Visual Studio 2012的時候,雖然可以正確編譯了,可是在執行階段,則是會當掉。稍微追了一下源代碼後,發現應該是Visual Studio 2012的std::strftime()這個函數(MSDN)有問題所造成的。
主要的問題是發生在 logger/ basic.hpp這個文件,裡面定義的get_timestamp()這個函數裡面有透 ??過std::strftime()來列印出目前的時間,以做為紀錄之用;而他定義的輸出字串,則是一個長度30的C字串buffer。
由於他有試著輸出時區的資訊(%z),而在Visual Sutdio里,如果在台灣的環境的話,他會是一個「台北標准時間」這樣的文字;而這樣的文字,再加上前面的時間資訊的會,就導致整個結果會超過30個字元。而在這個狀況下,Visual Studio 2010隻是會無法輸出,但是在Visual Studio 2012,卻可能是讓程序整個當掉… orz
而解決方法呢?基本上應該是兩種,一個是把buffer的大小改大、例如把它改成40(要改兩個地方,一個是105行、一個是111行,參考),這樣可以讓字串夠長、不會出問題;另一種方法,則是把105行里定義的時間格式字串「"%Y-%m-%d %H:%M:%S%z"」,最後面的「%z」拿掉,這樣就不會去處理時區的資訊,也就比較不容易出問題了。
最後:這篇大概就這樣了。內容,算是對WebSocket++ 的極簡單介紹的~實際上,由於官方文件實在不足,所以學習起來有點累;不過,至少已經成功地用WebSocket++ 完成第一個WebSocket 的Server 端程序了~接下來,看看有什麼特殊的想法,會再做補充吧。
❿ c語言連接websocket伺服器怎麼實現
當一般的socket來連接
~