赞
踩
nopoll是linux常用的开源的websocket的实现。可用于websocket的解决方案和已有的TCP的应用提供websocket的支持。
http://www.aspl.es/nopoll/html/nopoll_core_library_manual.html#installing_nopoll
nopoll的安装之前需要安装一个依赖OpenSSL,用于通信协议本身要求的加密需求。
安装成功后,只需要在我们的源文件中包含头文件nopoll.h
#include <nopoll.h>
如果在多个线程中同时调用nopoll的api,需要设置4个回调用以执行nopoll的创建,销毁和上锁和解锁。
在使用nopoll的API之前需要创建一个noPollCtx的对象,这个对象代表了一个单独的nopoll库的实例。
如下操作:
noPollCtx *ctx = nopoll_ctx_new();
if(!ctx)
{
error
}
//do some websocket ooperation(as client or server)
在用户终止的数据的传输,链接,需要释放这个context通过调用如下接口:
nopoll_ctx_unref(ctx);
- // create a listener to receive connections on port 1234
- noPollConn * listener = nopoll_listener_new (ctx, "0.0.0.0", "1234");
- if (! nopoll_conn_is_ok (listener)) {
- // some error handling here
- }
- // now set a handler that will be called when a message (fragment or not) is received
- nopoll_ctx_set_on_msg (ctx, listener_on_message, NULL);
- // now call to wait for the loop to notify events
- nopoll_loop_wait (ctx, 0);
现在,每次只要有数据帧被接收到,就会调用listener_on_message这个处理函数。
- void listener_on_message (noPollCtx * ctx, noPollConn * conn, noPollMsg * msg, noPollPtr user_data) {
- // print the message (for debugging purposes) and reply
- printf ("Listener received (size: %d, ctx refs: %d): (first %d bytes, fragment: %d) '%s'\n",
- nopoll_msg_get_payload_size (msg),
- nopoll_ctx_ref_count (ctx), shown, nopoll_msg_is_fragment (msg), example);
- // reply to the message
- nopoll_conn_send_text (conn, "Message received", 16);
- return;
- }
当创建了一个context(noPollCtx)后就能够通过如下的方式,连接到server
- // call to create a connection
- noPollConn * conn = nopoll_conn_new (ctx, "localhost", "1234", NULL, NULL, NULL, NULL);
- if (! nopoll_conn_is_ok (conn)) {
- // some error handling here
- }
这之后可以调用nopoll_conn_is_ready 返回一个nopoll_true或者使用nopoll_conn_wait_until_connection_ready.确定网路已经连接。可以通过如下的方式发送数据。
- // send a message
- if (nopoll_conn_send_text (conn, "Hello there! this is a test", 27) != 27) {
- // send a message
- }
从websocket的链接上接收数据:
使用nopoll_loop_wait()循环等待,设置消息接收的处理函数(nopoll_ctx_set_on_msg 和nopoll_conn_set_on_msg).
nopoll是否会自动的整合信息帧片段成为一个单独的消息。所有的websocket都必须设计成一个面向流的socket设计。一般来说,nopoll调用接口nopoll_conn_get_msg()尝试接收整合一个完整的消息,当接收到了一个消息片段后,这个消息片段可能是消息的头或者消息体的一部分,然后接口返回一个NULL,等待用户再次调用这个接口用以得到完整的消息。
写操作重复尝试失败,用户每次执行的而写操作(调用nopoll_conn_send_text或者nopoll_conn_send_text_fragment)都有失败的可能,因为socket不能够保持持续的数据接收。
出现这种情况时error=11将会被返回,或者是NOPOLL_EWOULDBLOCK,所以在每次执行写操作时都应该检查。
因为websocket发送的headers中包含了发送消息的长度。所以不能通过调用nopoll_conn_send_text这些发送的接口再次尝试发送数据,
- int websocket_write (noPollConn * conn, const char * content, int length) {
- // FIRST PART: normal send operation
- int tries = 0;
- int bytes_written;
- // do write operation and check
- bytes_written = nopoll_conn_send_text (conn, content, length);
- if (bytes_written == length) {
- // operation completed, just return bytes written
- return bytes_written;
- }
- // SECOND PART: retry in the case of failure
- // some failure found, check errno
- while (tries < 5 && errno == NOPOLL_EWOULDBLOCK && nopoll_conn_pending_write_bytes (conn) > 0) {
- // ok, unable to write all data but that data is waiting to be flushed
- // you can return here and then make your application to retry again or
- // try it right now, but with a little pause before continue
- nopoll_sleep (10000); // lets wait 10ns
- // flush and check if write operation completed
- if (nopoll_conn_complete_pending_write (conn) == 0)
- return length;
- // limit loop
- tries++;
- }
- // failure, return error code reported by the first call or the last retry
- return bytes_written;
- }
实现协议端口的共享:在同一个端口运行websocket协议或者先前的协议。
由于多个协议共享端口,所以在使用之前一般会确定使用的哪一种协议:
// detect tls conn
nopoll_bool is_tls_conn = bytes[0] == 22 && bytes[1] == 3 && bytes[2] == 1;
// detect then both values (TLS WebSocket and just WebScoket)
if (! axl_memcmp ("GET", bytes, 3) && ! is_tls_conn)
return nopoll_false; // nothing detected here (it doesn't seems
// to be a websocket connection) continue as normal
// nice, it seems we've found an incoming WebSocket connection
- // Create a noPollConn listener object that presents the legacy listener where the connection was
- // received. In general is recommended to reuse these references to avoid creating over and over
- // again new references as new WebSocket connections are received.
- //
- noPollConn * nopoll_listener = nopoll_listener_from_socket (nopoll_ctx, listener_socket);
- // Create an accepted listener connection reusing the socket received
- // where nopoll_ctx is a reference to a noPollCtx object created and reused by all
- // connections accepted, and _socket represents the socket file descriptor
- //
- noPollConn * conn = nopoll_listener_from_socket (nopoll_ctx, _socket);
- if (! nopoll_conn_is_ok (conn)) {
- // ok, something failed, release and return
- nopoll_conn_close (conn);
- return;
- }
- // Now, initiate the entire WebSocket accept process (including TLS one)
- // where nopoll_ctx is the context we used before, nopoll_listener is a listener where
- // the connection was received, conn is the connection accepted and is_tls_conn
- // is an indication about what to expect about TLS process.
- //
- if (! nopoll_conn_accept_complete (nopoll_ctx, nopoll_listener, conn, _socket, is_tls_conn)) {
- // failed to accept connection, release connection
- nopoll_conn_close (conn);
- // optionally close listener reference if it is not reused
- nopoll_conn_close (nopoll_listener);
- return;
- }
- // now process incoming messages as configured (either because you've configured an onMessage handler)
- // or because you are handling directly all incoming content (streaming API).
-
-
- nopoll提供了peer verify的功能。
- nopoll同样可适用于安卓系统。
在linux的SDK中,websocket的实现是使用的开源的nopoll,所以根据实际情况,梳理nopoll在每个接口中的调用和实现。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。