• ssdp协议搜索GB28181设备


    1、http协议和ssdp协议

    ssdp协议近似于http协议,事实上,和http协议相似得地方就是他得协议内容,当然,我们要去除他得端口和d类地址。

    为什么我在给其他员工或者面试得时候要他人深入一些,理解一下http协议,是因为理解了http协议,掌握ssdp也就不远了,很多人可能会问:http协议有啥内容,无非就是get,post,put,delete 么,还能怎么样,我经常问他们一点:http协议怎么知道他结束了?

    大部分面试者支支吾吾答不出来,就这么奇怪,有一部分人说socket.close(), socket 关闭是因为你知道结束了才关闭,不是因为关闭知道http协议结束。两个\r\n\r\n代表http协议内容部分结束,至于二进制,当然有content-length 字段去表述了。我们来看一下ssdp协议:

    static const char* ssdp_search =
    "M-SEARCH * HTTP/1.1"
    "HOST: 239.255.255.250:1900"
    "MAN: \"ssdp:discover\""
    "MX: 5"
    "ST: ssdp:all";
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这代表了搜索所有设备,这样对否,能出结果否,在239.255.255.250 这种d类ip地址上,端口1900发出该字符串,应该收到很多设备发出得信息,例如摄像头信息,你一定会搜到,不过,这一段代码搜索不到?为什么?看正确得写法:

    static const char* ssdp_search =
    "M-SEARCH * HTTP/1.1\r\n"
    "HOST: 239.255.255.250:1900\r\n"
    "MAN: \"ssdp:discover\"\r\n"
    "MX: 5\r\n"
    "ST: ssdp:all\r\n\r\n";
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    虽然ssdp是udp协议,但是他依然需要\r\n来代表行结束,\r\n\r\n代表协议内容部分结束。这样,就会搜索到所有信息,当然了,我们可以使用过滤,只搜索部分协议,比如就是摄像头,其他设备忽略。

    2、发现谁在发现

    除了搜索设备,我们还需要知道谁往我们得服务地址发送了搜索地址得需求,因为我们是一个设备,其他在gb28181 服务中,我们需要知道sip 网守和网关得设备,可能有多个这种设备,我们则需要知道谁正需要发现设备,我们写出以下代码:

    #include   
    #include   
    #include   
    #pragma comment(lib, "ws2_32.lib")
    
    int main_2()
    {
    	int iRet = 0;
    	WSADATA wsaData;
    	WSAStartup(MAKEWORD(2, 2), &wsaData);
    
    	SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
    
    	sockaddr_in addr;
    	addr.sin_family = AF_INET;
    	//addr.sin_addr.S_un.S_addr = INADDR_ANY;
    	addr.sin_addr.S_un.S_addr = inet_addr("192.168.0.129");
    	addr.sin_port = htons(1900);
    
    	bool bOptval = true;
    	iRet = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&bOptval, sizeof(bOptval));
    	if (iRet != 0) {
    		printf("setsockopt fail:%d", WSAGetLastError());
    		return -1;
    	}
    
    	iRet = ::bind(sock, (sockaddr*)&addr, sizeof(addr));
    	if (iRet != 0) {
    		printf("bind fail:%d", WSAGetLastError());
    		return -1;
    	}
    	printf("socket:%d bind success\n", sock);
    
    	// 加入组播  
    	ip_mreq multiCast;
    	//multiCast.imr_interface.S_un.S_addr = INADDR_ANY;
    	multiCast.imr_interface.S_un.S_addr = inet_addr("192.168.0.129");
    	multiCast.imr_multiaddr.S_un.S_addr = inet_addr("239.255.255.250");
    	iRet = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&multiCast, sizeof(multiCast));
    	if (iRet != 0) {
    		printf("setsockopt fail:%d", WSAGetLastError());
    		return -1;
    	}
    
    	printf("udp group start\n");
    
    	int len = sizeof(sockaddr);
    	char strRecv[1500] = { 0 };
    	while (true)
    	{
    		memset(strRecv, 0, sizeof(strRecv));
    		iRet = recvfrom(sock, strRecv, sizeof(strRecv) - 1, 0, (sockaddr*)&addr, &len);
    		if (iRet <= 0) {
    			printf("recvfrom fail:%d", WSAGetLastError());
    			return -1;
    		}
    		printf("recv data:%s\n", strRecv);
    	}
    
    	closesocket(sock);
    	WSACleanup();
    
    	return 0;
    }
    
    • 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

    以上代码是windows示例,也可以用asio来制作,都一样。
    在这里插入图片描述
    可以看出有很多设备正在发ssdp协议,这样,找到自己感兴趣得ssdp设备,给他回信息就行。

    3、标明我是谁

    ssdp 简单服务发现协议最本质得关键还是在于服务得发现,反过来,不就是让对方发现我是谁,

    static const char* ssdp_resinfo =
    "HTTP/1.1 200 OK\r\n"
    "CACHE-CONTROL:max-age=seconds\r\n"
    "DATE:2022-07-09\r\n"
    "EXT:\r\n"
    "LOCATION: URL for UPnP description for root device\r\n"
    "SERVER : OS / Version UPNP / 1.0 product / version\r\n"
    "ST:search target\r\n"
    "USN:advertisement UUID\r\n\r\n";
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    以下是摄像头返回得信息

    HTTP/1.1 200 OK
    CACHE-CONTROL: max-age=3600
    DATE: Tue, 02 Aug 2022 14:44:45 GMT
    EXT:
    LOCATION: http://192.168.0.64:49152/upnpdevicedesc.xml
    SERVER: Linux/4.9.37, UPnP/1.0, Portable SDK for UPnP devices/1.6.21
    ST: urn:schemas-upnp-org:service:EmbeddedNetDeviceControl:1
    USN: uuid:Upnp-iDS-ECD8012-M/E-1_0-F84224570::urn:schemas-upnp-org:service:EmbeddedNetDeviceControl:1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    使用http协议解析以后,在获取LOCATION 地址,使用httpclient 访问地址,返回如下xml内容

    <root xmlns="urn:schemas-upnp-org:device-1-0">
    <specVersion>
    <major>1major>
    <minor>0minor>
    specVersion>
    <device>
    <deviceType>urn:schemas-upnp-org:device:DigitalSecurityCamera:1deviceType>
    <friendlyName>HIKVISION iDS-ECD8012-M/E - F84224570friendlyName>
    <manufacturer>HIKVISIONmanufacturer>
    <manufacturerURL>http://www.hikvision.commanufacturerURL>
    <modelDescription>IP CameramodelDescription>
    <modelName>HIKVISION iDS-ECD8012-M/EmodelName>
    <modelNumber>iDS-ECD8012-M/EmodelNumber>
    <modelURL>http://www.hikvision.commodelURL>
    <serialNumber>F84224570serialNumber>
    <UDN>uuid:Upnp-iDS-ECD8012-M/E-1_0-F84224570UDN>
    <serviceList>
    <service>
    <serviceType>urn:schemas-upnp-org:service:EmbeddedNetDeviceControl:1serviceType>
    <serviceId>urn:upnp-org:serviceId:EmbeddedNetDeviceControlserviceId>
    <controlURL>/controlURL>
    <eventSubURL>/eventSubURL>
    <SCPDURL>/SCPDURL>
    service>
    serviceList>
    <presentationURL>http://192.168.0.64:80presentationURL>
    device>
    root>
    
    • 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

    从中可以发现很多信息
    那么现在我们得GB28181 服务有sip 服务,网关服务,中心节点服务,存储服务,推理服务,我们就必须标明自己得设备,并且写好XML文件,让对方获取,我们当然不必墨守成规,可以改成其他形式得文件,不过要考虑兼容性。

    封装测试

    在ssdp协议封装过程中,最为重要得一定是这个注意点,就是本机IP和主播地址IP,我们必须设置两个地址,在windows里面和linux下表现不同,必须要注意

    int main(int argc, char* argv[])
    {
    	asio::io_context io_service;
    	receiver r(io_service,
    		asio::ip::address::from_string("192.168.0.129"),
    		asio::ip::address::from_string("239.255.255.250"));
    
    	thread t([&r,&io_service] {
    		r.do_init("192.168.0.129");
    		r.StartTimer();
    		io_service.run();
    	});
    
    	while (1)
    	{
    		Sleep(3000);
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
  • 相关阅读:
    24计算机考研调剂 | 长江大学
    【常见开源库的二次开发】基于openssl的加密与解密——Base58比特币钱包地址——算法分析(三)
    SpringCloud-Bus
    CentOS7 PXE配合Kickstart实现无人值守自动装机 超详细
    浏览器中的history详解
    数据集收集列表(opencv,机器学习,深度学习)持续更新
    【大话Presto 】- 核心概念
    (二开)Flink 修改源码拓展 SQL 语法
    Android性能优化系列-腾讯matrix-流量监控之TrafficPlugin源码分析
    磨金石教育插画干货分享|日本插画为什么独树一帜,那么受欢迎
  • 原文地址:https://blog.csdn.net/qianbo042311/article/details/126119949