void lws_set_log_level(int level, void (*log_emit_function)(int level, const char *line));
lws_set_log_level() - Set the logging bitfield(位域)
param level: OR together the LLL_ debug contexts you want output from
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(標準輸出) one.
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.(分級顯示)
struct lws_context *lws_create_context(struct lws_context_creation_info *info);
lws_create_context() - Create the websocket handler(管理者)
param info: pointer to struct with parametersThis function creates the listening socket (if serving) and takes care of all initialization in one step(建立socket並完成一系列初始化工作)
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(建立vhost,特殊情況調用lws_create_vhost())
After initialization, it returns a struct lws_context * that represents this server. After calling, user code needs to take care of calling lws_service() with the context pointer to get the server's sockets serviced. This must be done in the same process context as the initialization call.(初始化以後,迴圈調用lws_service()來獲得服務)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.(串連,請求發送,接受訊息都會調用協議回呼函數,回呼函數是被周期性調用的,以便達到非同步傳輸的效果)
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還未達成協議,之後其它協議就不需要HTTP頭了)
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服務的一個濃縮)
This allows the same server to provide files like scripts and favicon images or whatever over http and dynamic data over websockets all in one place; they're all handled in the user callback. (在使用者回調裡面,提供指令碼語言,圖片和其它資料)
int lws_service(struct lws_context *context, int timeout_ms);
解析:
polllws_service() - Service any pending(即將發生的) websocket activity
param context: Websocket context(上下文)
param timeout_ms: 0 means return immediately if nothing needed service otherwise block and service immediately, returning after the timeout if nothing needed service.
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.
1) Accept new connections to our context's server(接受串連)
2) Call the receive callback for incoming frame data received by server or client connections.(訊息回調)
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. (迴圈調用該函數)
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.(最好重開線程調用該函數)
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.(逾時最好設為0)
struct lws_client_connect_info
struct lws_client_connect_info {
struct lws_context *context; /**< lws context to create connection in */
const char *address; /**< remote address to connect to */
int port; /**< remote port to connect to */
int ssl_connection; /**< nonzero for ssl */
const char *path; /**< uri path */
const char *host; /**< content of host header */
const char *origin; /**< content of origin header */
const char *protocol; /**< list of ws protocols we could accept */
int ietf_version_or_minus_one; /**< deprecated: currently leave at 0 or -1 */
void *userdata; /**< if non-NULL, use this as wsi user_data instead of malloc it */
const void *client_exts; /**< UNUSED... provide in info.extensions at context creation time */
const char *method;
/**< if non-NULL, do this http method instead of ws[s] upgrade.
* use "GET" to be a simple http client connection */
struct lws *parent_wsi;
/**< if another wsi is responsible for this connection, give it here.
* this is used to make sure if the parent closes so do any
* child connections first. */
const char *uri_replace_from;
/**< if non-NULL, when this string is found in URIs in
* text/html content-encoding, it's replaced with uri_replace_to */
const char *uri_replace_to;
/**< see uri_replace_from */
struct lws_vhost *vhost;
/**< vhost to bind to (used to determine related 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.
*/
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.
*/ void *_unused[4];
};
struct lws * lws_client_connect_via_info(struct lws_client_connect_info * ccinfo);
lws_client_connect_via_info() - Connect to another websocket server
param ccinfo: pointer to lws_client_connect_info struct
This function creates a connection to a remote server using the
information provided in ccinfo.
void lws_context_destroy(struct lws_context *context);
lws_context_destroy() - Destroy the websocket context
param context: Websocket context
This function closes any active connections and then frees the context. After calling this, any further use of the context is undefined
實現代碼:
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;
}