赞
踩
原理:
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);
客户端代码:
- /*
- Author:zhuoyong
- Date:2022-04-07
- Mark:人脸识别客户端代码
- */
-
- #ifndef CSSDPCLIENT_H
- #define CSSDPCLIENT_H
- #include<string>
- #include<string.h>
- #include<queue>
- #include<stdio.h>
- #include<stdlib.h>
- #include<arpa/inet.h>
- #include<thread>
- #include<chrono>
- #include<unistd.h>
- #include<netinet/in.h>
- #include<arpa/inet.h>
- #include<net/if.h>
- #include<pthread.h>
- #include<fcntl.h>
- #define ERR printf
- #define RTM printf
- #define MAXSSDPSIZE 1024
-
- using namespace std;
-
- class CSSDPClient
- {
- public:
- static void Discover();
- //最终加密后的pssword=:md5(<uuid>:<uid>:<pwd>)
- static void ModifyNet(string &strUuid,string&strUid,string&strPwd,string &strMask,string&strGateway,string &strDns);
- //strCryptPwd=base64(AES(pwd))
- static void ModifyUser(string &strUuid,string&strUid,string&strPwd);
- protected:
- CSSDPClient();
- ~CSSDPClient();
- void SendMsg(const string&str);
- void RecvMsg();
- void NotifyOne(const string&str);
- string MakeSSDHeader();
- string MakeSearchMsg();
- string MakeModifyNetMsg();
- string MakeModifyUserMsg();
- static CSSDPClient *Ins();
- void InerDiscover(const string&str);
- void InitSocket();
- private:
- static CSSDPClient * g_in;
- sockaddr_in m_sddr ;
- int m_ssdps;
- queue<string> m_que;
- pthread_cond_t m_cd;
- pthread_mutex_t m_mt;
- };
-
- #endif // CSSDPCLIENT_H
- /*
- * ===========================================================================
- *
- * Filename: SSDPClient.cpp
- * Description: 客户端设备发现 xml协议
- * Version: 1.0
- * Created: 20220406-12:07
- * Revision: none
- * Compiler: g++
- * Author: (zhouyongku),
- * Company:
- *
- * ===========================================================================
- */
-
- #include"SSDPClient.h"
-
-
-
- CSSDPClient *CSSDPClient::g_in=NULL;
- //全局变量
-
-
- //解析IP地址
- CSSDPClient::CSSDPClient()
- {
- m_mt=PTHREAD_MUTEX_INITIALIZER;
- m_cd=PTHREAD_COND_INITIALIZER;
-
- std::thread t([&]
- {
- InitSocket();
- while(true)
- {
- pthread_mutex_lock(&m_mt); // 拿到互斥锁,进入临界区
- if( m_que.size()<=0 )pthread_cond_wait(&m_cd,&m_mt); // 令线程等待在条件变量上
- pthread_mutex_unlock(&m_mt); // 释放互斥锁
- InerDiscover(m_que.front());
- m_que.pop();
- }
- });
- t.detach();
- }
-
- CSSDPClient::~CSSDPClient()
- {
-
- }
-
- CSSDPClient *CSSDPClient::Ins()
- {
- if( CSSDPClient::g_in == nullptr )
- {
- CSSDPClient::g_in = new CSSDPClient();
- }
-
- return CSSDPClient::g_in;
- }
-
- void CSSDPClient::InerDiscover(const string&str)
- {
- SendMsg( str );
- RecvMsg( );
- }
-
- void CSSDPClient::InitSocket()
- {
- struct timeval TimeOut;
- TimeOut.tv_sec = 1;
- TimeOut.tv_usec = 0;
-
-
- m_ssdps=socket(AF_INET,SOCK_DGRAM,0);
- if( m_ssdps < 0)
- {
- ERR("CSSDPClient::InitSocket failed of create socket 239.255.255.250:1900");
- return;
- }
-
- bzero(&m_sddr, sizeof(m_sddr));
- m_sddr.sin_family = AF_INET;
- m_sddr.sin_addr.s_addr = inet_addr("239.255.255.250");
- m_sddr.sin_port = htons(1900);
- setsockopt(m_ssdps, SOL_SOCKET, SO_RCVTIMEO, (char *)&TimeOut, sizeof(TimeOut));
- ip_mreq mreq;
- bzero(&mreq,sizeof(mreq));
- mreq.imr_multiaddr.s_addr =inet_addr("239.255.255.250");
- mreq.imr_interface.s_addr =htonl(INADDR_ANY);
- if( setsockopt(m_ssdps, IPPROTO_IP,IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) <0 )
- {
- ERR("CSSDPServer::InitSocket failed of setsockopt IP_ADD_MEMBERSHIP");
- return;
- }
-
- // if( bind(m_ssdps, (struct sockaddr *)&m_sddr, sizeof(m_sddr)) < 0 )
- // {
- // ERR("CSSDPClient::InitSocket failed of bind socket %s:%d",SSDP_MCAST_ADDR,SSDP_PORT);
- // }
- }
-
- void CSSDPClient::Discover()
- {
- string str=CSSDPClient::Ins()->MakeSearchMsg();
- CSSDPClient::Ins()->NotifyOne(str);
-
- }
-
- void CSSDPClient::ModifyNet(string &strUuid, string &strUid, string &strPwd, string &strMask, string &strGateway, string &strDns)
- {
- string str=CSSDPClient::Ins()->MakeModifyNetMsg();
- CSSDPClient::Ins()->NotifyOne(str);
- }
-
- void CSSDPClient::ModifyUser(string &strUuid, string &strUid, string &strPwd)
- {
- string str=CSSDPClient::Ins()->MakeModifyUserMsg();
- CSSDPClient::Ins()->NotifyOne(str);
- }
-
- void CSSDPClient::NotifyOne(const string&str)
- {
- RTM("CSSDPClient::NotifyOne quesize=%d",m_que.size());
- pthread_mutex_lock(&m_mt); // 拿到互斥锁,进入临界区
- m_que.push( str );
- pthread_cond_signal(&m_cd); // 通知等待在条件变量上的消费者
- pthread_mutex_unlock(&m_mt); // 释放互斥锁
- }
-
- string CSSDPClient::MakeSSDHeader()
- {
- string strMsg="M-SEARCH * HTTP/1.1\n";
- strMsg +="HOST: 239.255.255.250:1900\n";
- strMsg +="MAN: \"ssdp:discover\"\n";
- strMsg +="MX: 1\n";
- strMsg +="ST: urn:dial-multiscreen-org:service:dial:1\n";
- strMsg +="USER-AGENT:arm\n";
- return strMsg;
- }
-
- string CSSDPClient::MakeSearchMsg()
- {
-
- string strMsg=MakeSSDHeader();
- strMsg +="<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
- strMsg +="<Probe>\n";
- strMsg +=" <Uuid>";
- strMsg += "uuid-test";
- strMsg +="</Uuid>\n";
- strMsg +=" <Types>inquiry</Types>\n";
- strMsg +=" <DeviceType>";
- strMsg += "wodepingban";
- strMsg +="</DeviceType>\n";
- strMsg +="</Probe>";
- return strMsg;
- }
-
- string CSSDPClient::MakeModifyNetMsg()
- {
- string strMsg=MakeSSDHeader();
- char szMsg[MAXSSDPSIZE]={0};
- sprintf( szMsg,
- "%s\n"
- "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
- "<Probe>\n"
- "<Uuid>testuuid</Uuid>\n"
- "<Types>update</Types>\n"
- "<DeviceSN>123456sdflsdfjl1023-1asdfgh</DeviceSN>\n"
- "<method>modifyipdns</method>\n"
- "<MAC>ab-cd-ef-gh-kh</MAC>\n"
- "<IPv4Address>192.168.66.24</IPv4Address>\n"
- "<IPv4SubnetMask>255.255.255.0</IPv4SubnetMask>\n"
- "<IPv4Gateway>192.168.66.254</IPv4Gateway>\n"
- "<IPv6Address>::</IPv6Address>\n"
- "<IPv6Gateway>::</IPv6Gateway>\n"
- "<IPv6MaskLen>64</IPv6MaskLen>\n"
- "<DHCP>false</DHCP>\n"
- "<Password>kFnsMaQrzmGi89g+6txepC1RNnZMSi/fA16x+UdjFOmqBmoVCc/zeZ8X6oZmLBdWaXnvwTxjLIQBsLsDP0xjHw==</Password>\n"
- "</Probe>\n",
- strMsg.c_str());
- return string(szMsg);
-
- }
-
- string CSSDPClient::MakeModifyUserMsg()
- {
- string strMsg=MakeSSDHeader();
-
-
- char szMsg[MAXSSDPSIZE]={0};
- sprintf( szMsg,
- "%s\n"
- "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
- "<Probe>\n"
- "<Uuid>your uuid>\n"
- "<Types>update</Types>\n"
- "<DeviceSN>your device sn</DeviceSN>\n"
- "<method>modifypassword</method>\n"
- "<newpassword>your new md5 password</newpassword>\n"
- "<Password>your md5 password</Password>\n"
- "</Probe>\n");
- return string(szMsg);
- }
-
-
- //发送ssdp:discover消息
- void CSSDPClient::SendMsg(const string&str)
- {
- RTM("CSSDPClient::SendMsg msg=%s",str.c_str());
-
- socklen_t len = sizeof(m_sddr);
- int nRet=sendto(m_ssdps,str.c_str(),str.length(),0,(sockaddr*)&m_sddr,len);
- if( nRet >0 )
- {
- RTM("CSSDPClient::SendMsg leng=%d",nRet);
-
- }
-
- char szMsg[MAXSSDPSIZE]={0};
- nRet = recvfrom( m_ssdps,szMsg,MAXSSDPSIZE,0,(sockaddr*)&m_sddr,&len);
- if( nRet >0 )
- {
- RTM("CSSDPClient::SendMsg RECV MSG=%s",szMsg);
- }
- }
-
- void CSSDPClient::RecvMsg()
- {
- socklen_t len = sizeof(m_sddr);
- char szMsg[MAXSSDPSIZE]={0};
- int num = recvfrom(m_ssdps,szMsg,MAXSSDPSIZE,0,(sockaddr*)&m_sddr,&len);
- if( num >0 )
- {
- string str;
- //ParseMsg(buf);
- }
- }
-
-
-
-
-
服务端:
- #ifndef CSSDPSERVER_H
- #define CSSDPSERVER_H
- /*
- Author:zhuoyong
- Date:2022-04-07
- Mark:设备发现服务端代码
- */
- #include<string>
- #include<string.h>
- #include<queue>
- #include<stdio.h>
- #include<stdlib.h>
- #include<arpa/inet.h>
- #include<thread>
- #include<chrono>
- #include<unistd.h>
- #include<netinet/in.h>
- #include<arpa/inet.h>
- #include<net/if.h>
- #include<pthread.h>
- #include<fcntl.h>
- #include<mutex>
- #define ERR printf
- #define RTM printf
- #define MAXSSDPSIZE 1024
-
- using namespace std;
-
-
- class CSSDPServer
- {
- public:
- static void Init( );
-
- protected:
- CSSDPServer( );
- ~CSSDPServer();
- void SendMsg(const string&str);
- void RecvMsg();
- string MakeSSDHeader();
- string MakeResponseSearchMsg( );
- static CSSDPServer *Ins();
- void InitSendSocket();
- void InitRecvSocket();
- void ProcesMsg( const char *strMsg );
- private:
- static CSSDPServer * g_in;
- sockaddr_in m_sddr ;
- sockaddr_in m_cddr ;
- int m_ssdps;
- int m_ssdpc;
- queue<string> m_que;
- pthread_cond_t m_cd;
- pthread_mutex_t m_mt;
- };
-
- #endif // CSSDPSERVER_H
- /*
- * ===========================================================================
- *
- * Filename: SSDPServer.cpp
- * Description: 服务端设备发现 xml协议
- * Version: 1.0
- * Created: 20220406-12:07
- * Revision: none
- * Compiler: g++
- * Author: (zhouyongku),
- * Company:
- *
- * ===========================================================================
- */
-
-
- #include"SSDPServer.h"
-
- CSSDPServer *CSSDPServer::g_in=NULL;
- //全局变量
-
-
- //解析IP地址
- CSSDPServer::CSSDPServer( )
- {
- m_mt=PTHREAD_MUTEX_INITIALIZER;
- m_cd=PTHREAD_COND_INITIALIZER;
- RTM("CSSDPServer::CSSDPServer");
- std::thread t([&]
- {
- RTM("CSSDPServer::CSSDPServer create thread");
- InitSendSocket();
- InitRecvSocket();
- char szMsg[MAXSSDPSIZE]={0};
- socklen_t len = sizeof(m_sddr);
- while( true )
- {
- if((recvfrom(m_ssdps, szMsg, MAXSSDPSIZE, 0, (sockaddr*)&m_sddr, &len)) >= 0)
- {
- //printf("recvfrom success ip=%s,msg=%s",inet_ntoa(m_sddr.sin_addr),szMsg);
- ProcesMsg( szMsg );
- memset(szMsg,0,sizeof(szMsg));
- }
- std::this_thread::sleep_for(std::chrono::seconds(10));
- }
- });
- t.detach();
- }
- void CSSDPServer::ProcesMsg( const char *strMsg )
- {
- //and your code here
-
-
-
-
- SendMsg( MakeResponseSearchMsg( ) );
-
-
- }
-
-
- CSSDPServer::~CSSDPServer()
- {
-
- }
-
- CSSDPServer *CSSDPServer::Ins( )
- {
- if( CSSDPServer::g_in == nullptr )
- {
- CSSDPServer::g_in = new CSSDPServer( );
- }
-
- return CSSDPServer::g_in;
- }
-
-
- void CSSDPServer::InitSendSocket()
- {
- struct timeval TimeOut;
- TimeOut.tv_sec = 1;
- TimeOut.tv_usec = 0;
-
-
- m_ssdpc=socket(AF_INET,SOCK_DGRAM,0);
- if( m_ssdpc < 0)
- {
- ERR("CSSDPClient::InitSocket failed of create socket 239.255.255.250:1900");
- return;
- }
-
- bzero(&m_cddr, sizeof(m_cddr));
- m_cddr.sin_family = AF_INET;
- m_cddr.sin_addr.s_addr = inet_addr("239.255.255.250");
- m_cddr.sin_port = htons(1900);
- setsockopt(m_ssdpc, SOL_SOCKET, SO_RCVTIMEO, (char *)&TimeOut, sizeof(TimeOut));
- ip_mreq mreq;
- bzero(&mreq,sizeof(mreq));
- mreq.imr_multiaddr.s_addr =inet_addr("239.255.255.250");
- mreq.imr_interface.s_addr =htonl(INADDR_ANY);
- if( setsockopt(m_ssdpc, IPPROTO_IP,IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) <0 )
- {
- ERR("CSSDPServer::InitSocket failed of setsockopt IP_ADD_MEMBERSHIP");
- return;
- }
- }
-
- void CSSDPServer::InitRecvSocket()
- {
- RTM("CSSDPServer::InitRecvSocket");
- struct timeval TimeOut;
- TimeOut.tv_sec = 1;
- TimeOut.tv_usec = 0;
-
- m_ssdps=socket(AF_INET,SOCK_DGRAM,0);
- if( m_ssdps < 0)
- {
- ERR("CSSDPServer::InitSocket failed of create socket 239.255.255.250:1900");
- return;
- }
-
- bzero(&m_sddr, sizeof(m_sddr));
- m_sddr.sin_family = AF_INET;
- m_sddr.sin_addr.s_addr = INADDR_ANY;
- m_sddr.sin_port = htons(1900);
-
- if( bind(m_ssdps, (struct sockaddr *)&m_sddr, sizeof(m_sddr)) < 0 )
- {
- ERR("CSSDPServer::InitSocket failed of bind socket 0.0.0.0:1900");
- return ;
- }
- ip_mreq mreq;
- bzero(&mreq,sizeof(mreq));
- mreq.imr_multiaddr.s_addr =inet_addr("239.255.255.250");
- mreq.imr_interface.s_addr =htonl(INADDR_ANY);
- if( setsockopt(m_ssdps, IPPROTO_IP,IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) <0 )
- {
- ERR("CSSDPServer::InitSocket failed of setsockopt IP_ADD_MEMBERSHIP");
- return;
- }
- RTM("CSSDPServer::InitRecvSocket success");
-
- }
-
- void CSSDPServer::Init( )
- {
- CSSDPServer::Ins( );
- }
-
-
- string CSSDPServer::MakeSSDHeader()
- {
- string strMsg="NOTIFY * HTTP/1.1\n"
- "HOST: 239.255.255.250:1900\n"
- "CACHE-CONTROL: max-age=66\n"
- "LOCATION:xml\n"
- "OPT:ns=01\n"
- "01-NLS:0\n"
- "NT: urn:schemas-upnp-org:service:AVTransport:1\n"
- "NTS: ssdp:alive\n"
- "SERVER: Ubuntu/16.04\n"
- "X-User-Agent: redsonic\n"
- "USN:1\n";
- return strMsg;
- }
-
-
- string CSSDPServer::MakeResponseSearchMsg()
- {
-
- string strMsg=MakeSSDHeader();
-
- char szMsg[MAXSSDPSIZE]={0};
-
- snprintf( szMsg,MAXSSDPSIZE,
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
- "<ProbeMatch>\n"
- "<mount>your msg</mount>\n"
- "<enable>your msg</enable>\n"
- "<platformip>%s</platformip>\n"
- "<Uuid>your msg</Uuid>\n"
- "<Types>inquiry</Types>\n"
- "<DeviceType>CDZSFACEBOX</DeviceType>\n"
- "<DeviceSN>your msg</DeviceSN>\n"
- "<DeviceName>your msg</DeviceName>\n"
- "<MAC>your msg</MAC>\n"
- "<IPv4Address>your msg</IPv4Address>\n"
- "<IPv4SubnetMask>your msg</IPv4SubnetMask>\n"
- "<IPv4Gateway>your msg</IPv4Gateway>\n"
- "<IPv6Address>::</IPv6Address>\n"
- "<IPv6Gateway>::</IPv6Gateway>\n"
- "<IPv6MaskLen>64</IPv6MaskLen>\n"
- "<DHCP>::</DHCP>\n"
- "<SoftwareVersion>your msg</SoftwareVersion>\n"
- "<BootTime>your msg</BootTime>\n"
- "<Diskrate>your msg</Diskrate >\n"
- "<Cpurate>your msg</Cpurate >\n"
- "<Memoryrate>%s</Memoryrate >\n"
- "</ProbeMatch>");
-
-
- strMsg += szMsg;
- return strMsg;
- }
-
-
- //发送ssdp:discover消息
- void CSSDPServer::SendMsg(const string&str)
- {
- RTM("CSSDPServer::SendMsg msg=%s",str.c_str());
-
- socklen_t len = sizeof(m_cddr);
- int nLen = sendto(m_ssdps,str.c_str(),str.length(),0,(sockaddr*)&m_cddr,len);
- if( nLen >0 )
- {
- RTM("CSSDPServer::SendMsg success to send to %s msg len=%d",inet_ntoa(m_cddr.sin_addr),nLen);
- }
- else
- {
- RTM("CSSDPServer::SendMsg failed to send msg");
- }
- }
-
- void CSSDPServer::RecvMsg()
- {
- socklen_t len = sizeof(m_sddr);
- char szMsg[MAXSSDPSIZE]={0};
- int num = recvfrom(m_ssdps,szMsg,MAXSSDPSIZE,0,(sockaddr*)&m_sddr,&len);
- if( num >0 )
- {
- string str;
- //ParseMsg(buf);
- }
- }
-
-
-
-
-
测试代码:
- #include<SSDPClient.h>
-
- int main(int argc, char *argv[])
- {
- while( true )
- {
- CSSDPClient::Discover();
- std::this_thread::sleep_for( std::chrono::seconds(10) );
- }
-
- return 0;
- }
-
- #include"SSDPServer.h"
- int main(int argc, char *argv[])
- {
-
- CSSDPServer::Init( );
-
-
- std::this_thread::sleep_for( std::chrono::seconds(100000) );
-
- return 0;
- }
-
抓包:
发送方:ssdpclient 192.168.66.44 发送 search命令
接收方 ssdpserv (我在同一个电脑上测试 ip都是192.168.66.44)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。