当前位置:   article > 正文

设备发现协议SSDP实现_239.255.255.250

239.255.255.250

原理:

1.将socket加入239.255.255.250,端口 1900

2.客户端:通过设置setsockopt +IPPROTO_IP,IP_ADD_MEMBERSHIP属性,可向ssdp组进行组播。

3.服务端:通过设置绑定239.255.255.250:1900进行数据接收,通过setsockopt +IPPROTO_IP,IP_ADD_MEMBERSHIP属性 加入组播

容易错误的地方:

服务端打印sendto成功,但是通过wireshark抓包发现没有组播发送到239.255.255.250

这是因为:sendto的时候,用的sockaddr_in是通过recvfrom得到的:recvfrom得到的是具体的某个从组播拷贝的数据的源ip,这是单播。如果要组播发送,则要发送到这个地址:
    m_cddr.sin_family = AF_INET;
    m_cddr.sin_addr.s_addr = inet_addr("239.255.255.250");
    m_cddr.sin_port = htons(1900);

客户端代码:

  1. /*
  2. Author:zhuoyong
  3. Date:2022-04-07
  4. Mark:人脸识别客户端代码
  5. */
  6. #ifndef CSSDPCLIENT_H
  7. #define CSSDPCLIENT_H
  8. #include<string>
  9. #include<string.h>
  10. #include<queue>
  11. #include<stdio.h>
  12. #include<stdlib.h>
  13. #include<arpa/inet.h>
  14. #include<thread>
  15. #include<chrono>
  16. #include<unistd.h>
  17. #include<netinet/in.h>
  18. #include<arpa/inet.h>
  19. #include<net/if.h>
  20. #include<pthread.h>
  21. #include<fcntl.h>
  22. #define ERR printf
  23. #define RTM printf
  24. #define MAXSSDPSIZE 1024
  25. using namespace std;
  26. class CSSDPClient
  27. {
  28. public:
  29. static void Discover();
  30. //最终加密后的pssword=:md5(<uuid>:<uid>:<pwd>)
  31. static void ModifyNet(string &strUuid,string&strUid,string&strPwd,string &strMask,string&strGateway,string &strDns);
  32. //strCryptPwd=base64(AES(pwd))
  33. static void ModifyUser(string &strUuid,string&strUid,string&strPwd);
  34. protected:
  35. CSSDPClient();
  36. ~CSSDPClient();
  37. void SendMsg(const string&str);
  38. void RecvMsg();
  39. void NotifyOne(const string&str);
  40. string MakeSSDHeader();
  41. string MakeSearchMsg();
  42. string MakeModifyNetMsg();
  43. string MakeModifyUserMsg();
  44. static CSSDPClient *Ins();
  45. void InerDiscover(const string&str);
  46. void InitSocket();
  47. private:
  48. static CSSDPClient * g_in;
  49. sockaddr_in m_sddr ;
  50. int m_ssdps;
  51. queue<string> m_que;
  52. pthread_cond_t m_cd;
  53. pthread_mutex_t m_mt;
  54. };
  55. #endif // CSSDPCLIENT_H
  1. /*
  2. * ===========================================================================
  3. *
  4. * Filename: SSDPClient.cpp
  5. * Description: 客户端设备发现 xml协议
  6. * Version: 1.0
  7. * Created: 20220406-12:07
  8. * Revision: none
  9. * Compiler: g++
  10. * Author: (zhouyongku),
  11. * Company:
  12. *
  13. * ===========================================================================
  14. */
  15. #include"SSDPClient.h"
  16. CSSDPClient *CSSDPClient::g_in=NULL;
  17. //全局变量
  18. //解析IP地址
  19. CSSDPClient::CSSDPClient()
  20. {
  21. m_mt=PTHREAD_MUTEX_INITIALIZER;
  22. m_cd=PTHREAD_COND_INITIALIZER;
  23. std::thread t([&]
  24. {
  25. InitSocket();
  26. while(true)
  27. {
  28. pthread_mutex_lock(&m_mt); // 拿到互斥锁,进入临界区
  29. if( m_que.size()<=0 )pthread_cond_wait(&m_cd,&m_mt); // 令线程等待在条件变量上
  30. pthread_mutex_unlock(&m_mt); // 释放互斥锁
  31. InerDiscover(m_que.front());
  32. m_que.pop();
  33. }
  34. });
  35. t.detach();
  36. }
  37. CSSDPClient::~CSSDPClient()
  38. {
  39. }
  40. CSSDPClient *CSSDPClient::Ins()
  41. {
  42. if( CSSDPClient::g_in == nullptr )
  43. {
  44. CSSDPClient::g_in = new CSSDPClient();
  45. }
  46. return CSSDPClient::g_in;
  47. }
  48. void CSSDPClient::InerDiscover(const string&str)
  49. {
  50. SendMsg( str );
  51. RecvMsg( );
  52. }
  53. void CSSDPClient::InitSocket()
  54. {
  55. struct timeval TimeOut;
  56. TimeOut.tv_sec = 1;
  57. TimeOut.tv_usec = 0;
  58. m_ssdps=socket(AF_INET,SOCK_DGRAM,0);
  59. if( m_ssdps < 0)
  60. {
  61. ERR("CSSDPClient::InitSocket failed of create socket 239.255.255.250:1900");
  62. return;
  63. }
  64. bzero(&m_sddr, sizeof(m_sddr));
  65. m_sddr.sin_family = AF_INET;
  66. m_sddr.sin_addr.s_addr = inet_addr("239.255.255.250");
  67. m_sddr.sin_port = htons(1900);
  68. setsockopt(m_ssdps, SOL_SOCKET, SO_RCVTIMEO, (char *)&TimeOut, sizeof(TimeOut));
  69. ip_mreq mreq;
  70. bzero(&mreq,sizeof(mreq));
  71. mreq.imr_multiaddr.s_addr =inet_addr("239.255.255.250");
  72. mreq.imr_interface.s_addr =htonl(INADDR_ANY);
  73. if( setsockopt(m_ssdps, IPPROTO_IP,IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) <0 )
  74. {
  75. ERR("CSSDPServer::InitSocket failed of setsockopt IP_ADD_MEMBERSHIP");
  76. return;
  77. }
  78. // if( bind(m_ssdps, (struct sockaddr *)&m_sddr, sizeof(m_sddr)) < 0 )
  79. // {
  80. // ERR("CSSDPClient::InitSocket failed of bind socket %s:%d",SSDP_MCAST_ADDR,SSDP_PORT);
  81. // }
  82. }
  83. void CSSDPClient::Discover()
  84. {
  85. string str=CSSDPClient::Ins()->MakeSearchMsg();
  86. CSSDPClient::Ins()->NotifyOne(str);
  87. }
  88. void CSSDPClient::ModifyNet(string &strUuid, string &strUid, string &strPwd, string &strMask, string &strGateway, string &strDns)
  89. {
  90. string str=CSSDPClient::Ins()->MakeModifyNetMsg();
  91. CSSDPClient::Ins()->NotifyOne(str);
  92. }
  93. void CSSDPClient::ModifyUser(string &strUuid, string &strUid, string &strPwd)
  94. {
  95. string str=CSSDPClient::Ins()->MakeModifyUserMsg();
  96. CSSDPClient::Ins()->NotifyOne(str);
  97. }
  98. void CSSDPClient::NotifyOne(const string&str)
  99. {
  100. RTM("CSSDPClient::NotifyOne quesize=%d",m_que.size());
  101. pthread_mutex_lock(&m_mt); // 拿到互斥锁,进入临界区
  102. m_que.push( str );
  103. pthread_cond_signal(&m_cd); // 通知等待在条件变量上的消费者
  104. pthread_mutex_unlock(&m_mt); // 释放互斥锁
  105. }
  106. string CSSDPClient::MakeSSDHeader()
  107. {
  108. string strMsg="M-SEARCH * HTTP/1.1\n";
  109. strMsg +="HOST: 239.255.255.250:1900\n";
  110. strMsg +="MAN: \"ssdp:discover\"\n";
  111. strMsg +="MX: 1\n";
  112. strMsg +="ST: urn:dial-multiscreen-org:service:dial:1\n";
  113. strMsg +="USER-AGENT:arm\n";
  114. return strMsg;
  115. }
  116. string CSSDPClient::MakeSearchMsg()
  117. {
  118. string strMsg=MakeSSDHeader();
  119. strMsg +="<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
  120. strMsg +="<Probe>\n";
  121. strMsg +=" <Uuid>";
  122. strMsg += "uuid-test";
  123. strMsg +="</Uuid>\n";
  124. strMsg +=" <Types>inquiry</Types>\n";
  125. strMsg +=" <DeviceType>";
  126. strMsg += "wodepingban";
  127. strMsg +="</DeviceType>\n";
  128. strMsg +="</Probe>";
  129. return strMsg;
  130. }
  131. string CSSDPClient::MakeModifyNetMsg()
  132. {
  133. string strMsg=MakeSSDHeader();
  134. char szMsg[MAXSSDPSIZE]={0};
  135. sprintf( szMsg,
  136. "%s\n"
  137. "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
  138. "<Probe>\n"
  139. "<Uuid>testuuid</Uuid>\n"
  140. "<Types>update</Types>\n"
  141. "<DeviceSN>123456sdflsdfjl1023-1asdfgh</DeviceSN>\n"
  142. "<method>modifyipdns</method>\n"
  143. "<MAC>ab-cd-ef-gh-kh</MAC>\n"
  144. "<IPv4Address>192.168.66.24</IPv4Address>\n"
  145. "<IPv4SubnetMask>255.255.255.0</IPv4SubnetMask>\n"
  146. "<IPv4Gateway>192.168.66.254</IPv4Gateway>\n"
  147. "<IPv6Address>::</IPv6Address>\n"
  148. "<IPv6Gateway>::</IPv6Gateway>\n"
  149. "<IPv6MaskLen>64</IPv6MaskLen>\n"
  150. "<DHCP>false</DHCP>\n"
  151. "<Password>kFnsMaQrzmGi89g+6txepC1RNnZMSi/fA16x+UdjFOmqBmoVCc/zeZ8X6oZmLBdWaXnvwTxjLIQBsLsDP0xjHw==</Password>\n"
  152. "</Probe>\n",
  153. strMsg.c_str());
  154. return string(szMsg);
  155. }
  156. string CSSDPClient::MakeModifyUserMsg()
  157. {
  158. string strMsg=MakeSSDHeader();
  159. char szMsg[MAXSSDPSIZE]={0};
  160. sprintf( szMsg,
  161. "%s\n"
  162. "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
  163. "<Probe>\n"
  164. "<Uuid>your uuid>\n"
  165. "<Types>update</Types>\n"
  166. "<DeviceSN>your device sn</DeviceSN>\n"
  167. "<method>modifypassword</method>\n"
  168. "<newpassword>your new md5 password</newpassword>\n"
  169. "<Password>your md5 password</Password>\n"
  170. "</Probe>\n");
  171. return string(szMsg);
  172. }
  173. //发送ssdp:discover消息
  174. void CSSDPClient::SendMsg(const string&str)
  175. {
  176. RTM("CSSDPClient::SendMsg msg=%s",str.c_str());
  177. socklen_t len = sizeof(m_sddr);
  178. int nRet=sendto(m_ssdps,str.c_str(),str.length(),0,(sockaddr*)&m_sddr,len);
  179. if( nRet >0 )
  180. {
  181. RTM("CSSDPClient::SendMsg leng=%d",nRet);
  182. }
  183. char szMsg[MAXSSDPSIZE]={0};
  184. nRet = recvfrom( m_ssdps,szMsg,MAXSSDPSIZE,0,(sockaddr*)&m_sddr,&len);
  185. if( nRet >0 )
  186. {
  187. RTM("CSSDPClient::SendMsg RECV MSG=%s",szMsg);
  188. }
  189. }
  190. void CSSDPClient::RecvMsg()
  191. {
  192. socklen_t len = sizeof(m_sddr);
  193. char szMsg[MAXSSDPSIZE]={0};
  194. int num = recvfrom(m_ssdps,szMsg,MAXSSDPSIZE,0,(sockaddr*)&m_sddr,&len);
  195. if( num >0 )
  196. {
  197. string str;
  198. //ParseMsg(buf);
  199. }
  200. }

