Fork me on GitHub

libwebsocket demo以及遇到的坑。

借鉴的 https://blog.csdn.net/qq_19004627/article/details/88737411

坑1:openssl报错:ip address mismatch(preverify_ok=0;err=64;depth=0),不确定是不是自己生成的证书在无网情况下是不是不可用(开发电脑无法连互联网),暂时屏蔽了openssl相关的代码。

坑2:这个文章的client的代码中的发送代码有中文“你好”,导致服务器解析异常,进而断链(这个问题,困扰了我几乎一整天)。暂时修改成非中文,如果一定要中文,需要转utf-8。

坑3:服务器的回显代码可以做下优化。如下所示,当data->len非零时再传输。

case LWS_CALLBACK_SERVER_WRITEABLE:   // 当此连接可写时
	{
		if (data->len != 0)
		{
			lws_write(wsi, &data->buf[LWS_PRE], data->len, LWS_WRITE_TEXT);
			data->len = 0;
		}
	} 

坑4:接收字符串打印乱码(直接打印in),可以在长度后面增加\0。

case LWS_CALLBACK_RECEIVE:           // 当接收到客户端发来的帧以后
										 // 判断是否最后一帧
		data->fin = lws_is_final_fragment(wsi);
		// 判断是否二进制消息
		data->bin = lws_frame_is_binary(wsi);
		// 对服务器的接收端进行流量控制,如果来不及处理,可以控制之
		// 下面的调用禁止在此连接上接收数据
		//lws_rx_flow_control(wsi, 0);
		// 业务处理部分,为了实现Echo服务器,把客户端数据保存起来
		memcpy(&data->buf[LWS_PRE], in, len);
		data->len = len;
		data->buf[LWS_PRE + data->len] = 0;
		lwsl_notice("recvied message:%s,len=%d\n", (char*)&data->buf[LWS_PRE], data->len);

		// 需要给客户端应答时,触发一次写回调
		lws_callback_on_writable(wsi);
		break;

5、异步发送数据 :lws_callback_on_writable不支持多线程,可以使用lws_cancel_service 退出lws_service,然后判断是否有数据发送:(lws_service 中的timeout参数已经没用了,见下文注释)

int CWssClientHelper::SendMsg(const std::string& msg)
{
	std::lock_guard<std::mutex> lck(m_lckSendBuffers);
	std::string tempMsg;
	tempMsg.append(LWS_PRE, 0);  // 追加LWS_PRE个字节
	tempMsg.append(msg.data(), msg.size());
	m_sendBuffers.push_back(tempMsg);
	m_readyToSend = true;
	if (m_wsc)
	{
		lws_cancel_service(m_wsc);
	}
	return WSS_CLIENT_ERR_OK;
}
....
// 循环线程 while (!m_bExit) { // 执行一次事件循环(Poll),最长等待1000毫秒 lws_service(m_wsc, 1000); /** * 下面的调用的意义是:当连接可以接受新数据时,触发一次WRITEABLE事件回调 * 当连接正在后台发送数据时,它不能接受新的数据写入请求,所有WRITEABLE事件回调不会执行 */ if (m_readyToSend) { lws_callback_on_writable(wsi); } }

  

/**
 * lws_service() - Service any pending websocket activity
 * \param context:	Websocket context
 * \param timeout_ms:	Set to 0; ignored; for backward compatibility
 *
 *	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.
 *
 *  Since v3.2 internally the timeout wait is ignored, the lws scheduler is
 *  smart enough to stay asleep until an event is queued.
 */
LWS_VISIBLE LWS_EXTERN int
lws_service(struct lws_context *context, int timeout_ms);

 

其他今天搜寻了一天的资料的心得:

1、lws_write前面一定要预留LWS_PRE的空间,给lws内部使用,否则会崩溃。

2、如果报文很长,需要分片,需要判断lws_is_final_fragment,可以使用类似下面的代码:

case LWS_CALLBACK_RECEIVE:
 {
     Client * const client = (Client *)user;
     const size_t remaining = lws_remaining_packet_payload(wsi);
 
     if (!remaining && lws_is_final_fragment(wsi)) {
         if (client->HasFragments()) {
             client->AppendMessageFragment(in, len, 0);
             in = (void *)client->GetMessage();
             len = client->GetMessageLength();
         }
 
         client->ProcessMessage((char *)in, len, wsi);
         client->ResetMessage();
     } else
         client->AppendMessageFragment(in, len, remaining);
 }
 break;

3、客户端支持多连接到不同服务器,需要开多个线程去处理。

 

其他的一些可以参考https://blog.csdn.net/yetyongjin/article/details/131082375

 

posted @ 2024-08-29 20:07  烟波--钓徒  阅读(210)  评论(0编辑  收藏  举报