⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 btjl.txt

📁 比特精灵 源代码
💻 TXT
📖 第 1 页 / 共 2 页
字号:
	QString get = QString("GET ") + post + " HTTP/1.1\r\nHOST: " + host + "\r\nACCEPT-LANGUAGE: en\r\n\r\n";
	QProxy	proxy; //因為UPnP設備基本上是局域網內部的操作,不需要代理,為了避免全局的代理設置影響後續TCP操作,這裡定義一個空的代理.
	QSocket tcp;
	int		retry = 0;
	if(delay<=0)delay = UPNPDELAY;
	if(!tcp.Connect(addr.c_str(),port,false,&proxy))return false;//connection failed
	tcp.SendData(get.c_str(),get.Length());
	do
	{
		if(tcp.Write()>=0&&tcp.SendLength()>0) sleep(1); //sleep(x) = Sleep(x * 1000)
	}while(++retry<delay&&tcp.SendLength()>0);
	if(tcp.SendLength()>0||tcp.Read()<0)return false;
	retry = 0;
	do
	{
		if(retry)sleep(1);
	}while(tcp.Read()>=0&&++retry<delay&&tcp.Read()>=0);
	char a[50], b[50], c[50];
	if(SplitterString(tcp.RecvBuffer(),a,b,c,40,40,40)!=3||b[0]!='2')return false;
	const char* lfe = NULL;
	const char* buf = tcp.RecvBuffer(); //如果當前沒有數據,返回"",RecvBuffer永遠不會返回NULL,所以不用擔心空指針
	const char* lfr = NULL;
	//get friendly name
	lfr = strstr(buf,"<friendlyName>");
	if(lfr)
	{
		lfr += (sizeof("<friendlyName>") - 1);
		lfe = strstr(lfr,"</friendlyName>");
		if(lfe)m_friendlyname = QString(lfr, lfe - lfr).Trim();
	}
	//get <modelName>
	lfr = strstr(buf,"<modelName>");
	if(lfr)
	{
		lfr += (sizeof("<modelName>") - 1);
		lfe = strstr(lfr, "</modelName>");
		if(lfe)m_modelname = QString(lfr, lfe - lfr).Trim();
	}
	//get <URLBase>
	lfr = strstr(buf,"<URLBase>");
	if(lfr)
	{
		lfr += (sizeof("<URLBase>") - 1);
		lfe = strstr(lfr,"</URLBase>");
		if(lfe)m_baseurl = QString(lfr, lfe - lfr).Trim();
	}
	if(m_baseurl.IsEmpty())m_baseurl = QString("http://") + host + "/";
	if(m_baseurl[m_baseurl.Length()]!='/')m_baseurl += "/";
	//get service
	QString svrn = QString("<serviceType>") + m_name + "</serviceType>";
	lfr = strstr(buf,svrn.c_str());
	if(lfr)
	{
		lfe = strstr(lfr, "</service>");
		if(lfe)
		{
			QString tmp = QString(lfr, lfe - lfr);
			lfr = strstr(tmp.c_str(),"<controlURL>");
			if(lfr)
			{
				lfr += (sizeof("<controlURL>") - 1);
				lfe = strstr(lfr,"</controlURL>");
				if(lfe&&lfe>lfr)
				{
					if(lfr[0]=='/')
					{//relative url
						lfr++;
						m_controlurl = m_baseurl + QString(lfr, lfe - lfr);
					}
					else
					{
						m_controlurl = QString(lfr, lfe - lfr);
					}
				}
			}
		}
	}
	return Comfirmed();
}
/*GetProperty: 在對像已經有效的情況下獲取對象的某屬性.
實現過程: 通過對目標對象的控制URL發送UPnP規範定義的POST請求並解析返回數據來獲取相應的屬性.
參數: 
name: 針對該屬性的動作,如:GetExternalIPAddress
rsp: 屬性返回值的名稱,如:NewExternalIPAddress
delay: 最大等待時間*/
QString QMyUPNP::GetProperty(const QString& name, const QString& rsp, int delay)
{
	if(!Comfirmed())return QString();
	QString post, host, addr;
	int port = 0;
	addr = NGetAddressFromUrl(m_controlurl, post, host, port);
	if(addr.IsEmpty()||!is_validport(port))return QString();
	QMemoryStream cnt; //QMemoryStream 內部有智能的內存算法可以避免頻繁的內存分配.
	QMemoryStream psr;
	cnt.Write("<s:Envelope\r\n    xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"\r\n    ");
	cnt.Write("s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n  <s:Body>\r\n    <u:");
	cnt.Write(name.c_str());
	cnt.Write(" xmlns:u=\"");
	cnt.Write(m_name.c_str());
	cnt.Write("\">\r\n    </u:");
	cnt.Write(name.c_str());
	cnt.Write(">\r\n  </s:Body>\r\n</s:Envelope>\r\n\r\n");
	psr.Write("POST ");
	psr.Write(post.c_str());
	psr.Write(" HTTP/1.1\r\nHOST: ");
	psr.Write(host.c_str());
	psr.Write("\r\nContent-Length: ");
	psr.Write(cnt.Size());
	psr.Write("\r\nContent-Type: text/xml; charset=\"utf-8\"\r\nSOAPACTION: ");
	psr.Write(m_name.c_str());
	psr.Write("#");
	psr.Write(name.c_str());
	psr.Write("\r\n\r\n");
	psr.Write(cnt.Data(),cnt.Size());
	QProxy	proxy;
	QSocket tcp;
	int		retry = 0;
	if(delay<=0)delay = UPNPDELAY;
	if(!tcp.Connect(addr.c_str(),port,false,&proxy))
	{
		return QString();//no proxy
	}
	tcp.SendData(psr.Data(),psr.Size());
	do
	{
		if(tcp.Write()>=0&&tcp.SendLength()>0) sleep(1);
	}while(++retry<delay&&tcp.SendLength()>0);
	if(tcp.SendLength()>0||tcp.Read()<0)
	{
		return QString();
	}
	retry = 0;
	do
	{
		if(retry)sleep(1);
	}while(tcp.Read()>=0&&++retry<delay&&tcp.Read()>=0);
	char a[50], b[50], c[50];
	if(SplitterString(tcp.RecvBuffer(),a,b,c,40,40,40)!=3||b[0]!='2')
	{
		return QString();
	}
	QString schr = QString("<") + rsp;
	QString echr = QString("</") + rsp + ">";
	const char* lfe = NULL;
	const char* buf = tcp.RecvBuffer();
	const char* lfr = strstr(buf,schr.c_str());
	if(lfr)
	{	
		lfe = strstr(lfr, echr.c_str());
		if(lfe)
		{
			QString ret = QString(lfr, lfe - lfr);
			lfr = strchr(ret.c_str(),'>');
			if(lfr)
			{
				lfr++;
				return QString(lfr);
			}
		}
	}
	return QString();
}
/*GetArgString: 將BS使用的一個QStringList的參數格式轉換成符合UPnP規範的字串型參數.*/
QString GetArgString(QStringList& args)
{
	QMemoryStream ms;
	for(int i=0;i<args.Count()-1;i+=2)
	{
		ms.Write("    <",5);
		ms.Write(args.Item(i).c_str());
		ms.Write(">",1);
		ms.Write(args.Item(i+1).c_str());
		ms.Write("</",2);
		ms.Write(args.Item(i).c_str());
		ms.Write(">\r\n",3);
	}
	return QString(ms.Data(),ms.Size());
}
/*InvokeCommand: 在對像有效的情況下調用對象的方法.
實現過程:通過向目標對象的控制URL發送UPnP規範定義的POST方法來調用對象的方法.
參數含義: 
name: 調用方法的名稱.如:AddPortMapping
args: QStringList類型,其組成結構為:偶數索引的值為參數名,奇數索引的值為參數值,從0開始索引.
delay: 最大等待時間.*/
bool QMyUPNP::InvokeCommand(const QString& name, QStringList& args, int delay)
{
	if(!Comfirmed())return false;
	QString post, host, addr;
	int port = 0;
	addr = NGetAddressFromUrl(m_controlurl, post, host, port);
	if(addr.IsEmpty()||!is_validport(port))return false;
	QMemoryStream cnt;
	QMemoryStream psr;
	cnt.Write("<s:Envelope\r\n    xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"\r\n    ");
	cnt.Write("s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n  <s:Body>\r\n    <u:");
	cnt.Write(name.c_str());
	cnt.Write(" xmlns:u=\"");
	cnt.Write(m_name.c_str());
	cnt.Write("\">\r\n");
	cnt.Write(GetArgString(args).c_str());
	cnt.Write("    </u:");
	cnt.Write(name.c_str());
	cnt.Write(">\r\n  </s:Body>\r\n</s:Envelope>\r\n\r\n");
	psr.Write("POST ");
	psr.Write(post.c_str());
	psr.Write(" HTTP/1.1\r\nHOST: ");
	psr.Write(host.c_str());
	psr.Write("\r\nContent-Length: ");
	psr.Write(cnt.Size());
	psr.Write("\r\nContent-Type: text/xml; charset=\"utf-8\"\r\nSOAPACTION: ");
	psr.Write(m_name.c_str());
	psr.Write("#");
	psr.Write(name.c_str());
	psr.Write("\r\n\r\n");
	psr.Write(cnt.Data(),cnt.Size());
	QProxy	proxy;
	QSocket tcp;
	int		retry = 0;
	if(delay<=0)delay = UPNPDELAY;
	if(!tcp.Connect(addr.c_str(),port,false,&proxy))return false;//no proxy
	tcp.SendData(psr.Data(),psr.Size());
	do
	{
		if(tcp.Write()>=0&&tcp.SendLength()>0) sleep(1);
	}while(++retry<delay&&tcp.SendLength()>0);
	if(tcp.SendLength()>0||tcp.Read()<0)return false;
	retry = 0;
	do
	{
		if(retry)sleep(1);
	}while(tcp.Read()>=0&&++retry<delay&&tcp.Read()>=0);
	char a[50], b[50], c[50];
	if(SplitterString(tcp.RecvBuffer(),a,b,c,40,40,40)==3&&b[0]=='2')return true;
	return false;
}
/*GetAddPortmapArgs: 生成相應可用於InvokeCommand的針對AddPortmapping的參數.*/
void GetAddPortmapArgs(QStringList& args, int eport, int iport,
			  const char* iclient, const char* descri,
			  bool enabled, int dur, const char* type, const char* remote)
{
	args.Clear();
	args.Add("NewRemoteHost");
	args.Add(remote);
	args.Add("NewExternalPort");
	args.Add(QString(eport));
	args.Add("NewProtocol");
	args.Add(type);
	args.Add("NewInternalPort");
	args.Add(QString(iport));
	args.Add("NewInternalClient");
	args.Add(iclient);
	args.Add("NewEnabled");
	args.Add(enabled?"1":"0");
	args.Add("NewPortMappingDescription");
	args.Add(descri);
	args.Add("NewLeaseDuration");
	args.Add(QString(dur));
}
void GetDeletePortmapArgs(QStringList& args, int eport, const char* type, const char* remote)
{
	args.Clear();
	args.Add("NewRemoteHost");
	args.Add(remote);
	args.Add("NewExternalPort");
	args.Add(QString(eport));
	args.Add("NewProtocol");
	args.Add(type);
}
/*附註:
1, 以上用到的QString,QUdpSocket,QStringList,QMemoryStream,QSocket,QProxy都是BS內部實現的類,功能與接口與一些流行的類庫如MFC,VCL類似.
2, 通過QMyUPNP類來查找支持自動端口映射的設備的示例代碼:
	QMyUPNP Tmp;
	//查找服務的示例
	if(!Tmp.Comfirmed()) Tmp.Search(UPNPPORTMAP1);
	if(!Tmp.Comfirmed()) Tmp.Search(UPNPPORTMAP0);
	if(Tmp.Comfirmed()) MessageBox(NULL,(QString("Found: ") + Tmp.GetModelName()).c_str(),"",MB_OK);
	//添加端口的示例
	QStringList args;
GetAddPortmapArgs(args,FWANPort,FLocalPort,FLocalIP,FDescription,true,0,FType,FWANIP);//FWANIP為""表示默認公網IP
	Tmp.InvokeCommand(UPNPADDPORTMAP,args,6);
	//刪除端口的示例
	QStringList args;
	GetDeletePortmapArgs(args,FWANPort,FType,FWANIP);
	Tmp.InvokeCommand(UPNPDELPORTMAP,args,6);
	//獲取公網IP的示例
	QString ip = Tmp.GetProperty(UPNPGETEXTERNALIP,6);
	MessageBox(NULL,(QString("Your WAN IP: ") + ip).c_str(),"",MB_OK);*/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -