20190506(libwebsockets库使用学习)
目錄
1.libwebsockets庫中回調(diào)函數(shù)里resons部分宏
2. API解釋
3.實現(xiàn)代碼
1.libwebsockets庫中回調(diào)函數(shù)里resons部分宏
關(guān)于libwebsockets庫中回調(diào)函數(shù)里resons部分宏的解釋參考:https://blog.csdn.net/qifengzou/article/details/50281545
回調(diào)函數(shù)原型:
ws_service_callback(strcut lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len)
本人騰訊翻譯(reason):
LWS_CALLBACK_CLIENT_ESTABLISHED
after your client connection completed,a handshake with the remote server.
客戶端連接完成后,與遠(yuǎn)程服務(wù)器進(jìn)行握手。
LWS_CALLBACK_ESTABLISHED
after the server completes a handshake with an incoming client.If you built the library with ssl support,in?is a pointer to the ssl struct associated with the connection or NULL.
服務(wù)器完成與傳入客戶端的握手后,如果構(gòu)建具有SSL支持的庫,*in是指向與連接關(guān)聯(lián)的SSL結(jié)構(gòu)的指針,或者為NULL。
LWS_CALLBACK_CLOSED
when the websocket session ends.
當(dāng)Websocket會話結(jié)束時。
LWS_CALLBACK_CLOSED_HTTP
when a HTTP(non-websocket) session ends
HTTP(非Websocket)會話結(jié)束時
LWS_CALLBACK_CLIENT_CONNECTION_ERROR
the request client connection has been unable to complete a handshake with the remote sever.If in is non-NULL,you can find an error string if length len where it point to?
請求客戶端連接無法完成與遠(yuǎn)程服務(wù)器的握手。如果in為非空,則可以找到錯誤字符串(如果其指向的位置為
LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPODRTED
when a client connection is being prepared to start a handshake to a server,each supported extension is checked with protocols[0] callback with this reason,giving the user code a chance to suppress the claim to support that extension by returning non-zero.If unhandled,by default 0 will be returned and the extension support include in the header to the server.Notice this callback comes to protocols[0].
當(dāng)客戶端連接準(zhǔn)備開始與服務(wù)器握手時,每個支持的擴(kuò)展將根據(jù)protocols[0]回調(diào)函數(shù)中的resaon檢查,從而使用戶代碼有機(jī)會通過返回非零來抑制聲明以支持該擴(kuò)展。如果未處理,默認(rèn)情況下,將返回0,并且擴(kuò)展支持包含在服務(wù)器的報頭中。注意,這個回調(diào)到達(dá)protocols[0]。
LWS_CALLBACK_CLIENT_RECEIVE
data has appeared from the server for the client connection,it is can be found at *in and is len bytes long.
數(shù)據(jù)出現(xiàn)在客戶端連接的服務(wù)器上時,可以在通過*in處找到,長度為len字節(jié)。
LWS_CALLBACK_RECEIVE
data has appeared for this server endpoint from ?a remote client,it is can be found at *in and is len bytes long.
此服務(wù)器端點的數(shù)據(jù)來自遠(yuǎn)程客戶端,可以在*in處找到,長度為len字節(jié)。
LWS_CALLBACK_CLIENT_WRITEABLE
If you call lws_callback_on_writbable() on a connection,you will get one of these callbacks coming when the connection socket is able to accecpt another write packet without blocking.If it already was able to ?take another packet without blocking,you'll get this callback at the next call to the service loop function.
Notice that CLIENTs get LWS_CALLBACK_CLIENT_WRITEABLE?and servers get LWS_CALLBACK_SERVER_WRITEABLE
如果在連接時調(diào)用lws_Callback_on_write(),那么當(dāng)連接套接字能夠不阻塞地訪問另一個寫數(shù)據(jù)包時,您將得到其中一個回調(diào)。如果它已經(jīng)能夠不阻塞地接收另一個數(shù)據(jù)包,那么您將在下一次調(diào)用服務(wù)循環(huán)函數(shù)時得到這個回調(diào)。
請注意,客戶端獲得LWS_CALLBACK_CLIENT_WRITEABLE,而服務(wù)器獲得LWS_CALLBACK_SERVER_WRITEABLE
LWS_CALLBACK_SERVER_WRITEABLE
同上
LWS_CALLBACK_CLIENT_HTTP_WRITEABLE
When ?doing an HTTP type client connection,you can call
lws_clinet_http_body_pending(wsi,i) from
LWS_CALLBACK_CLINET_APPEND_HANDSHAKE_HEADER to get these callbackes sending the HTTP headers.
在進(jìn)行HTTP類型的客戶端連接時,您可以調(diào)用:
Lws_Clinet_http_BODY_PINING(wsiI,i)來自
lws_Callback_Clinet_append_handsh_Header以獲取這些發(fā)送HTTP標(biāo)頭的回調(diào)。
From this callback,when you have sen everything,you should let lws ?know by calling?lws_clinet_http_body_pending(wsi,0)
在這個回調(diào)中,當(dāng)您已經(jīng)完成所有操作時,您應(yīng)該通過調(diào)用lws_clinet_http_body_pending(wsi,0)
LWS_CALLBACK_COMPLETED_CLIENT_HTTP
沒有解釋
LWS_CALLBACK_ESTBLISHED_CLIENT_HTTP
沒有解釋
LWS_CALLBACK_RECEIVE_CLIENT_HTTP
沒有解釋
LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ
沒有解釋
LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER
this callback happens when a client handshake is being compiled. user is NULL, in is a char **,it's pointing to a char * which holds the next location in the header buffer where you can add headers,and len is the remaining sapce in the header buffer,which is typically some hundreds of bytes.So, to add a canned cookie,your handler code might look similar to:
此回調(diào)發(fā)生在編譯客戶端握手時。user為null,in是char **,它指向一個char*,其中包含頭緩沖區(qū)中可以添加頭文件的下一個位置,len是頭文件緩沖區(qū)中的剩余部分,通常為數(shù)百個字節(jié),因此,要添加罐裝cookie,處理程序代碼可能類似于:
Notice if you add anything,you just have to take care about the CRLF in the line you add.Obviously this callback is optional,if you don't handle it everything is fine.
注意,如果您添加任何內(nèi)容,您只需注意您添加的行中的CRLF。顯然,這個回調(diào)是可選的,如果您不處理它,一切都很好。
Notice the callback is coming to protocols[0] all the time,because there is no specific protocol negotiated yet.
請注意,回調(diào)一直指向 protocols[0],因為還沒有經(jīng)過協(xié)商的特定協(xié)議。
2. API解釋
本人騰訊翻譯(API解釋):
void lws_set_log_level(int level, void (*log_emit_function)(int level, const char *line))
lws_set_log_level() - Set the logging bitfield(位域)
lws_set_log_level()-設(shè)置日志位字段(位域)。
param level: OR together the LLL_ debug contexts you want output from
參數(shù)?level:或者一起使用要從其中輸出的LLL_DEBUG上下文。
param log_emit_function: NULL to leave it as it is, or a user-supplied function to perform log string emission instead of the default stderr(標(biāo)準(zhǔn)輸出) one.
參數(shù) LOG_EEMIT_Function:如果保持不變,則為NULL,或者使用用戶提供的函數(shù)來執(zhí)行日志字符串發(fā)射,而不是默認(rèn)的stderr(標(biāo)準(zhǔn)輸出)函數(shù)。
log level defaults to "err", "warn" and "notice" contexts enabled and emission on stderr. If stderr is a tty (according to isatty()) then the output is coloured according to the log level using ANSI escapes.(分級顯示)
日志級別默認(rèn)為“ERR”、“WARN”和“NOTER”上下文已啟用,并在stderr上發(fā)出。如果stderr是tty(根據(jù)isatty(),則根據(jù)日志級別使用ANSI轉(zhuǎn)義對輸出進(jìn)行著色。(分級顯示)
struct lws_context *lws_create_context(struct lws_context_creation_info *info);
lws_create_context() - Create the websocket handler(管理者)
lws_create_context() - 創(chuàng)建WebSocket處理程序(管理者)
param info: pointer to struct with parameters? ?
參數(shù)info:指向帶參數(shù)的結(jié)構(gòu)的指針
This function creates the listening socket (if serving) and takes care of all initialization in one step(創(chuàng)建socket并完成一系列初始化工作)
此函數(shù)創(chuàng)建偵聽套接字(如果提供服務(wù)),并在這一步中處理所有初始化(創(chuàng)建套接字并完成一系列初始化工作)。
If option LWS_SERVER_OPTION_EXPLICIT_VHOSTS is given, no vhost is created; you're expected to create your own vhosts afterwards using lws_create_vhost(). Otherwise a vhost named "default" is also createdusing the information in the vhost-related members, for compatibility(創(chuàng)建vhost,特殊情況調(diào)用lws_create_vhost())
如果給出了選項LWS_SERVER_OPTION_EXPLICIT_VHOSTS,則不會創(chuàng)建vhost;之后需要使用lws_create_vhost()創(chuàng)建自己的vhost。否則,為了兼容性,還會使用vhost相關(guān)成員中的信息創(chuàng)建名為“default”的vhost(創(chuàng)建vhost,特殊情況調(diào)用lws_create_vhost()
After initialization, it returns a struct lws_context * that represents this server.?
初始化后,它返回表示此服務(wù)器的struct lws_context *(比如叫context )。
After calling, user code needs to take care of calling lws_service() with the context pointer to get the server's sockets serviced.?
調(diào)用之后,用戶代碼需要使用上下文指針context調(diào)用lws_service(),以獲得服務(wù)于服務(wù)器的套接字。
This must be done in the same process context as the initialization call.(初始化以后,循環(huán)調(diào)用lws_service()來獲得服務(wù))
這必須在初始化調(diào)用所在的進(jìn)程上下文中完成。(初始化以后,循環(huán)調(diào)用lws_service()來獲得服務(wù))
The protocol callback functions are called for a handful of events including http requests coming in, websocket connections becoming established, and data arriving; it's also called periodically to allow async transmission.(連接,請求發(fā)送,接受消息都會調(diào)用協(xié)議回調(diào)函數(shù),回調(diào)函數(shù)是被周期性調(diào)用的,以便達(dá)到異步傳輸?shù)男Ч?
協(xié)議回調(diào)函數(shù)被調(diào)用來處理一些事件,包括http請求的傳入、WebSocket連接的建立和數(shù)據(jù)的到達(dá);它也被定期調(diào)用以允許異步傳輸。
HTTP requests are sent always to the FIRST protocol in protocol, since at that time websocket protocol has not been negotiated. Other protocols after the first one never see any HTTP callback activity.(HTTP請求只在第一次交互時才會有,這個時候ws還未達(dá)成協(xié)議,之后其它協(xié)議就不需要HTTP頭了)
HTTP請求總是發(fā)送到協(xié)議中的第一個協(xié)議,因為當(dāng)時還沒有協(xié)商WebSocket協(xié)議。第一個協(xié)議之后的其他協(xié)議再不看到任何HTTP回調(diào)活動。
The server created is a simple http server by default; part of the websocket standard is upgrading this http connection to a websocket one.(WS是HTTP服務(wù)的一個濃縮)
默認(rèn)情況下,創(chuàng)建的服務(wù)器是簡單的HTTP服務(wù)器;WebSocket標(biāo)準(zhǔn)的一部分是將此HTTP連接升級到WebSocket連接。(WS是HTTP服務(wù)的一個濃縮)。
This allows the same server to provide files like scripts and favicon images or whatever over http and dynamic data over websockets all inone place; they're all handled in the user callback. (在用戶回調(diào)里面,提供腳本語言,圖片和其它數(shù)據(jù))
這允許相同的服務(wù)器通過http提供諸如腳本和圖標(biāo)圖像之類的文件,并在WebSocket上提供動態(tài)數(shù)據(jù);它們都是在用戶回調(diào)中處理的。(在用戶回調(diào)里面,提供腳本語言,圖片和其它數(shù)據(jù))
int lws_service(struct lws_context *context, int timeout_ms)
polllws_service() - Service any pending(即將發(fā)生的) websocket activity
Pollws_service()-服務(wù)任何掛起的(即將發(fā)生的)WebSocket活動
param context: Websocket context(上下文)
參數(shù)context:WebSocket上下文(上下文)
param ?timeout_ms: 0 means return immediately if nothing needed service otherwise block and service immediately, returning after the timeout if nothing needed service.
參數(shù)Timeout_ms:0表示在沒有任何需要的情況下立即返回服務(wù),否則立即阻止服務(wù),如果沒有任何需要的服務(wù),則在超時后返回。
This function deals with any pending websocket traffic(交互), for three kinds of event. It handles these events on both server and client types of connection the same.
此函數(shù)處理任何掛起的WebSocket通信量(交互),用于三種事件。它處理服務(wù)器和客戶端連接類型相同的這些事件。
1) Accept new connections to our context's server(接受連接)
接受到上下文服務(wù)器的新連接(接受連接)
2) Call the receive callback for incoming frame data received by server or client connections.(消息回調(diào))
對服務(wù)器或客戶端連接接收的傳入幀數(shù)據(jù)調(diào)用接收回調(diào)。(消息回調(diào))
You need to call this service function periodically to all the above functions to happen; if your application is single-threaded you can just call it in your main event loop. (循環(huán)調(diào)用該函數(shù))
您需要定期對所有上述函數(shù)調(diào)用該服務(wù)函數(shù);如果您的應(yīng)用程序是單線程的,您只需在主事件循環(huán)中調(diào)用它。(循環(huán)調(diào)用該函數(shù))
Alternatively you can fork a new process that asynchronously handles calling this service in a loop. In that case you are happy if this call blocks your thread until it needs to take care of something and would call it with a large nonzero timeout. Your loop then takes no CPU while there is nothing happening.(最好重開線程調(diào)用該函數(shù))
或者,您可以派生一個新進(jìn)程,該進(jìn)程在循環(huán)中異步處理調(diào)用此服務(wù)。在這種情況下,如果這個調(diào)用阻塞了您的線程,直到它需要處理一些事情,并且會使用一個很大的非零超時來調(diào)用它,那么您會很高興。當(dāng)什么都沒有發(fā)生的時候,你的循環(huán)就不需要CPU了。(最好重開線程調(diào)用該函數(shù))
If you are calling it in a single-threaded app, you don't want it to wait around blocking other things in your loop from happening, so you would call it with a timeout_ms of 0, so it returns immediately if nothing is pending, or as soon as it services whatever was pending.(超時最好設(shè)為0)
如果您在單線程應(yīng)用程序中調(diào)用它,您不希望它等待阻止您循環(huán)中的其他事情發(fā)生,因此您應(yīng)該使用Timeout_ms為0調(diào)用它,因此如果沒有掛起,它就會立即返回,或者在它為任何掛起的東西提供服務(wù)時立即返回。(超時最好設(shè)為0)
struct lws * lws_client_connect_via_info(struct lws_client_connect_info * ccinfo);
lws_client_connect_via_info() - Connect to another websocket server
lws_client_connect_via_info() -?連接到另一臺websocket服務(wù)器
param ccinfo: pointer to lws_client_connect_info struct
參數(shù)ccinfo:指向lws_client_connect_info結(jié)構(gòu)的指針
This function creates a connection to a remote server using the information provided in ccinfo.
此函數(shù)使用ccinfo中提供的信息創(chuàng)建到遠(yuǎn)程服務(wù)器的連接。
void lws_context_destroy(struct lws_context *context);
lws_context_destroy() - Destroy the websocket context
lws_context_destroy() - 銷毀WebSocket上下文
param context: Websocket context
參數(shù)context:Websocket上下文
This function closes any active connections and then frees the context. After calling this, any further use of the context is undefined
此函數(shù)將關(guān)閉所有活動連接,然后釋放上下文。調(diào)用它之后,上下文的任何進(jìn)一步使用都是未定義的。
?
struct lws_client_connect_info
struct lws_client_connect_info {
struct lws_context *context;/**< lws context to create connection in */要在其中創(chuàng)建連接的LWS上下文
const char *address;/**< remote address to connect to */要連接到的遠(yuǎn)程地址
int port;/**< remote port to connect to */要連接到的遠(yuǎn)程端口
int ssl_connection;/**< nonzero for ssl */SSL非零
const char *path; /**< uri path */URI路徑
const char *host; /**< content of host header */主機(jī)標(biāo)頭的內(nèi)容
const char *origin;/**< content of origin header */原始標(biāo)題的內(nèi)容
const char *protocol;/**< list of ws protocols we could accept */可以接受的ws協(xié)議列表
int ietf_version_or_minus_one; /**< deprecated: currently leave at 0 or -1 */已棄用:當(dāng)前為0或-1
void *userdata;/**< if non-NULL, use this as wsi user_data instead of malloc it */如果不為NULL,則將其用作wsi user_data而不是malloc
const void *client_exts;/**< UNUSED... provide in info.extensions at context creation time */沒用過.。在創(chuàng)建上下文時在info.Extension中提供
const char *method;
/**< if non-NULL, do this http method instead of ws[s] upgrade.如果不為空,請執(zhí)行此http方法,而不是%ws[s]升級。
* use "GET" to be a simple http client connection */使用“get”作為簡單的http客戶端連接
struct lws *parent_wsi;
/**< if another wsi is responsible for this connection, give it here.如果另一個WSI負(fù)責(zé)此連接,請在此處給出。
* this is used to make sure if the parent closes so do any? 這用于確保如果父連接關(guān)閉,則先執(zhí)行子連接
* child connections first. */
const char *uri_replace_from;
/**< if non-NULL, when this string is found in URIs in? ?如果非NULL,則當(dāng)在text/html內(nèi)容編碼中的URI中找到此字符串時,
* text/html content-encoding, it's replaced with uri_replace_to */?它將被替換為uri_place_to const char*uri_place_to;
const char *uri_replace_to;
/**< see uri_replace_from */參見uri替換自
struct lws_vhost *vhost;
/**< vhost to bind to (used to determine related SSL_CTX) */ 要綁定到的vhost(用于確定相關(guān)的SSL_CTX)
struct lws **pwsi;
/**< if not NULL, store the new wsi here early in the connection
* process. Although we return the new wsi, the call to create the
* client connection does progress the connection somewhat and may
* meet an error that will result in the connection being scrubbed and
* NULL returned. While the wsi exists though, he may process a
* callback like CLIENT_CONNECTION_ERROR with his wsi: this gives the
* user callback a way to identify which wsi it is that faced the error
* even before the new wsi is returned and even if ultimately no wsi
* is returned.
*/
如果不為NULL,則在連接過程的早期將新的WSI存儲在此處。盡管我們返回了新的WSI,但是創(chuàng)建客戶機(jī)連接的調(diào)用確實在一定程度上推進(jìn)了連接,并且可能會遇到一個錯誤,該錯誤將導(dǎo)致連接被擦除并返回NULL。但是,當(dāng)WSI存在時,他可以使用WSI處理類似Client_Connection_Error的回調(diào):這為用戶回調(diào)提供了一種方法,以確定即使在返回新的WSI之前(即使最終沒有返回任何ws)面臨錯誤的WSI是哪個WSI。
const char *iface;
/**< NULL to allow routing on any interface, or interface name or IP
* to bind the socket to */
/* Add new things just above here ---^
* This is part of the ABI, don't needlessly break compatibility
*
* The below is to ensure later library versions with new
* members added above will see 0 (default) even if the app
* was not built against the newer headers.
*/
空,允許在任何接口上進(jìn)行路由,或接口名稱或ip將套接字綁定到。
添加新的東西就在這里這是ABI的一部分,不要不必要地破壞兼容性下面是為了確保以后的庫版本與上面添加的新成員將看到0(默認(rèn)),即使應(yīng)用程序不是針對較新的標(biāo)題構(gòu)建的。
void *_unused[4];
};
3.實現(xiàn)代碼
struct session_data {int fd; }; static int ws_service_callback(struct lws *wsi,enum lws_callback_reasons reason, void *user,void *in, size_t len) {switch (reason) {case LWS_CALLBACK_CLIENT_ESTABLISHED:printf("[Main Service] Connect with server success.\n");connection_flag = 1;break;case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:printf("[Main Service] Connect with server error.\n");destroy_flag = 1;connection_flag = 0;break;case LWS_CALLBACK_CLOSED:printf("[Main Service] LWS_CALLBACK_CLOSED\n");destroy_flag = 1;connection_flag = 0;break;case LWS_CALLBACK_CLIENT_RECEIVE:printf("[Main Service] Client recvived:%s\n", (char *)in);if (writeable_flag)destroy_flag = 1;break;case LWS_CALLBACK_CLIENT_WRITEABLE:printf("[Main Service] On writeable is called. send byebye message\n");//websocket_write_back(wsi, "Byebye! See you later", -1);writeable_flag = 1;break;default:break;}return 0; } static lws_context* s_ptContext; static struct lws_protocols protocols[] = {{ "lws-mirror-protocol",ws_service_callback, 0, 1024 * 32 },{ NULL, NULL, 0, 0 } /* end */ }; #define PORT_LEN 8 #define SESSION_LEN 24 string CombineIPAndPort(std::string strIP, int wPort, int dwType) {std::string strSession(strIP);char achPort[PORT_LEN] = { 0 };sprintf_s(achPort, PORT_LEN, ":%d|%d", wPort, dwType);strSession.append(achPort);return strSession; } static lws_context* CreateContext() {lws_set_log_level(0xFF, NULL);lws_context* plcContext = NULL;lws_context_creation_info tCreateinfo;memset(&tCreateinfo, 0, sizeof tCreateinfo);tCreateinfo.port = CONTEXT_PORT_NO_LISTEN;tCreateinfo.protocols = protocols;plcContext = lws_create_context(&tCreateinfo);return plcContext; } static void Connect(string url, string &strServerIP, int wPort, int dwType) {struct lws_client_connect_info tConnectInfo;memset(&tConnectInfo, 0, sizeof(tConnectInfo));tConnectInfo.context = s_ptContext;tConnectInfo.address = "172.22.3.25";tConnectInfo.port = 90;tConnectInfo.path = url.c_str();tConnectInfo.protocol = protocols->name;tConnectInfo.host = "172.22.3.25";// char *pchSession = new char[SESSION_LEN];// if (pchSession)// {// memset(pchSession, 0, SESSION_LEN);// memcpy(pchSession, CombineIPAndPort(strServerIP, wPort, dwType).c_str(), SESSION_LEN);// }// tConnectInfo.userdata = pchSession;lws_client_connect_via_info(&tConnectInfo); } DWORD WINAPI lws_ServiceThread(LPVOID lpParameter) {s_ptContext = CreateContext();while (TRUE){lws_service(s_ptContext, 50);if (false){break;}}lws_context_destroy(s_ptContext);return 0; } int initLibWebSocket(string url) {HANDLE hThread = CreateThread(0, 0, lws_ServiceThread, (LPVOID)10, CREATE_SUSPENDED, 0);ResumeThread(hThread);Sleep(3000);string ipTemp = "127.0.0.1";Connect(url, ipTemp, 80, 0);return 0; }真正的實例,待驗證:https://blog.csdn.net/yuanwei1314/article/details/76228495
會報段錯誤,原因不知,但知道在哪里報
server端:lws_service(context, 50);報段錯誤
client端:wsi = lws_client_connect(.......)報段錯誤
總結(jié)
以上是生活随笔為你收集整理的20190506(libwebsockets库使用学习)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 哈工大软件构造期末复习(根据老师复习提纲
- 下一篇: 哈工大软件构造课程知识点总结(二)