janus模块介绍-SIP Gateway
模块启动
默认的SIP GateWay也是https协议,端口为8088或者8089
如果需要在自己搭建的测试服务上测试SIP GateWay模块,则也需要修改为wss
具体改动如下: 找到/opt/janus/share/janus/demos/siptest.js
var server = "wss://" + window.location.hostname + ":8989";
然后重启janus服务,执行
/opt/janus/bin/janus --debug-level=5 --log-file=$HOME/janus-log
打开测试网页,在demos中找到SIP Gateway,点击start开始运行。
点击f12可以看到demo中Using WebSockets to contact Janus: wss://49.232.250.45:8989
模块基本说明
这是Janus的一个简单SIP插件,允许WebRTC对等方在SIP服务器(例如Asterisk)注册,并通过Janus实例调用SIP用户代理。具体地,当连接到插件时,请求对等方提供其SIP服务器证书,即SIP服务器的地址和其用户名/密码。这导致插件在SIP服务器处注册,并代表网络对等方充当SIP客户端。大多数SIP状态和生存期都被插件屏蔽,只有相关事件(例如INVITE和BYE)和功能(呼叫、挂断)可供网络对等方使用:对等方可以在SIP服务器上呼叫扩展或等待传入的INVITE,并且在呼叫期间可以发送DTMF音调。调用可以执行纯RTP或SDES-SRTP。
该插件背后的概念是允许与同一对等方相关联的不同网页,从而允许同一SIP用户同时连接到插件,但只进行一次SIP REGISTER。这同样适用于呼叫:虽然传入的呼叫将被通知给与对等方相关的所有web UI,但只有一个能够接听和接听,这与SIP分叉的工作方式非常相似,但不需要在同一个地方分叉。然而,这一特定功能尚未实现。
SIP Plugin API
我们可以在SIP插件API中发送的所有请求都是异步的,这意味着所有响应(成功和错误)都将作为同一事务的事件传递。
支持的请求包括注册、注销、调用、接受、拒绝、信息、消息、dtmf_info、订阅、取消订阅、传输、录制、保留、取消保留、更新和挂断。顾名思义,register可以用于在SIP注册器处注册用户名以调用和被调用,而unregister则注销该用户名;call用于通过插件向不同的SIP URI发送INVITE,而accept和dence用于在邀请而不是邀请的情况下接受或拒绝呼叫;接送负责有人接送和无人接送(更多详细信息,请参阅有人接送或无人接送);hold和unhold可以分别用于将呼叫挂起和恢复呼叫;info允许您发送一个通用的SIP info请求,而dtmf_info则专注于将info用于dtmf;message是用于向另一个对等方发送SIP消息的方法;subscribe和unsubscribe用于处理SIP事件,即发送subscribe请求,该请求将导致NOTIFY异步事件;相反,录音用于将对话记录到一个或多个.mjr文件中(取决于您想要录制的方向);更新允许您更新现有会话(例如,进行重新协商或强制ICE重新启动);最后,挂断可以用于在任何时候终止通信,或者挂断(BYE)正在进行的呼叫,或者取消/拒绝(cancel/BYE)尚未开始的呼叫。
无论请求如何,错误响应或事件的格式始终如下:
{"sip" : "event","error_code" : <numeric ID, check Macros below>,"error" : "<error description as a string>"
}
请注意,上面的错误语法指的是插件API消息传递,而不是响应于SIP请求而获得的SIP错误代码,这些错误代码是使用不同的语法通知的:
{"sip" : "event","result" : {"event" : "<name of the error event>","code" : <SIP error code>,"reason" : "<SIP error reason>","reason_header" : "<Reason header text; optional>","reason_header_protocol" : "<Reason header protocol; optional>","reason_header_cause" : "<Reason header cause code; optional>"}
}
对于可用的请求,您可以使用注册请求发送一个SIP REGISTER。更准确地说,注册请求可能会导致SIP register,因为这种方法实际上提供了无需注册即可开始使用SIP帐户的方法。例如,所谓的访客注册就是这样的情况:如果你注册为访客,这意味着你将使用From标头中提供的SIP URI进行呼叫,但实际上你不会发送SIP register;这对于向不需要注册的服务(例如,IVR系统或会议桥)发出的呼叫特别有用,但也意味着除非对等方知道您的私人SIP地址,否则您将无法接收呼叫。注册为帮助者时也不会发送SIP REGISTER:正如我们稍后将解释的,帮助者会话仅用于方便使用同一帐户设置同时SIP呼叫。
也就是说,注册请求的格式必须如下:
{"request" : "register","type" : "<if guest or helper, no SIP REGISTER is actually sent; optional>","send_register" : <true|false; if false, no SIP REGISTER is actually sent; optional>,"force_udp" : <true|false; if true, forces UDP for the SIP messaging; optional>,"force_tcp" : <true|false; if true, forces TCP for the SIP messaging; optional>,"sips" : <true|false; if true, configures a SIPS URI too when registering; optional>,"rfc2543_cancel" : <true|false; if true, configures sip client to CANCEL pending INVITEs without having received a provisional response first; optional>,"username" : "<SIP URI to register; mandatory>","secret" : "<password to use to register; optional>","ha1_secret" : "<prehashed password to use to register; optional>","authuser" : "<username to use to authenticate (overrides the one in the SIP URI); optional>","display_name" : "<display name to use when sending SIP REGISTER; optional>","user_agent" : "<user agent to use when sending SIP REGISTER; optional>","proxy" : "<server to register at; optional, as won't be needed in case the REGISTER is not goint to be sent (e.g., guests)>","outbound_proxy" : "<outbound proxy to use, if any; optional>","headers" : "<object with key/value mappings (header name/value), to specify custom headers to add to the SIP REGISTER; optional>","contact_params" : "<array of key/value objects, to specify custom Contact URI params to add to the SIP REGISTER; optional>","incoming_header_prefixes" : "<array of strings, to specify custom (non-standard) headers to read on incoming SIP events; optional>","refresh" : "<true|false; if true, only uses the SIP REGISTER as an update and not a new registration; optional>","master_id" : "<ID of an already registered account, if this is an helper for multiple calls (more on that later); optional>","register_ttl" : "<integer; number of seconds after which the registration should expire; optional>"
}
注册事件将被发回,因为这是一个异步请求。
如果需要,此请求将向具有正确凭据的指定服务器发起SIP REGISTER。401和407响应将被自动处理,因此错误将不会被通知回呼叫者,除非它们是决定性的(例如,错误的凭证)。注册失败将返回名称为registration_failed的错误。相反,成功注册会在注册事件中得到通知,格式如下:
{"sip" : "event","result" : {"event" : "registered","username" : <SIP URI username>,"register_sent" : <true|false, depending on whether a REGISTER was sent or not>,"master_id" : <unique ID of this registered session in the plugin, if a potential master>}
}
要注销,只需发送一个不带其他参数的注销请求:
{"request" : "unregister"
}
与以前一样,将发回一个注销事件。和以前一样,这也会发送一个SIP REGISTER,以防它最初被发送。在未注册的事件中通知成功注销:
{"sip" : "event","result" : {"event" : "unregistered","username" : <SIP URI username>,"register_sent" : <true|false, depending on whether a REGISTER was sent or not>}
}
注册后,您可以拨打电话或等待来电:请注意,如果您选择从不发送REGISTER,您将无法接听来电。
要发送SIP INVITE,您可以使用呼叫请求,其格式如下:
{"request" : "call","call_id" : "<user-defined value of Call-ID SIP header used in all SIP requests throughout the call; optional>","uri" : "<SIP URI to call; mandatory>","refer_id" : <in case this is the result of a REFER, the unique identifier that addresses it; optional>,"headers" : "<object with key/value mappings (header name/value), to specify custom headers to add to the SIP INVITE; optional>","srtp" : "<whether to mandate (sdes_mandatory) or offer (sdes_optional) SRTP support; optional>","srtp_profile" : "<SRTP profile to negotiate, in case SRTP is offered; optional>","secret" : "<password to use to call, only needed in case authentication is needed and no REGISTER was sent; optional>","ha1_secret" : "<prehashed password to use to call, only needed in case authentication is needed and no REGISTER was sent; optional>","authuser" : "<username to use to authenticate as to call, only needed in case authentication is needed and no REGISTER was sent; optional>","autoaccept_reinvites" : <true|false, whether we should blindly accept re-INVITEs with a 200 OK instead of relaying the SDP to the application; optional, TRUE by default>
}
调用事件将被发回,因为这是一个异步请求。
请注意,此请求必须与JSEP优惠相关联:无法通过SIP插件发送无优惠INVITE。这将生成一个SIP INVITE,并根据指示进行发送。虽然100秒Trying不会通知回用户,但在振铃事件中,180秒将会响铃:
{"sip" : "event","call_id" : "<value of SIP Call-ID header for related call>","result" : {"event" : "ringing","headers" : "<object with key/value strings; custom headers extracted from SIP event based on incoming_header_prefix defined in register request; optional>"}
}
如果呼叫被拒绝或发生任何其他错误,则会发回挂断错误事件。如果呼叫被接受,则接受的事件将与被叫方发起的JSEP应答一起发送回用户:
{"sip" : "event","call_id" : "<value of SIP Call-ID header for related call>","result" : {"event" : "accepted","username" : "<SIP URI of the callee>","headers" : "<object with key/value strings; custom headers extracted from SIP event based on incoming_header_prefix defined in register request; optional>"}
}
在这一点上,除了PeerConnection相关的考虑因素外,可以认为该调用已建立。SIP插件会自动发送SIP ACK,因此不需要应用程序手动执行任何操作。
请注意,SIP插件通过183个响应响应支持早期媒体。在接收到183响应的情况下,在进度事件中,它将与被叫方发起的JSEP应答一起发送回用户:
{"sip" : "event","call_id" : "<value of SIP Call-ID header for related call>","result" : {"event" : "progress","username" : "<SIP URI of the callee>","headers" : "<object with key/value strings; custom headers extracted from SIP event based on incoming_header_prefix defined in register request; optional>"}
}
如果呼叫者收到进度事件,以下接受的事件将不包含JSEP应答,因为在“会话进度”事件中收到的应答将作为会话的SDP应答。
请注意,您只使用call来开始对话,即第一次INVITE。要通过重新邀请更新会话,例如,重新协商会话以添加/删除流或强制ICE重新启动,您不使用调用,而是使用另一个名为update的请求。这个请求不需要任何参数,因为整个上下文都是从会话的当前状态派生的。不过,作为重新谈判的一部分,它确实需要新的JSEP报价。
{"request" : "update"
}
更新事件将被发回,因为这是一个异步请求。
虽然呼叫请求允许您发送SIP INVITE(更新请求允许您更新现有会话),但也有一种方法可以对SIP INVITEs做出反应,即处理传入呼叫。传入呼叫通过传入呼叫事件通知应用程序:
{"sip" : "event","call_id" : "<value of SIP Call-ID header for related call>","result" : {"event" : "incomingcall","username" : "<SIP URI of the caller>","displayname" : "<display name of the caller, if available; optional>","callee" : "<SIP URI that was called (in case the user is associated with multiple public URIs)>","referred_by" : "<SIP URI header conveying the identity of the transferor, if this is a transfer; optional>","replaces" : "<call-ID of the call that this is supposed to replace, if this is an attended transfer; optional>","srtp" : "<whether the caller mandates (sdes_mandatory) or offers (sdes_optional) SRTP support; optional>","headers" : "<object with key/value strings; custom headers extracted from SIP event based on incoming_header_prefix defined in register request; optional>"}
}
来电可能会也可能不会附带JSEP报价,这取决于来电者发送的是无报价邀请还是常规邀请。无论哪种方式,您都可以通过接受请求来接受来电:
{"request" : "accept","srtp" : "<whether to mandate (sdes_mandatory) or offer (sdes_optional) SRTP support; optional>","headers" : "<object with key/value mappings (header name/value), to specify custom headers to add to the SIP OK; optional>""autoaccept_reinvites" : <true|false, whether we should blindly accept re-INVITEs with a 200 OK instead of relaying the SDP to the browser; optional, TRUE by default>
}
由于这是一个异步请求,将发回一个接受事件。
这将导致200 OK被发送回呼叫者。接受请求必须始终附有JSEP回复(如果incomingcall事件包含要约)或要约(如果是无要约邀请)。在前一种情况下,接受的事件将被发回,只是为了确认呼叫可以被视为已建立;相反,在后一种情况下,接受事件将被发送回,而接受的事件只会在稍后,只要在呼叫者发送回的SIP ACK中有JSEP应答可用,就紧随其后。
请注意,如果您在另一个呼叫中接到来电,您将不会收到incomingcall事件,而是收到missed_call事件,这只是一个通知,因为在SIP插件中,无法在同一句柄上同时进行两个呼叫:
{"sip" : "event","call_id" : "<value of SIP Call-ID header for related call>","result" : {"event" : "missed_call","caller" : "<SIP URI of the caller>","displayname" : "<display name of the caller, if available; optional>","callee" : "<SIP URI that was called (in case the user is associated with multiple public URIs)>"}
}
此外,您只能使用accept来回答第一个INVITE。要接受重新邀请(将通过updatingcall事件通知),您不使用accept,而是使用之前引入的更新。这个请求不需要任何参数,因为整个上下文都是从会话的当前状态派生的。不过,作为重新谈判的一部分,它确实需要新的JSEP答案来提供。和以前一样,由于这是一个异步请求,因此会发回一个更新的事件。
关闭会话取决于调用状态。如果您有不想接听的来电,请使用拒绝请求;在所有其他情况下,请改用挂断请求。这两个请求都不需要额外的参数,因为整个上下文可以从插件中会话的当前状态中提取:
{"request" : "decline","code" : <SIP code to be sent, if not set, 486 is used; optional>","headers" : "<object with key/value mappings (header name/value), to specify custom headers to add to the SIP request; optional>"
}
{"request" : "hangup","headers" : "<object with key/value mappings (header name/value), to specify custom headers to add to the SIP BYE; optional>"
}
由于这些都是异步请求,您将得到一个响应事件:如果使用了谢绝,则拒绝;如果使用了挂起,则挂起。
如前所述,当呼叫被拒绝或挂断时,会发送一个挂断事件,这基本上是一个SIP错误事件通知,因为它包括代码和原因。例如,常规BYE将被通知200和SIP BYE,尽管也可以提供更详细的描述。
建立会话后,可以使用不同的请求与会话进行交互。
首先,您可以使用挂起请求将呼叫挂起。默认情况下,此请求将向对等方发送一个新的INVITE,其中包含媒体的sendonly方向,但如果您想设置不同的方向(recvonly或inactive),也可以通过传递direction属性来实现:
{"request" : "hold","direction" : "<sendonly, recvonly or inactive>"
}
持有者方不涉及WebRTC重新协商,因为这只会触发SIP方的重新INVITE。要从挂起状态移除调用,只需向插件发送一个取消挂起的请求,该请求不需要其他属性:
{"request" : "unhold"
}
并且将恢复在保持呼叫之前在SDP中设置的媒体方向。
消息请求允许您向对等方发送SIP message。默认情况下,在活动呼叫期间,它在对话框中发送。但是,如果用户已经注册,它也可能被发送到对话框之外。在这种情况下,uri参数是必需的。
{"request" : "message","call_id" : "<user-defined value of Call-ID SIP header used to send the message; optional>","content_type" : "<content type; optional>""content" : "<text to send>","uri" : "<SIP URI of the peer; optional; if set, the message will be sent out of dialog>","headers" : "<object with key/value mappings (header name/value), to specify custom headers to add to the SIP MESSAGE; optional>"
}
messagesend事件将被发回。相反,传入的SIP消息会在消息事件中得到通知:
{"sip" : "event","result" : {"event" : "message","sender" : "<SIP URI of the message sender>","displayname" : "<display name of the sender, if available; optional>","content_type" : "<content type of the message>","content" : "<content of the message>","headers" : "<object with key/value strings; custom headers extracted from SIP event based on incoming_header_prefix defined in register request; optional>"}
}
传递后,消息传递事件将与SIP服务器响应一起发送回。用于跟踪邮件的传递状态。
{"sip" : "event","call_id" : "<value of SIP Call-ID header for related message>","result" : {"event" : "messagedelivery","code" : "<SIP error code>","reason" : "<SIP error reason>",}
}
SIP INFO的工作方式几乎相同,只是您使用一个对一个对等体的信息请求:
{"request" : "info","type" : "<content type>""content" : "<message to send>","headers" : "<object with key/value mappings (header name/value), to specify custom headers to add to the SIP INFO; optional>"
}
将发回一个infosend事件。相反,传入的SIP info会在信息事件中得到通知:
{"sip" : "event","result" : {"event" : "info","sender" : "<SIP URI of the message sender>","displayname" : "<display name of the sender, if available; optional>","type" : "<content type of the message>","content" : "<content of the message>","headers" : "<object with key/value strings; custom headers extracted from SIP event based on incoming_header_prefix defined in register request; optional>"}
}
正如预期的那样,使用SUBSCRIBE和NOTIFY机制也支持SIP事件。要做到这一点,您需要使用订阅请求,该请求的格式如下:
{"request" : "subscribe","call_id" : "<user-defined value of Call-ID SIP header used in all SIP requests throughout the subscription; optional>","event" : "<the event to subscribe to, e.g., 'message-summary'; mandatory>","accept" : "<what should be put in the Accept header; optional>","to" : "<who should be the SUBSCRIBE addressed to; optional, will use the user's identity if missing>","subscribe_ttl" : "<integer; number of seconds after which the subscription should expire; optional>","headers" : "<array of key/value objects, to specify custom headers to add to the SIP SUBSCRIBE; optional>"
}
如果subscribe请求被接受,则会发回订阅事件,然后是subscribe_succeed,如果事务失败,则会返回subscribe_failed。相反,传入的SIP NOTIFY事件在通知事件中得到通知:
{"sip" : "event","call_id" : "<value of SIP Call-ID header for related subscription>","result" : {"event" : "notify","notify" : "<name of the event that the user is subscribed to, e.g., 'message-summary'>","substate" : "<substate of the subscription, e.g., 'active'>","content-type" : "<content-type of the message>""content" : "<content of the message>","headers" : "<object with key/value strings; custom headers extracted from SIP event based on incoming_header_prefix defined in register request; optional>"}
}
您还可以录制SIP调用,它的工作原理与VideoCall插件的工作原理几乎相同。具体来说,您可以使用录制请求来启动或停止录制,使用以下语法:
{"request" : "recording","action" : "<start|stop, depending on whether you want to start or stop recording something>""audio" : <true|false; whether or not our audio should be recorded>,"video" : <true|false; whether or not our video should be recorded>,"peer_audio" : <true|false; whether or not our peer's audio should be recorded>,"peer_video" : <true|false; whether or not our peer's video should be recorded>,"send_peer_pli" : <true|false; whether or not send PLI to request keyframe from peer>,"filename" : "<base path/filename to use for all the recordings>"
}
正如您所看到的,这意味着对话的双方是分开录制的,音频和视频流也是如此(如果可用)。您可以选择要记录的内容,以防您只对子集感兴趣。文件名部分只是一个前缀,指示将用于最多四个可能需要启用的录制的实际文件名。
如果请求成功,则会发回已记录的更新事件。
Simultaneous SIP calls using the same account
如前几节所述,使用Janus句柄附加到SIP插件意味着代表用户或应用程序创建SIP堆栈:这通常意味着注册帐户,并能够启动或接收调用、处理订阅等。这也意味着,由于在Janus中,每个核心句柄只能与单个PeerConnection相关联,因此每个SIP帐户每次仅限于一个调用:如果用户已经在SIP会话中,并且另一个调用传入,则会自动拒绝,并显示486 Busy。
虽然通常不是什么大问题,但在某些用例中,支持多个并发调用是有意义的,并且可以从一个无缝地切换到另一个。这在使用所谓的助手会话的SIP插件中是可能的。具体来说,助手会话在假设存在正常注册的主会话(即“常规”SIP插件句柄)的情况下工作,并且这些助手会话可以简单地与之关联:任何时候需要另一个并发调用,如果主会话繁忙,则可以使用其中一个助手;可用的助手会话越多,可以建立的同时调用就越多。
其工作方式很简单:
您以通常的方式创建SIP会话,并在那里发送常规注册表;这将是主会话,并在成功注册时返回master_id;
对于要添加的每个助手,您将新的Janus句柄附加到SIP插件,并发送一个类型为“helper”的寄存器,并提供与主会话相同的用户名,以及引用主会话的master_id属性;
此时,新的助手与主机相关联,这意味着它可以用于启动新的调用或接收与主会话完全相同的调用,并使用相同的帐户信息、凭据等。
请注意,一旦主服务器注销,或者它所在的Janus句柄被分离,与它相关的所有助手会话也会自动删除。具体来说,插件将强制分离相关句柄。如果您需要再次注册,并希望在那里也有一些助手,您将不得不再次添加他们。
如果您想在实践中看到这一点,SIP插件演示有一个“隐藏”函数,您可以从JavaScript控制台调用该函数来玩助手:调用addHelper()函数将添加一个新的助手,并显示其他控件。您可以根据需要添加任意数量的辅助对象。
Attended and blind transfers
Janus SIP插件支持有人参与和盲传输,并且这样做主要依赖于多个调用功能:因此,请确保您已经阅读并熟悉关于使用相同帐户进行同步SIP调用的部分。
大多数与传输相关的功能都基于上一节中已经记录的现有消息和事件,但有几个方面需要注意。首先,如果您是传输者,则需要使用名为transfer的新请求,该请求允许您向受让者发送SIPREFER,以便到达不同的目标。传输请求的格式必须如下所示:
{"request" : "transfer","uri" : "<SIP URI to send the transferee too>","replace" : "<call-ID of the call this attended transfer is supposed to replace; default is none, which means blind/unattended transfer>"
}
无论是盲传输(无替换调用)还是有人参与传输,都将发回传输事件,因为这是一个异步请求。进一步的更新将以NOTIFY相关事件的形式出现,因为REFER隐式创建订阅。
相反,REFER的接收者将接收一个名为transfer的异步事件,其中包含它需要知道的信息。事实上,SIP插件不会自动执行任何操作:传入的REFER被通知给应用程序,以便它可以决定是否跟踪传输。事件的语法如下:
{"sip" : "event","result" : {"event" : "transfer","refer_id" : <unique ID, internal to Janus, of this referral>,"refer_to" : "<SIP URI to call>","referred_by" : "<SIP URI SIP URI header conveying the identity of the transferor; optional>","replaces" : "<call-ID of the call this transfer is supposed to replace; optional, and only present for attended transfers>","headers" : "<object with key/value strings; custom headers extracted from SIP event based on incoming_header_prefix defined in register request; optional>"}
}
该列表中最重要的属性是refer_id,因为如果传输被接受,则该值必须包含在调用请求中以调用目标:事实上,这是SIP插件必须将新的传出调用与前一个传输请求相关联的唯一方法,从而能够通过notify事件通知传输者调用的进展情况。请注意,如果受让人决定跟踪转移请求,并且他们已经在通话中(例如,与转发器),则他们必须为此目的使用不同的句柄,例如,通过使用相同帐户部分的同步SIP呼叫中描述的助手。
传输目标将完全像前面讨论的那样接收调用,不同的是,出于信息目的,它可能包含或不包含referred_by属性。就像受让人一样,如果他们已经在调用中,则应由应用程序创建一个助手来设置一个新的Janus句柄以接受传输。
请注意,插件不会将涉及的调用置于等待状态,或自动关闭打算由传输替换的调用。所有这些都是应用程序的责任,因此开发人员应该相应地对事件做出反应。
相关文章:
janus模块介绍-SIP Gateway
模块启动 默认的SIP GateWay也是https协议,端口为8088或者8089 如果需要在自己搭建的测试服务上测试SIP GateWay模块,则也需要修改为wss 具体改动如下: 找到/opt/janus/share/janus/demos/siptest.js var server "wss://" window.location…...
wstunnel (websocket模式ssh)
接上一篇 修改客户端运行参数 ssh -o ProxyCommand"./wstunnel client -L stdio://%h:%p ws://192.168.254.131:8080" 127.0.0.1 其中127.0.0.1为服务端的本地ssh访问,可以修改为通过服务端访问其他设备的ssh服务。例如: ssh -o ProxyComma…...
linux文件相关命令
一、linux文件相关命令 1、cd cd 是 “change directory” 的缩写,用于改变当前工作目录。 cd :不带任何参数时,会切换到用户的主目录(通常是 /home/用户名)。 cd ~:也会切换到用户的主目录。 cd .&…...
锂电池寿命预测 | Matlab基于GRU门控循环单元的锂电池寿命预测
目录 预测效果基本介绍程序设计参考资料 预测效果 基本介绍 锂电池寿命预测 | Matlab基于GRU门控循环单元的锂电池寿命预测 Matlab基于GRU的锂电池剩余寿命预测 基于GRU的锂电池剩余寿命预测(单变量) 运行环境Matlab2020及以上 锂电池的剩余寿命预测是…...
通往AGI路上,DPU将如何构建生成式AI时代的坚实算力基石?
4月19日,在以“重构世界 奔赴未来”为主题的2024中国生成式AI大会上,中科驭数作为DPU新型算力基础设施代表,受邀出席了中国智算中心创新论坛,发表了题为《以网络为中心的AI算力底座构建之路》主题演讲,勾勒出在通往AGI…...
无人驾驶 自动驾驶汽车 环境感知 精准定位 决策与规划 控制与执行 高精地图与车联网V2X 深度神经网络学习 深度强化学习 Apollo
无人驾驶 百度apollo课程 1-5 百度apollo课程 6-8 七月在线 无人驾驶系列知识入门到提高 当今,自动驾驶技术已经成为整个汽车产业的最新发展方向。应用自动驾驶技术可以全面提升汽车驾驶的安全性、舒适性,满足更高层次的市场需求等。自动驾驶技术得益于人工智能技术的应用…...
【QEMU系统分析之启动篇(十九)】
系列文章目录 第十九章 QEMU系统仿真的加速器上电后设置分析 文章目录 系列文章目录第十九章 QEMU系统仿真的加速器上电后设置分析 前言一、QEMU是什么?二、QEMU系统仿真的启动分析1.系统仿真的初始化代码2.主循环数据初始化3. os_setup_post()Windows 系统 os_set…...
Jmeter redis连接测试
Jmeter连接redis获取数据,一直连不上报错。最后只能通过java代码连接测试,最后只能自己动手。 import redis.clients.jedis.*;import java.io.IOException; import java.util.HashSet; import java.util.Set;/*** 单机版的Jedis连接池的用法*/ public c…...
使用Uiautomotorviewer无法获取手机页面元素+解决办法
在进行 Android 应用程序开发或测试时,有时会遇到以下错误: Error while obtaining UI hierarchy XML file: com.android.ddmlib.SyncException这个错误可能会导致开发或测试过程中的一些困扰,但有一个简单的解决方法: 解决方法…...
深度相机(3D相机)
传统的RGB彩色相机称为2D相机, 只能得到2D的图像信息, 无法得到物体与相机的距离信息,也就是深度信息。 顾名思义, 深度相机除了获取2D信息,还能得到深度信息,也叫RGBD相机, 或3D相机。 顺便提…...
了解时间复杂度和空间复杂度
在学习数据结构前,我们需要了解时间复杂度和空间复杂度的概念,这能够帮助我们了解数据结构。 算法效率分为时间效率和空间效率 时间复杂度 一个算法的复杂度与其执行的次数成正比。算法中执行基础操作的次数,为算法的时间复杂度。 我们采…...
[笔试强训]day2
1.牛牛的快递 题目链接:牛牛的快递_牛客题霸_牛客网 思路:分小于1.0kg和大于1.0kg,其中大于1.0kg的要“向上取整” ,eg:1.7->2,2.0->2。注意一个点:第二个输入的参数是字符,要…...
android脱壳第二发:grpc-dumpdex加修复
上一篇我写的dex脱壳,写到银行类型的app的dex修复问题,因为dex中被抽取出来的函数的code_item_off 的偏移所在的内存,不在dex文件范围内,所以需要进行一定的修复,然后就停止了。本来不打算接着搞得,但是写了…...
在 TypeScript 中declare module 关键字用法
在 TypeScript 中,declare module 关键字用于声明模块的类型信息,这种声明通常出现在声明文件(通常是 .d.ts 文件)中。这对于当你需要为现有的 JavaScript 库或模块提供类型信息时非常有用,尤其是对于没有提供自己的类…...
NLP step by step -- 了解Transformer
Transformer模型 Transformer相关历史 首先我们先看一下有关Transformer模型的发展历史,下面的图是基于Transformer架构的一些关键模型节点: 图片来源于Hugging Face 图片来源于Hugging Face Transformer 架构 于 2017 年 6 月推出。原本研究的重点是…...
【Leetcode】vector刷题
🔥个人主页:Quitecoder 🔥专栏:Leetcode刷题 目录 1.只出现一次的数字2.杨辉三角3.删除有序数组中的重复项4.只出现一次的数字II5.只出现一次的数字III6.电话号码的字母组合 1.只出现一次的数字 题目链接:136.只出现一…...
【图解计算机网络】从浏览器地址输入到网页显示的整个过程
从浏览器地址输入到网页显示的整个过程 整体流程DHCPhttp协议报文组装DNSTCP协议封装与TCP三次握手IP协议封装与路由表MAC地址与ARP协议交换机路由器 整体流程 从往浏览器输入一个地址到网页的显示,要经过很长的一个流程,中间涉及到计算机网络的许多知识…...
liqo学习及安装,k8s,kubernetes多集群互联
先按照官方的教程在虚拟机安装学习 在开始以下教程之前,您应该确保您的系统上安装了以下软件: Docker,容器运行时。Kubectl,Kubernetes 的命令行工具。 curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.…...
五种主流数据库:集合运算
关系型数据库中的表与集合理论中的集合类似,表是由行(记录)组成的集合。因此,SQL 支持基于数据行的各种集合运算,包括并集运算(Union)、交集运算(Intersect)和差集运算&a…...
java-springmvc 01
springmvc也是在spring framework中的,不是一个单独的项目 MVC就是和Tomcat有关。 01.MVC启动的第一步,启动Tomcat(这个和springboot的run方法启动Tomcat有关) 02.SpringMVC中,最为核心的就是DispatcherServlet&…...
SecuPress Pro 专业级WordPress网站安全防护插件优化版
下载地址:SecuPress Pro 专业版.zip SecuPress Pro:专业的WordPress安全解决方案 如果您没有时间进行每周扫描,SecuPress Pro将是您的理想选择。SecuPress Pro提供了所有SecuPress Free的功能,同时还增加了一些高级选项ÿ…...
linux 查看nginx日志
在 Linux 系统中,查看 Nginx 日志通常涉及以下几个步骤: 确定日志文件位置:Nginx 的日志文件通常位于 /etc/nginx/logs 或 /var/log/nginx。具体位置取决于您在安装 Nginx 时的配置。 查看访问日志:Nginx 的访问日志默认命名为 a…...
iOS - 多线程-GCD-队列组
文章目录 iOS - 多线程-GCD-队列组1. 队列组1.1 基本使用步骤 iOS - 多线程-GCD-队列组 开发过程中,有时候想实现这样的效果 多个任务并发执行所有任务执行完成后,进行下一步处理(比如回到主线程刷新UI) 1. 队列组 可以使用GC…...
1052. 【NOIP2016备赛】方阵操作(square)
1052. 【NOIP2016备赛】方阵操作(square) (Input: square.in, Output: square.out) 时间限制: 1 s 空间限制: 256 MB 题目描述 小 Z 给你一个 n n 的方阵,要求你完成 Q 次操作: 1. 1 i j k,将 ai,j 修改为 k。 2. 2 i j,交…...
Python打怪升级(4)
在计算机领域常常有说"合法"和"非法"指的是:是否合理,是否有效,并不是指触犯了法律。 random.randint(begin,end) 详细讲解一下这个random是指模板,也就是别人写好的代码直接来用,在Python当中,…...
2024年【危险化学品生产单位安全生产管理人员】考试题库及危险化学品生产单位安全生产管理人员考试报名
题库来源:安全生产模拟考试一点通公众号小程序 危险化学品生产单位安全生产管理人员考试题库参考答案及危险化学品生产单位安全生产管理人员考试试题解析是安全生产模拟考试一点通题库老师及危险化学品生产单位安全生产管理人员操作证已考过的学员汇总,…...
动态IP与静态IP的区别,你选对了吗?
在互联网世界中,IP地址是每台设备在网络上的唯一标识。这些地址可以是动态的,也可以是静态的。对于非专业人士来说,理解这两者之间的区别可能会有些困难。本文旨在深入探讨动态IP和静态IP的主要差异,帮助读者根据自己的需求做出明…...
jasypt组件死锁bug案例分享
事故描述 1、上午9.55发布了一个Apollo动态配置参数; 2、片刻后,服务器接口开始出现大量的超时告警,似乎是某资源被耗尽不足分配; 3、正值业务请求高峰的上午十点(平台上午10点会有一些活动会拉一波用户流量&#x…...
golang上传文件到ftp服务器
之前有个业务需要把文件上传到ftp服务器,写了一个上传ftp的功能 package ftpimport "context"type Client interface {// UploadFile 上传文件UploadFile(ctx context.Context, opt *UploadFileOpt) error }type UploadFileOpt struct {Data […...
数据治理和数据管理 傻傻分不清楚?
互联网时代,数据,这一无形资产,已成为现代企业的核心竞争力。如何高效地管理和利用数据,成为企业关注的焦点。在这个过程中,数据治理(Data Governance)和数据管理(Data Management&a…...
linux磁盘原理
在linux系统中,对磁盘进行管理与windows系统类似,都要先分区,格式化,创建文件系统,挂载目录,数据写入...
react 使用WEB3.0控件开发包 V3.0接入海康威视摄像头
1、下载官方安装包: 2、安装官方插件 3、引入文件 在public/index 中引入监控依赖,这三个文件可以在下载的官方demo中找到 4、react 中使用 useEffect(() > { const ipInfo :[192.168.xxxx];//初始化摄像头const WebVideoCtrl window.WebVideoCtrl…...
数据可视化———Tableau
基本认识: 维度:定性—字符串文本,日期和日期时间等等 度量:定量—连续值,一般属于数值 数据类型: 数值 日期/日期时间 字符串 布尔值 地理值 运算符 算数运算符:加减乘除,%取余,…...
【黑马头条】-day12项目部署和发布-jenkins
文章目录 1 持续集成2 软件开发模式2.1 瀑布模式2.2 敏捷开发2.2.1 迭代开发2.2.2 增量开发 3 Jenkins3.1 Jenkins安装3.1.1 导入镜像3.1.2 配置3.1.3 初始化设置 3.2 插件安装3.3 服务器环境准备3.3.1 Docker安装配置3.3.2 Git安装配置3.3.3 Maven安装配置 3.4 Jenkins工具配置…...
学习操作系统路线
操作系统 简介 本课程为计算机专业学生量身定制,补足计算机操作系统相关知识,查漏补缺,也可用于考研复习。内容包括:操作统概述、进程管理、内存管理、文件管理、输入/输出管理等章节。内容力求精炼、重点突出、条理清晰、深入浅…...
uniapp微信小程序(商城项目)
最近,闲来无事,打算学一下uniapp小程序 于是在跟着某站上学着做了一个小程序,主要是为了学uniapp和vue。某站黑马优购 完成的功能主要有:首页、搜索、分类和购物车。 有人问了为什么没有登录、和添加订单呢?问的很好…...
Linux的自动化脚本:使用crul命令下载文件,实现断点续传
目录 一、要求 二、解决思路 (一)curl工具可以进行文件传输,可以实现手动断点续传 1、使用 --range 选项: 2. 使用 --continue-at 选项: (二)编写shell脚本调用curl命令,实现自…...
Golang | Leetcode Golang题解之第46题全排列
题目: 题解: func permute(nums []int) [][]int {var (n len(nums)dfs func(vals []int) // 已选择数 排列为vals 后续回溯继续选择 直至选完ans [][]int)dfs func(vals []int) {//边界if len(vals) n {ans append(ans, vals)}//转移 枚举选哪个f…...
MySQL数据表记录删操作
删除操作 作用删除表里的记录行(都是整行整行的删除的) 1.单表的删除 语法: delete from 表名 where 要删除的记录筛选条件; 案例:删除员工编号大于203的员工信息 delete from employees where employee_id>203; 2.多表…...
Python浅谈清朝秋海棠叶版图
1、清朝疆域概述: 清朝是我国最后一个封建王朝,其始于1616年建州女真部努尔哈赤建立后金,此后统一女真各部、东北地区。后又降服漠南蒙古,1644年入关打败农民起义军、灭南明,削三藩,复台湾。后又收外蒙&am…...
Linux之线程管理
目录 第1关:创建线程 任务描述 相关知识 使用pthread_create函数创建线程 编程要求 答案: 第2关:线程挂起 任务描述 相关知识 使用pthread_join挂起线程 编程要求 答案: 第3关:线程终止 任务描述 相关知识 使用pthread…...
.net反射(Reflection)
文章目录 一.概念:二.反射的作用:三.代码案例:四.运行结果: 一.概念: .NET 反射(Reflection)是指在运行时动态地检查、访问和修改程序集中的类型、成员和对象的能力。通过反射,你可…...
白平衡简介
文章目录 白平衡的概念白平衡的调节常见的白平衡模式 白平衡的概念 白平衡是指摄影、摄像和显示技术中的一项重要概念,用于调节图像中的白色或中性灰色的色彩,使其看起来在不同光源条件下都是准确的白色或灰色。白平衡的主要目的是确保图像的色彩准确性…...
centos7.9下安装SVN服务
一、安装subversion yum install -y subversion #安装svn mkdir -p /data/svnrepos/java #自定义svn仓库位置/data/svnrepos,自定义一个项目叫svn(这里新建目录) svnadmin create /data/svnrepos/java #创建一…...
iStat Menus for Mac:强大的系统监控工具
iStat Menus for Mac是一款功能强大的系统监控工具,专为Mac用户设计,旨在帮助用户全面了解电脑的运行状态,提高电脑的性能和稳定性。 iStat Menus for Mac v6.73 (1239)中文版下载 该软件可以实时监测CPU使用率、内存占用、网络速度、硬盘活动…...
NumPy 1.26 中文官方指南(四)
附加文件 术语表 原文:numpy.org/doc/1.26/glossary.html (n,) 括号中跟着逗号的数字表示一个具有一个元素的元组。尾随逗号将一个元素元组与括号n区分开。 -1 在维度入口中,指示 NumPy 选择长度,以保持数组元素总数不变。 >>> n…...
Python flask
Flask 是一个用 Python 编写的轻量级 Web 应用框架。它被设计为易于使用和扩展,使其成为构建简单网站到复杂的、动态的 web 应用程序的理想选择。以下是 Flask 的一些基本组件和概念: 主要组件 Flask:框架本身,提供基本的功能来处…...
2-token生成
Token是密码学中的一个概念,可以用作身份验证凭证。在计算机领域中,token可以是一个字符串,用于标识用户的身份和权限。当用户进行身份验证时,他们通常会收到一个token,以便在将来的请求中用作凭证。 在互联网应用程序…...
Flutter 上架如何解决 ITMS-91053 问题
最近,我的 Flutter App 发布到 TestFlight 后,就会收到一封邮件:The uploaded build for YOUR APP has one or more issues. 上面的邮件主要是说,我的 App 缺少了调用 API 的声明,以前从来没看到过,上网一查…...
PgSQL的登录相关(Ubuntu22.04)
一 将用户设为密码登录方式 1 修改用户的密码 sudo -u postgres psql -c "ALTER USER yuhui WITH PASSWORD xinmima;" 2 修改配置,指定用户yuhui使用密码登录 sudo vi /etc/postgresql/16/main/pg_hba.conf local all postgres …...
DigitalOcean 应用托管平台级更新:应用端到端运行时性能大幅改进
DigitalOcean 希望可以为企业提供所需的工具和基础设施,以帮助企业客户加速云端的开发,实现业务的指数级增长。为此 DigitalOcean 在 2020 年就推出了App Platform。 App Platform(应用托管) 是一个完全托管的 PaaS 解决方案&…...
mysql 指定根目录 迁移根目录
mysql 指定根目录 迁移根目录 1、问题描述2、问题分析3、解决方法3.1、初始化mysql前就手动指定mysql根目录为一个大的分区(支持动态扩容),事前就根本上解决mysql根目录空间不够问题3.1.0、方法思路3.1.1、卸载mariadb3.1.2、下载Mysql安装包3.1.3、安装Mysql 8.353…...
架构师:搭建Spring Security、OAuth2和JWT 的安全认证框架
1、简述 Spring Security 是 Spring 生态系统中的一个强大的安全框架,用于实现身份验证和授权。结合 OAuth2 和 JWT 技术,可以构建一个安全可靠的认证体系,本文将介绍如何在 Spring Boot 中配置并使用这三种技术实现安全认证,并分析它们的优点。 2、Spring Security Spri…...
用 Go map 要注意这个细节,避免依赖他!
有的小伙伴没留意过 Go map 输出、遍历顺序,以为它是稳定的有序的,会在业务程序中直接依赖这个结果集顺序,结果栽了个大跟头,吃了线上 BUG。 有的小伙伴知道是无序的,但却不知道为什么,有的却理解错误? 今…...
进阶python (集合,collections,itertools)
文章目录 集合创建集合集合操作 (交 并 补)处理集合之间的关系 Collections模块counternamedtupleOrderedDictdeque 集合 创建集合 # unordered mutable myset set() # 方式1 创建一个空集合,随后使用add方法添加元素myset.add(1) myset.add(2) myse…...
第 10 场蓝桥杯小白入门赛题解
1.五一礼物【算法赛】 - 蓝桥云课 (lanqiao.cn) #include <iostream> using namespace std; int main() {cout<<"51"<<endl;return 0; }2.合成贤者之石【算法赛】 - 蓝桥云课 (lanqiao.cn) 假设黄水晶的个数是 x x x,那蓝水晶个数肯定是 x − 1 …...
明火检测实时识别报警:视觉算法助力安全生产管理
背景与现状 在各种工作、生产环境下,明火的存在往往是潜在的安全隐患。无论是加油站、化工园区、仓储场所还是校园,明火一旦失控就会引发火灾,造成严重的人员伤亡和财产损失。传统的明火检查手段主要依赖于人工巡查和定期的消防检查…...
Instagram新号操作攻略:快速起号防封号
对于企业和个人而言,运营好INS可以吸引流量、增加曝光、提升品牌知名度。然而很多人初次接触INS甚至在起号阶段就失败了!今天就教给大家一个可以快速起号的方法,而且不怕被封号! Instagram快速起号的方法 1️⃣ 新号刚注册完 注册…...
STM32使用ESP01S连接阿里云物联网平台
一、ESP01S烧录MQTT固件准备 首先准备好烧录工具,可以从官网上进行下载。 MQTT固件官网网址:AT固件汇总 | 安信可科技 (ai-thinker.com) 进去后如下图界面,向下翻找找到MQTT固件(1471)下载固件即可。 烧录工具光网地…...
【初阶数据结构】时间复杂度
文章目录 基本概念和术语复杂度1.时间复杂度1.1时间复杂度的概念1.2大O渐进表示法1.3常见的时间复杂度计算举例O(1)O(N)O(MN)O(N^2^)O(2^N^)O(log N) 2.空间复杂度2.1空间复杂度的概念2.2常见的空间复杂度举例O(1)O(N) 基本概念和术语 1.数据 :所有能输入到计算机中…...
video标签,如何隐藏右下角三个点包含的功能?
// nodownload: 不要下载 // nofullscreen: 不要全屏 // noremoteplayback: 不要远程回放 // disablePictureInPicture: 不要画中画 <videocontrols disablePictureInPicture"true"controlslist"nodownload nofullscreen noremoteplayback" > </v…...
C++:哈希表和unordered系列容器的封装
一、unordered系列关联式容器的介绍 在C98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到log2N,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想。最好的查询是&…...