基于DLNA实现iOS,Android投屏:SSDP发现设备
SSDP能够在局域网能简单地发现设备提供的服务。SSDP有两种发现方式:主动通知和搜索响应方式。
寻址
UPnP 技术是架构在 IP 网络之上。因此拥有一个网络中唯一的 IP 地址是 UPnP 设备正常工作的基础。UPnP 设备首先查看网络中是否有 DHCP 服务器,如果有,那么使用 DHCP 分配的 IP 即可;如果没有,则需要使用LLA技术来为自己找适合的IP地址。
另外,在 UPnP 运行过程中,UPnP 设备都需要周期性检测网络中是否有 DHCP 服务器存在,一旦发现有 DHCP 服务器,就必须终止使用 LLA 技术获取的 IP 地址,改用 DHCP 分配的 IP 地址。
发现
SSDP
SSDP:Simple Sever Discovery Protocol,简单服务发现协议,此协议为网络客户提供一种无需任何配置、管理和维护网络设备服务的机制。此协议采用基于通知和发现路由的多播发现方式实现。协议客户端在保留的多播地址:239.255.255.250:1900(IPV4)发现服务,(IPv6 是:FF0x::C)同时每个设备服务也在此地址上上监听服务发现请求。如果服务监听到的发现请求与此服务相匹配,此服务会使用单播方式响应。
常见的协议请求消息有两种类型,第一种是服务通知,设备和服务使用此类通知消息声明自己存在;第二种是查询请求,协议客户端用此请求查询某种类型的设备和服务。
iOS中使用GCDAsyncUdpSocket发送和接受SSDP请求、响应及通知,安卓也需要用类此框架来完成
所以我们发现设备也有两种方法
- 主动通知方式:当设备加入到网络中,向网络上所有控制点通知它所提供的服务,通知消息采用多播方式。
- 搜索——响应方式:当一个控制点加入到网络中,在网络搜索它感兴趣的所有设备和服务,搜索消息采用多播方式发送,而设备针对搜索的响应则是使用单播方式发送。
SSDP 设备类型及服务类型
服务类型 | 表示文字 |
---|---|
UPnP_MediaServer1 | urn:schemas-upnp-org:device:MediaServer:1 |
UPnP_MediaRenderer1 | urn:schemas-upnp-org:device:MediaRenderer:1 |
UPnP_ContentDirectory1 | urn:schemas-upnp-org:service:ContentDirectory:1 |
UPnP_RenderingControl1 | urn:schemas-upnp-org:service:RenderingControl:1 |
UPnP_ConnectionManager1 | urn:schemas-upnp-org:service:ConnectionManager:1 |
UPnP_AVTransport1 | urn:schemas-upnp-org:service:AVTransport:1 |
设备类型 | 表示文字 |
---|---|
UPnP_RootDevice | upnp:rootdevice |
UPnP_InternetGatewayDevice1 | urn:schemas-upnp-org:device:InternetGatewayDevice:1 |
UPnP_WANConnectionDevice1 | urn:schemas-upnp-org:device:WANConnectionDevice:1 |
UPnP_WANDevice1 | urn:schemas-upnp-org:device:WANConnectionDevice:1 |
UPnP_WANCommonInterfaceConfig1 | urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1 |
UPnP_WANIPConnection1 | urn:schemas-upnp-org:device:WANConnectionDevice:1 |
UPnP_Layer3Forwarding1 | urn:schemas-upnp-org:service:WANIPConnection:1 |
UPnP_WANConnectionDevice1 | urn:schemas-upnp-org:service:Layer3Forwarding:1 |
主动通知方式
当设备添加到网络后,定期向(239.255.255.250:1900)发送SSDP通知消息宣告自己的设备和服务。
宣告消息分为 ssdp:alive(设备可用)
和ssdp:byebye(设备不可用)
ssdp:alive 消息
1 2 3 4 5 6 7 8 9 10 11 |
NOTIFY * HTTP/1.1 // 消息头 NT: // 在此消息中,NT头必须为服务的服务类型。(如:upnp:rootdevice) HOST: // 设置为协议保留多播地址和端口,必须是:239.255.255.250:1900(IPv4)或FF0x::C(IPv6 NTS: // 表示通知消息的子类型,必须为ssdp:alive LOCATION: // 包含根设备描述得URL地址 device 的webservice路径(如:http://127.0.0.1:2351/1.xml) CACHE-CONTROL: // max-age指定通知消息存活时间,如果超过此时间间隔,控制点可以认为设备不存在 (如:max-age=1800) SERVER: // 包含操作系统名,版本,产品名和产品版本信息( 如:Windows NT/5.0, UPnP/1.0) USN: // 表示不同服务的统一服务名,它提供了一种标识出相同类型服务的能力。如:// 根/启动设备 uuid:f7001351-cf4f-4edd-b3df-4b04792d0e8a::upnp:rootdevice// 连接管理器 uuid:f7001351-cf4f-4edd-b3df-4b04792d0e8a::urn:schemas-upnp-org:service:ConnectionManager:1// 内容管理器 uuid:f7001351-cf4f-4edd-b3df-4b04792d0e8a::urn:schemas-upnp-org:service:ContentDirectory:1 |
ssdp:byebye 消息
当设备即将从网络中退出时,设备需要对每一个未超期的 ssdp:alive
消息多播形式发送ssdp:byebye
消息,其格式如下:
1 2 3 4 |
NOTIFY * HTTP/1.1 // 消息头 HOST: // 设置为协议保留多播地址和端口,必须是:239.255.255.250:1900(IPv4)或FF0x::C(IPv6 NTS: // 表示通知消息的子类型,必须为ssdp:byebye USN: // 同上 |
搜索——响应方式
当控制点,如手机客户端,加入到网络中,可以通过多播搜索消息来寻找网络上感兴趣的设备。我写DLNA模块时候也用主动搜索方式来发现设备。主动搜索可以使用多播方式在整个网络上搜索设备和服务,也可以使用单播方式搜索特定主机上的设备和服务。
多播搜索消息
一般情况我们使用多播搜索消息来搜索所有设备即可。多播搜索消息如下:
1 2 3 4 5 6 7 8 9 10 |
M-SEARCH * HTTP/1.1 // 请求头 不可改变 MAN: "ssdp:discover" // 设置协议查询的类型,必须是:ssdp:discover MX: 5 // 设置设备响应最长等待时间,设备响应在0和这个值之间随机选择响应延迟的值。这样可以为控制点响应平衡网络负载。 HOST: 239.255.255.250:1900 // 设置为协议保留多播地址和端口,必须是:239.255.255.250:1900(IPv4)或FF0x::C(IPv6 ST: upnp:rootdevice // 设置服务查询的目标,它必须是下面的类型:// ssdp:all 搜索所有设备和服务 // upnp:rootdevice 仅搜索网络中的根设备 // uuid:device-UUID 查询UUID标识的设备 // urn:schemas-upnp-org:device:device-Type:version 查询device-Type字段指定的设备类型,设备类型和版本由UPNP组织定义。 // urn:schemas-upnp-org:service:service-Type:version 查询service-Type字段指定的服务类型,服务类型和版本由UPNP组织定义。 |
如果需要实现投屏,则设备类型 ST
为urn:schemas-upnp-org:service:AVTransport:1
多播搜索响应
多播搜索 M-SEARCH
响应与通知消息很类此,只是将NT字段作为ST字段。响应必须以一下格式发送:
1 2 3 4 5 6 7 8 9 10 |
HTTP/1.1 200 OK // * 消息头 LOCATION: // * 包含根设备描述得URL地址 device 的webservice路径(如:http://127.0.0.1:2351/1.xml) CACHE-CONTROL: // * max-age指定通知消息存活时间,如果超过此时间间隔,控制点可以认为设备不存在 (如:max-age=1800) SERVER: // 包含操作系统名,版本,产品名和产品版本信息( 如:Windows NT/5.0, UPnP/1.0) EXT: // 为了符合HTTP协议要求,并未使用。 BOOTID.UPNP.ORG: // 可以不存在,初始值为时间戳,每当设备重启并加入到网络时+1,用于判断设备是否重启。也可以用于区分多宿主设备。 CONFIGID.UPNP.ORG: // 可以不存在,由两部分组成的非负十六进制整数,由两部分组成,第一部分代表跟设备和其上的嵌入式设备,第二部分代表这些设备上的服务。 USN: // * 表示不同服务的统一服务名 ST: // * 服务的服务类型 DATE: // 响应生成时间 |
其中主要关注带有 *
的部分即可。这里还有一个大坑,有些设备返回来的字段名称可能包含有小写,如LOCATION和Location,需要做处理。
此外还需根据LOCATION保存设备的IP和端口地址。
响应例子如下:
1 2 3 4 5 6 7 8 |
HTTP/1.1 200 OK Cache-control: max-age=1800 Usn: uuid:88024158-a0e8-2dd5-ffff-ffffc7831a22::urn:schemas-upnp-org:service:AVTransport:1 Location: http://192.168.1.243:46201/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/desc.xml Server: Linux/3.10.33 UPnP/1.0 Teleal-Cling/1.0 Date: Tue, 01 Mar 2016 08:47:42 GMT+00:00 Ext: St: urn:schemas-upnp-org:service:AVTransport:1 |
描述
控制点发现设备之后仍然对设备知之甚少,仅能知道UPnP类型,UUID和设备描述URL。为了进一步了解设备和服务,需要获取并解析XML描述文件。
描述文件有两种类型:设备描述文档(DDD)
和服务描述文档(SDD)
设备描述文档
设备描述文档是对设备的基本信息描述,包括厂商制造商信息、设备信息、设备所包含服务基本信息等。
设备描述采用XML格式,可以通过HTTP GET请求获取。其链接为设备发现消息中的Location。如上述设备的描述文件获取请求为
1 2 |
GET http://192.168.1.243:46201/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/desc.xml HTTP/1.1 HOST: 192.168.1.243:46201 |
设备响应如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
HTTP/1.1 200 OK Content-Length : 3612 Content-type : text/xml Date : Tue, 01 Mar 2016 10:00:36 GMT+00:00<?xml version="1.0" encoding="UTF-8"?> <root xmlns="urn:schemas-upnp-org:device-1-0" xmlns:qq="http://www.tencent.com"><specVersion><major>1</major><minor>0</minor></specVersion><device><deviceType>urn:schemas-upnp-org:device:MediaRenderer:1</deviceType><UDN>uuid:88024158-a0e8-2dd5-ffff-ffffc7831a22</UDN><friendlyName>客厅的小米盒子</friendlyName><qq:X_QPlay_SoftwareCapability>QPlay:1</qq:X_QPlay_SoftwareCapability><manufacturer>Xiaomi</manufacturer><manufacturerURL>http://www.xiaomi.com/</manufacturerURL><modelDescription>Xiaomi MediaRenderer</modelDescription><modelName>Xiaomi MediaRenderer</modelName><modelNumber>1</modelNumber><modelURL>http://www.xiaomi.com/hezi</modelURL><serialNumber>11262/180303452</serialNumber><presentationURL>device_presentation_page.html</presentationURL><UPC>123456789012</UPC><dlna:X_DLNADOC xmlns:dlna="urn:schemas-dlna-org:device-1-0">DMR-1.50</dlna:X_DLNADOC><dlna:X_DLNACAP xmlns:dlna="urn:schemas-dlna-org:device-1-0">,</dlna:X_DLNACAP><iconList><icon><mimetype>image/png</mimetype><width>128</width><height>128</height><depth>8</depth><url>icon/icon128x128.png</url></icon></iconList><serviceList><service><serviceType>urn:schemas-upnp-org:service:AVTransport:1</serviceType><serviceId>urn:upnp-org:serviceId:AVTransport</serviceId><controlURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/AVTransport/action</controlURL><eventSubURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/AVTransport/event</eventSubURL><SCPDURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/AVTransport/desc.xml</SCPDURL></service><service><serviceType>urn:schemas-upnp-org:service:RenderingControl:1</serviceType><serviceId>urn:upnp-org:serviceId:RenderingControl</serviceId><controlURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/RenderingControl/action</controlURL><eventSubURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/RenderingControl/event</eventSubURL><SCPDURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/RenderingControl/desc.xml</SCPDURL></service><service><serviceType>urn:schemas-upnp-org:service:ConnectionManager:1</serviceType><serviceId>urn:upnp-org:serviceId:ConnectionManager</serviceId><controlURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/ConnectionManager/action</controlURL><eventSubURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/ConnectionManager/event</eventSubURL><SCPDURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/ConnectionManager/desc.xml</SCPDURL></service><service><serviceType>urn:mi-com:service:RController:1</serviceType><serviceId>urn:upnp-org:serviceId:RController</serviceId><controlURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/RController/action</controlURL><eventSubURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/RController/event</eventSubURL><SCPDURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/RController/desc.xml</SCPDURL></service></serviceList><av:X_RController_DeviceInfo xmlns:av="urn:mi-com:av"><av:X_RController_Version>1.0</av:X_RController_Version><av:X_RController_ServiceList><av:X_RController_Service><av:X_RController_ServiceType>controller</av:X_RController_ServiceType><av:X_RController_ActionList_URL>http://192.168.1.243:6095/</av:X_RController_ActionList_URL></av:X_RController_Service><av:X_RController_Service><av:X_RController_ServiceType>data</av:X_RController_ServiceType><av:X_RController_ActionList_URL>http://api.tv.duokanbox.com/bolt/3party/</av:X_RController_ActionList_URL></av:X_RController_Service></av:X_RController_ServiceList></av:X_RController_DeviceInfo></device> </root> |
其中响应消息体为XML格式的设备描述内容。信息结构比较明确,就不一一介绍了。解析该XML,保存设备的一些基本信息如deviceType
、friendlyName
、iconList
等。之后我们关注该设备提供的服务列表,投屏最关注的服务为urn:schemas-upnp-org:service:AVTransport:1
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?xml version="1.0" encoding="UTF-8"?> <root xmlns="urn:schemas-upnp-org:device-1-0" xmlns:qq="http://www.tencent.com"><device><serviceList><service><serviceType>urn:schemas-upnp-org:service:AVTransport:1</serviceType><serviceId>urn:upnp-org:serviceId:AVTransport</serviceId><controlURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/AVTransport/action</controlURL><eventSubURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/AVTransport/event</eventSubURL><SCPDURL>/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/AVTransport/desc.xml</SCPDURL></service></serviceList></device> </root> |
- serviceId : 必有字段。服务表示符,是服务实例的唯一标识。
- serviceType : 必有字段。UPnP服务类型。格式定义与deviceType类此。详看文章开头表格。
- SCPDURL : 必有字段。Service Control Protocol Description URL,获取设备描述文档URL。
- controlURL : 必有字段。向服务发出控制消息的URL,详见 基于DLNA实现iOS,Android投屏:SOAP控制设备
- eventSubURL : 必有字段。订阅该服务时间的URL,详见 基于DLNA实现iOS,Android投屏:SOAP控制设备
如只需要实现简单的投屏,则保存urn:schemas-upnp-org:service:AVTransport:1
服务的上述信息即可。如需要进一步了解该服务,则需要获取并解析服务描述文档。
坑点1:有些设备 SCPDURL
、controlURL
、eventSubURL
开头包含/
,有些设备不包含,拼接URL时需要注意。
服务描述文档
为了实现简单的投屏和控制(播放、暂停、停止、快进)操作并不需要解析服务描述文件。所有动作均为UPnP规范动作,具体动作请求参见基于DLNA实现iOS,Android投屏:SOAP控制设备
服务描述文档是对服务功能的基本说明,包括服务上的动作及参数,还有状态变量和其数据类型、取值范围等。
和设备描述文档一致,服务描述文档也是采用XML语法,并遵守标准UPnP服务schema文件格式要求。获取上述服务SDD语法如下:
1 2 |
GET http://192.168.1.243:46201/dev/88024158-a0e8-2dd5-ffff-ffffc7831a22/svc/upnp-org/AVTransport/desc.xml HOST: 192.168.1.243:46201 |
设备响应如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
HTTP/1.1 200 OK Content-Length : 3612 Content-type : text/xml Date : Tue, 01 Mar 2016 10:00:36 GMT+00:00 <!-- 省略了部分动作和状态变量 --> <?xml version="1.0" encoding="UTF-8"?> <scpd xmlns="urn:schemas-upnp-org:service-1-0"><specVersion><major>1</major><minor>0</minor></specVersion><actionList><action><name>Pause</name><argumentList><argument><name>InstanceID</name><direction>in</direction><relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable></argument></argumentList></action><action><name>Play</name><argumentList><argument><name>InstanceID</name><direction>in</direction><relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable></argument><argument><name>Speed</name><direction>in</direction><relatedStateVariable>TransportPlaySpeed</relatedStateVariable></argument></argumentList></action><action><name>Previous</name><argumentList><argument><name>InstanceID</name><direction>in</direction><relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable></argument></argumentList></action><action><name>SetAVTransportURI</name><argumentList><argument><name>InstanceID</name><direction>in</direction><relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable></argument><argument><name>CurrentURI</name><direction>in</direction><relatedStateVariable>AVTransportURI</relatedStateVariable></argument><argument><name>CurrentURIMetaData</name><direction>in</direction><relatedStateVariable>AVTransportURIMetaData</relatedStateVariable></argument></argumentList></action>...</actionList><serviceStateTable><stateVariable sendEvents="no"><name>CurrentTrackURI</name><dataType>string</dataType></stateVariable><stateVariable sendEvents="no"><name>CurrentMediaDuration</name><dataType>string</dataType></stateVariable><stateVariable sendEvents="no"><name>AbsoluteCounterPosition</name><dataType>i4</dataType></stateVariable><stateVariable sendEvents="no"><name>RelativeCounterPosition</name><dataType>i4</dataType></stateVariable><stateVariable sendEvents="no"><name>A_ARG_TYPE_InstanceID</name><dataType>ui4</dataType></stateVariable>...</serviceStateTable> </scpd> |
- actionList 目前服务上所包含的动作列表。
- actionList 目前服务上所包含的状态变量。
以Pause动作为例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<?xml version="1.0" encoding="UTF-8"?> <scpd xmlns="urn:schemas-upnp-org:service-1-0"><actionList><action><!-- 动作名称 --><name>Pause</name><!-- 参数列表 --><argumentList><argument><!-- 参数名称 --><name>InstanceID</name><!-- 输出或输出--><direction>in</direction><!-- 声明参数有关的状态变量 --><relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable></argument></argumentList></action>...</actionList><serviceStateTable><!-- 状态变量 --><stateVariable><!-- 是否发送事件消息,如果为yes则该状态变量发生变化时生成事件消息。 --><stateVariable sendEvents="no"><!-- 状态变量名称 --><name>A_ARG_TYPE_InstanceID</name><!-- 状态数据类型 --><dataType>ui4</dataType></stateVariable>...</serviceStateTable> </scpd> |
为了实现简单的投屏和控制(播放、暂停、停止、快进)操作并不需要解析服务描述文件。所有动作均为UPnP规范动作,具体动作请求参见基于DLNA实现iOS,Android投屏:SOAP控制设备
基于DLNA实现iOS,Android投屏:SSDP发现设备相关推荐
- Android投屏方案(基于cling)
一 .前言 最近做了一个浏览器&视频播放的项目,是在73.0.3683.90版本的chrome源码上修改而来,涉及到抓取网页里视频的播放地址.播放视频.视频投屏.视频下载.网页内广告屏蔽等方面 ...
- 基于DLNA实现iOS、Android投屏:基本概念
http://geek.csdn.net/news/detail/58920 由于我司需求,需要在iOS和安卓客户端实现DLNA投屏和控制.经过一番折腾,决定由我来研究DLNA.说起来又兴奋又紧张,兴 ...
- 基于DLNA实现iOS、Android投屏
由于我司需求,需要在iOS和安卓客户端实现DLNA投屏和控制.经过一番折腾,决定由我来研究DLNA.说起来又兴奋又紧张,兴奋希望自己能够弄出来然后跟安卓组讲解原理,紧张是因为怕自己能力不足做不出来. ...
- DLNA系列1:投屏到BubbleUpnp播放器出错的解决
今天开始着手分析DLNA源码,碰到了第一个棘手的问题,项目可以投屏到 Windows Media Player,却无法投屏到 BubbleUpnp播放器,通过代码跟踪,最终问题还是得到了解决.而要弄清 ...
- linux 投屏软件,Scrcpy - Android投屏软件
Scrcpy是一款开源的Android投屏软件,适用于大部分安卓设备.此应用程序可显示和控制通过USB(或通过TCP / IP)连接的Android设备.它不需要任何根访问权限.它可以在GNU/Lin ...
- 在Ubuntu中安装Android投屏软件scrcpy
文章目录 前言 1.安装 2.使用 3.scrcpy 常见使用 前言 在前面有介绍在win10中如何使用scrcpy进行Android投屏,之所以这样操作,是因为当我们手头开发板没有屏幕的时候,就可以 ...
- Android - 投屏工具 scrcpy
引用 https://github.com/Genymobile/scrcpy 前言 在 App 开发过程当中,低头操作手机会很别扭,为了降低低头频率,有两种方法可以解决该问题: 在某宝上买一个手机支 ...
- AirServer自动接收多画面投屏或者跨设备投屏
AIrServer是一款ios投屏到mac的专用软件,可将iOS上的音频,视频,照片,幻灯片和镜像接收功通过AIrPlay投射到Mac.AIrserver 最新版可以实现将手机上的媒体文件以及其他操作 ...
- android 投屏开发框架,Android DLNA投屏-基于CyberGarage开发投屏功能
在上一篇博客<Android DLNA投屏-基本原理>中,讲到了DLNA的一些基本原理.了解这些基本原理,对开发是很有帮助的.但仅仅依据原理去进行Android DLNA开发,是比较困难的 ...
最新文章
- hdu 2005 第几天?(c语言)
- 临床预测模型开发checklist详解
- mysql,mybatis常用小知识点
- JAVA中数组Array与List互转
- Android编程获取手机型号,本机电话号码,sdk版本及firmware版本号(即系统版本号)...
- 自定义的html radio button的样式
- 华为第二批“十大军团”正式成立!
- [转载] Python机器学习库scikit-learn使用小结(二)
- Linux printf()占位符
- 计算机上已安装某个第三方应用程序,防止电脑第三方软件“被”安装 3招彻底屏蔽不明软件...
- 正确理解MySQL中的where和having的区别
- [私人] T460p上运行orbit_js报ERR_NO_ICU的问题
- 深度学习入门:基于Python的理论与实现——第一章Python入门
- KMO检验和Bartlett球形检验
- 一份硬核计算机科学CS自学计划
- python 008 __ 小斌文档 | 元组
- Android 进阶之路《丢掉初学者的诟病》
- 【转帖】楚狂人的 DriverNetworks开发网络驱动教材(0-7课)
- 使用函数调用 输出三个数中的最大值,最小值
- 支付宝账号转账/扫码即可到转账页
热门文章
- 教培机构、讲师的6大痛点
- php实现试看功能,据说是视频试看功能的js代码,共享给大家,POSCMS,CodeIgniter技术文档,PHP开发文档,迅睿CMS框架官方教程...
- PT_中心极限定理CLT:棣莫佛-拉普拉斯定理de Moivre - Laplace CLT+林德伯格-列维(Lindeberg-Levy)定理
- 整理*软件测试的方法一共有几种
- Zifeng Wu的38层网络:Wider or Deeper: Revisiting the ResNet Model for Visual Recognition
- PB12.5版串口助手
- Fat32、NTFS和exFAT格式
- power linux 安装系统,在Linux系统中安装/使用PowerShell Core 6.0
- 【WLAN】Wi-Fi Direct 用户指南
- 人工智能-逻辑回归、分类评估方法、ROC曲线、类别不平衡