服务端:

  1. #ifndef CSSDPSERVER_H
  2. #define CSSDPSERVER_H
  3. /*
  4. Author:zhuoyong
  5. Date:2022-04-07
  6. Mark:设备发现服务端代码
  7. */
  8. #include<string>
  9. #include<string.h>
  10. #include<queue>
  11. #include<stdio.h>
  12. #include<stdlib.h>
  13. #include<arpa/inet.h>
  14. #include<thread>
  15. #include<chrono>
  16. #include<unistd.h>
  17. #include<netinet/in.h>
  18. #include<arpa/inet.h>
  19. #include<net/if.h>
  20. #include<pthread.h>
  21. #include<fcntl.h>
  22. #include<mutex>
  23. #define ERR printf
  24. #define RTM printf
  25. #define MAXSSDPSIZE 1024
  26. using namespace std;
  27. class CSSDPServer
  28. {
  29. public:
  30. static void Init( );
  31. protected:
  32. CSSDPServer( );
  33. ~CSSDPServer();
  34. void SendMsg(const string&str);
  35. void RecvMsg();
  36. string MakeSSDHeader();
  37. string MakeResponseSearchMsg( );
  38. static CSSDPServer *Ins();
  39. void InitSendSocket();
  40. void InitRecvSocket();
  41. void ProcesMsg( const char *strMsg );
  42. private:
  43. static CSSDPServer * g_in;
  44. sockaddr_in m_sddr ;
  45. sockaddr_in m_cddr ;
  46. int m_ssdps;
  47. int m_ssdpc;
  48. queue<string> m_que;
  49. pthread_cond_t m_cd;
  50. pthread_mutex_t m_mt;
  51. };
  52. #endif // CSSDPSERVER_H
  1. /*
  2. * ===========================================================================
  3. *
  4. * Filename: SSDPServer.cpp
  5. * Description: 服务端设备发现 xml协议
  6. * Version: 1.0
  7. * Created: 20220406-12:07
  8. * Revision: none
  9. * Compiler: g++
  10. * Author: (zhouyongku),
  11. * Company:
  12. *
  13. * ===========================================================================
  14. */
  15. #include"SSDPServer.h"
  16. CSSDPServer *CSSDPServer::g_in=NULL;
  17. //全局变量
  18. //解析IP地址
  19. CSSDPServer::CSSDPServer( )
  20. {
  21. m_mt=PTHREAD_MUTEX_INITIALIZER;
  22. m_cd=PTHREAD_COND_INITIALIZER;
  23. RTM("CSSDPServer::CSSDPServer");
  24. std::thread t([&]
  25. {
  26. RTM("CSSDPServer::CSSDPServer create thread");
  27. InitSendSocket();
  28. InitRecvSocket();
  29. char szMsg[MAXSSDPSIZE]={0};
  30. socklen_t len = sizeof(m_sddr);
  31. while( true )
  32. {
  33. if((recvfrom(m_ssdps, szMsg, MAXSSDPSIZE, 0, (sockaddr*)&m_sddr, &len)) >= 0)
  34. {
  35. //printf("recvfrom success ip=%s,msg=%s",inet_ntoa(m_sddr.sin_addr),szMsg);
  36. ProcesMsg( szMsg );
  37. memset(szMsg,0,sizeof(szMsg));
  38. }
  39. std::this_thread::sleep_for(std::chrono::seconds(10));
  40. }
  41. });
  42. t.detach();
  43. }
  44. void CSSDPServer::ProcesMsg( const char *strMsg )
  45. {
  46. //and your code here
  47. SendMsg( MakeResponseSearchMsg( ) );
  48. }
  49. CSSDPServer::~CSSDPServer()
  50. {
  51. }
  52. CSSDPServer *CSSDPServer::Ins( )
  53. {
  54. if( CSSDPServer::g_in == nullptr )
  55. {
  56. CSSDPServer::g_in = new CSSDPServer( );
  57. }
  58. return CSSDPServer::g_in;
  59. }
  60. void CSSDPServer::InitSendSocket()
  61. {
  62. struct timeval TimeOut;
  63. TimeOut.tv_sec = 1;
  64. TimeOut.tv_usec = 0;
  65. m_ssdpc=socket(AF_INET,SOCK_DGRAM,0);
  66. if( m_ssdpc < 0)
  67. {
  68. ERR("CSSDPClient::InitSocket failed of create socket 239.255.255.250:1900");
  69. return;
  70. }
  71. bzero(&m_cddr, sizeof(m_cddr));
  72. m_cddr.sin_family = AF_INET;
  73. m_cddr.sin_addr.s_addr = inet_addr("239.255.255.250");
  74. m_cddr.sin_port = htons(1900);
  75. setsockopt(m_ssdpc, SOL_SOCKET, SO_RCVTIMEO, (char *)&TimeOut, sizeof(TimeOut));
  76. ip_mreq mreq;
  77. bzero(&mreq,sizeof(mreq));
  78. mreq.imr_multiaddr.s_addr =inet_addr("239.255.255.250");
  79. mreq.imr_interface.s_addr =htonl(INADDR_ANY);
  80. if( setsockopt(m_ssdpc, IPPROTO_IP,IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) <0 )
  81. {
  82. ERR("CSSDPServer::InitSocket failed of setsockopt IP_ADD_MEMBERSHIP");
  83. return;
  84. }
  85. }
  86. void CSSDPServer::InitRecvSocket()
  87. {
  88. RTM("CSSDPServer::InitRecvSocket");
  89. struct timeval TimeOut;
  90. TimeOut.tv_sec = 1;
  91. TimeOut.tv_usec = 0;
  92. m_ssdps=socket(AF_INET,SOCK_DGRAM,0);
  93. if( m_ssdps < 0)
  94. {
  95. ERR("CSSDPServer::InitSocket failed of create socket 239.255.255.250:1900");
  96. return;
  97. }
  98. bzero(&m_sddr, sizeof(m_sddr));
  99. m_sddr.sin_family = AF_INET;
  100. m_sddr.sin_addr.s_addr = INADDR_ANY;
  101. m_sddr.sin_port = htons(1900);
  102. if( bind(m_ssdps, (struct sockaddr *)&m_sddr, sizeof(m_sddr)) < 0 )
  103. {
  104. ERR("CSSDPServer::InitSocket failed of bind socket 0.0.0.0:1900");
  105. return ;
  106. }
  107. ip_mreq mreq;
  108. bzero(&mreq,sizeof(mreq));
  109. mreq.imr_multiaddr.s_addr =inet_addr("239.255.255.250");
  110. mreq.imr_interface.s_addr =htonl(INADDR_ANY);
  111. if( setsockopt(m_ssdps, IPPROTO_IP,IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) <0 )
  112. {
  113. ERR("CSSDPServer::InitSocket failed of setsockopt IP_ADD_MEMBERSHIP");
  114. return;
  115. }
  116. RTM("CSSDPServer::InitRecvSocket success");
  117. }
  118. void CSSDPServer::Init( )
  119. {
  120. CSSDPServer::Ins( );
  121. }
  122. string CSSDPServer::MakeSSDHeader()
  123. {
  124. string strMsg="NOTIFY * HTTP/1.1\n"
  125. "HOST: 239.255.255.250:1900\n"
  126. "CACHE-CONTROL: max-age=66\n"
  127. "LOCATION:xml\n"
  128. "OPT:ns=01\n"
  129. "01-NLS:0\n"
  130. "NT: urn:schemas-upnp-org:service:AVTransport:1\n"
  131. "NTS: ssdp:alive\n"
  132. "SERVER: Ubuntu/16.04\n"
  133. "X-User-Agent: redsonic\n"
  134. "USN:1\n";
  135. return strMsg;
  136. }
  137. string CSSDPServer::MakeResponseSearchMsg()
  138. {
  139. string strMsg=MakeSSDHeader();
  140. char szMsg[MAXSSDPSIZE]={0};
  141. snprintf( szMsg,MAXSSDPSIZE,
  142. "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
  143. "<ProbeMatch>\n"
  144. "<mount>your msg</mount>\n"
  145. "<enable>your msg</enable>\n"
  146. "<platformip>%s</platformip>\n"
  147. "<Uuid>your msg</Uuid>\n"
  148. "<Types>inquiry</Types>\n"
  149. "<DeviceType>CDZSFACEBOX</DeviceType>\n"
  150. "<DeviceSN>your msg</DeviceSN>\n"
  151. "<DeviceName>your msg</DeviceName>\n"
  152. "<MAC>your msg</MAC>\n"
  153. "<IPv4Address>your msg</IPv4Address>\n"
  154. "<IPv4SubnetMask>your msg</IPv4SubnetMask>\n"
  155. "<IPv4Gateway>your msg</IPv4Gateway>\n"
  156. "<IPv6Address>::</IPv6Address>\n"
  157. "<IPv6Gateway>::</IPv6Gateway>\n"
  158. "<IPv6MaskLen>64</IPv6MaskLen>\n"
  159. "<DHCP>::</DHCP>\n"
  160. "<SoftwareVersion>your msg</SoftwareVersion>\n"
  161. "<BootTime>your msg</BootTime>\n"
  162. "<Diskrate>your msg</Diskrate >\n"
  163. "<Cpurate>your msg</Cpurate >\n"
  164. "<Memoryrate>%s</Memoryrate >\n"
  165. "</ProbeMatch>");
  166. strMsg += szMsg;
  167. return strMsg;
  168. }
  169. //发送ssdp:discover消息
  170. void CSSDPServer::SendMsg(const string&str)
  171. {
  172. RTM("CSSDPServer::SendMsg msg=%s",str.c_str());
  173. socklen_t len = sizeof(m_cddr);
  174. int nLen = sendto(m_ssdps,str.c_str(),str.length(),0,(sockaddr*)&m_cddr,len);
  175. if( nLen >0 )
  176. {
  177. RTM("CSSDPServer::SendMsg success to send to %s msg len=%d",inet_ntoa(m_cddr.sin_addr),nLen);
  178. }
  179. else
  180. {
  181. RTM("CSSDPServer::SendMsg failed to send msg");
  182. }
  183. }
  184. void CSSDPServer::RecvMsg()
  185. {
  186. socklen_t len = sizeof(m_sddr);
  187. char szMsg[MAXSSDPSIZE]={0};
  188. int num = recvfrom(m_ssdps,szMsg,MAXSSDPSIZE,0,(sockaddr*)&m_sddr,&len);
  189. if( num >0 )
  190. {
  191. string str;
  192. //ParseMsg(buf);
  193. }
  194. }

测试代码:

  1. #include<SSDPClient.h>
  2. int main(int argc, char *argv[])
  3. {
  4. while( true )
  5. {
  6. CSSDPClient::Discover();
  7. std::this_thread::sleep_for( std::chrono::seconds(10) );
  8. }
  9. return 0;
  10. }
  1. #include"SSDPServer.h"
  2. int main(int argc, char *argv[])
  3. {
  4. CSSDPServer::Init( );
  5. std::this_thread::sleep_for( std::chrono::seconds(100000) );
  6. return 0;
  7. }

抓包:

发送方:ssdpclient 192.168.66.44 发送 search命令

接收方 ssdpserv (我在同一个电脑上测试 ip都是192.168.66.44)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/475133
推荐阅读
  

闽ICP备14008679号