C# 实现uPnP映射
|
admin
2021年2月2日 17:42
本文热度 3575
|
上网找了很多关于C# 实现uPnP映射的资料,好用的资料不是很多,很多人都是用系统UPnP.dll封装好的方法,但是我在vs2010下用C#尝试不是很成功。很多时候UPnPNATClass nat=new UPnPNATClass();得到的都是null值.终于找到了一个自己封装SOAP进行uPnP端口映射的方法,我帮作者把类又重新封装了一下。
using System.Collections.Generic; using System.Net.Sockets;
public sealed class upnpLib public enum InternetConnectTypes { IPv4, IPv6 } public enum ResultTypes { Success, Faild } #region -- Private Fields -- private string _location; get { return this._location; } set { this._location = value; } get { return this._host; } set { this._host = value; } get { return this._port; } set { this._port = value; } get { return this._server; } set { this._server = value; } get { return this._maxAge; } set { this._maxAge = value; } get { return this._USN; } set { this._USN = value; } public RootDevice(string location) this.Host = location.Substring(location.IndexOf(''/'') + 2, location.IndexOf(''/'', location.IndexOf(''/'') + 2) - (location.IndexOf(''/'') + 2)); this.Port = this.Host.Substring(this.Host.IndexOf('':'') + 1); this.Host = this.Host.Substring(0, this.Host.IndexOf('':'')); this.Location = location.Substring(location.IndexOf(''/'', location.IndexOf(''/'') + 2)); public class DeviceService #region -- Private Fields -- private string _controlUrl; private string _eventSubUrl; get { return this._type; } set { this._type = value; } set { this._id = value; } get { return this._scpdUrl; } set { this._scpdUrl = value; } get { return this._controlUrl; } set { this._controlUrl = value; } public string EventSubUrl get { return this._eventSubUrl; } set { this._eventSubUrl = value; } get { return this._baseUrl; } set { this._baseUrl = value; } public class ServicePoint #region -- Private Fields -- private IList<Argument> _argumentList = new List<Argument>(); get { return this._name; } set { this._name = value; } public IList<Argument> ArgumentList get { return this._argumentList; } set { this._argumentList = value; } #region -- Private Fields -- private string _direction; private string _relatedStateVariable; get { return this._name; } set { this._name = value; } get { return this._direction; } set { this._direction = value; } public string RelatedStateVariable get { return this._relatedStateVariable; } set { this._relatedStateVariable = value; } public class StateVariable #region -- Private Fields -- private string _sendEvents; private string _dataType; private IList<string> _allowedValueList = new List<string>(); get { return this._sendEvents; } set { this._sendEvents = value; } get { return this._name; } set { this._name = value; } get { return this._dataType; } set { this._dataType = value; } public IList<string> AllowedValueList get { return this._allowedValueList; } set { this._allowedValueList = value; } #region -- Private Fields-- private ResultTypes _status; public ResultTypes Status get { return this._status; } set { this._status = value; } get { return this._message; } set { this._message = value; } #region -- Private Fields -- private InternetConnectTypes _ict; private Result r = new Result(); private DeviceService service = null; private IList<RootDevice> devices = null; private IList<DeviceService> services = null; private IList<ServicePoint> _actions = null; private IList<StateVariable> _stateVariables = null; public InternetConnectTypes InternetConnectType get { return this._ict; } set { this._ict = value; } public IList<ServicePoint> ActionList get { return this._actions; } public IList<StateVariable> StateVariableList get { return this._stateVariables; } public upnpLib(InternetConnectTypes ict) this.InternetConnectType = ict; r.Status = ResultTypes.Success; this.devices = this.discoverDevices(5); if (this.devices.Count == 0) throw new Exception("没有发现可用uPnP设备!"); this.services = this.getDeviceSvc(this.getDeviceDesc(this.devices[0])); foreach (DeviceService s in this.services) if (s.Type.Contains("service:WANIPConnection")) string Xml = this.getServiceDesc(this.devices[0],s); this._actions = this.getServicePoint(Xml); this._stateVariables = this.GetStateVariables(Xml); r.Status = ResultTypes.Faild; private IList<RootDevice> discoverDevices(int timeOut) #region -- Send UDP data -- string strData = "M-SEARCH * HTTP/1.1\r\n" + "HOST: 239.255.255.250:1900\r\n" + "MAN:\"ssdp:discover\"\r\n" + "MX:" + timeOut.ToString() + "\r\n" + "ST:upnp:rootdevice\r\n\r\n"; byte[] data = Encoding.UTF8.GetBytes(strData); UdpClient uc = new UdpClient(this.InternetConnectType == InternetConnectTypes.IPv4 ? AddressFamily.InterNetwork : AddressFamily.InterNetworkV6); IPEndPoint IPep = new IPEndPoint(IPAddress.Broadcast, 1900); uc.Send(data, data.Length, IPep); Timer RecvTimeOut = new Timer(this.RecvTimeOutFunc, uc, timeOut * 1000, timeOut * 1000); IList<RootDevice> hints = new List<RootDevice>(); #region -- Recive response -- string temp = "", find = ""; while (buffer == null || buffer.Length == 0) buffer = uc.Receive(ref IPep); if (buffer != null && buffer.Length > 0) strData = Encoding.UTF8.GetString(buffer); if (!strData.Contains("upnp:rootdevice")) continue; temp = "";find = "LOCATION:"; start = strData.IndexOf(find); end = strData.IndexOf("\r\n", start); temp = strData.Substring(start + find.Length, end - (start + find.Length)).Trim(); hint = new RootDevice(temp); temp = ""; find = "max-age ="; start = strData.IndexOf(find); end = strData.IndexOf("\r\n", start); temp = strData.Substring(start + find.Length, end - (start + find.Length)).Trim(); hint.MaxAge = int.Parse(temp); temp = ""; find = "SERVER:"; start = strData.IndexOf(find); end = strData.IndexOf("\r\n", start); temp = strData.Substring(start + find.Length, end - (start + find.Length)).Trim(); temp = ""; find = "USN:"; start = strData.IndexOf(find); end = strData.IndexOf("\r\n", start); temp = strData.Substring(start + find.Length, end - (start + find.Length)).Trim(); private void RecvTimeOutFunc(object uc) private string getDeviceDesc(RootDevice rd) string strData = "GET " + rd.Location + " HTTP/1.1\r\n" + "HOST:" + rd.Host + ":" + rd.Port + "\r\n" + "ACCEPT-LANGUAGE: \r\n\r\n", result = ""; byte[] data = Encoding.UTF8.GetBytes(strData); IPAddress ipadr = (Dns.GetHostAddresses(rd.Host))[0]; IPEndPoint IPep = new IPEndPoint(ipadr, int.Parse(rd.Port)); TcpClient tc = new TcpClient(this.InternetConnectType == InternetConnectTypes.IPv4 ? AddressFamily.InterNetwork : AddressFamily.InterNetworkV6); ns.Write(data, 0, data.Length); byte[] buff = new byte[ReadSize], readBuff; ReadSize = ns.Read(buff, 0, buff.Length); readBuff = new byte[ReadSize]; Array.Copy(buff, 0, readBuff, 0, ReadSize); strData += Encoding.UTF8.GetString(readBuff); result = strData.Substring(strData.IndexOf("\r\n\r\n") + 4).Trim(); while (result.Substring(result.Length - 2) == "\r\n" || result.Substring(result.Length - 2) == Encoding.Default.GetString(new byte[2] { 0, 0 })) result = result.Substring(0, result.Length - 2); private IList<DeviceService> getDeviceSvc(string Xml) MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(Xml)); XmlReader xr = XmlReader.Create(ms); IList<DeviceService> hints = new List<DeviceService>(); if (xr.NodeType == XmlNodeType.Element && xr.Name == "URLBase") if (xr.NodeType == XmlNodeType.Text) } while (xr.NodeType != XmlNodeType.EndElement || xr.Name != "URLBase"); if (xr.NodeType == XmlNodeType.Element && xr.Name == "service") DeviceService s = new DeviceService(); string curElement = string.Empty; if (xr.NodeType == XmlNodeType.Element) if (xr.NodeType == XmlNodeType.EndElement) if (xr.NodeType == XmlNodeType.Text) s.EventSubUrl = xr.Value; } while (xr.NodeType != XmlNodeType.EndElement || xr.Name != "service"); private string getServiceDesc(RootDevice rd, DeviceService ds) string strData = "GET " + ds.BaseUrl + ds.SCPDUrl + " HTTP/1.1\r\n" + "HOST:" + rd.Host + ":" + rd.Port + "\r\n" + "ACCEPT-LANGUAGE: \r\n\r\n", result = ""; byte[] data = Encoding.UTF8.GetBytes(strData); IPAddress ipadr = (Dns.GetHostAddresses(rd.Host))[0]; IPEndPoint IPep = new IPEndPoint(ipadr, int.Parse(rd.Port)); TcpClient tc = new TcpClient(this.InternetConnectType == InternetConnectTypes.IPv4 ? AddressFamily.InterNetwork : AddressFamily.InterNetworkV6); ns.Write(data, 0, data.Length); byte[] buff = new byte[ReadSize], readBuff; ReadSize = ns.Read(buff, 0, buff.Length); readBuff = new byte[ReadSize]; Array.Copy(buff, 0, readBuff, 0, ReadSize); strData += Encoding.UTF8.GetString(readBuff); result = strData.Substring(strData.IndexOf("\r\n\r\n") + 4).Trim(); while (result.Substring(result.Length - 2) == "\r\n" || result.Substring(result.Length - 2) == Encoding.Default.GetString(new byte[2] { 0, 0 })) result = result.Substring(0, result.Length - 2); private IList<ServicePoint> getServicePoint(string Xml) MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(Xml)); XmlReader xr = XmlReader.Create(ms); IList<ServicePoint> hints = new List<ServicePoint>(); if (xr.NodeType == XmlNodeType.Element && xr.Name == "action") ServicePoint sp = new ServicePoint(); string curElement = string.Empty; if (xr.NodeType == XmlNodeType.Element && xr.Name != "argumentList") if (xr.NodeType == XmlNodeType.EndElement && xr.Name != "argumentList") if (xr.NodeType == XmlNodeType.Text) if (xr.NodeType == XmlNodeType.Element && xr.Name == "argumentList") string curElement2 = string.Empty; if (xr.NodeType == XmlNodeType.Element && xr.Name == "argument") Argument arg = new Argument(); if (xr.NodeType == XmlNodeType.Element) if (xr.NodeType == XmlNodeType.EndElement) if (xr.NodeType == XmlNodeType.Text) arg.Direction = xr.Value; case "relatedStateVariable": arg.RelatedStateVariable = xr.Value; } while (xr.NodeType != XmlNodeType.EndElement || xr.Name != "argument"); sp.ArgumentList.Add(arg); } while (xr.NodeType != XmlNodeType.EndElement || xr.Name != "argumentList"); } while (xr.NodeType != XmlNodeType.EndElement || xr.Name != "action"); private IList<StateVariable> GetStateVariables(string Xml) MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(Xml)); XmlReader xr = XmlReader.Create(ms); IList<StateVariable> hints = new List<StateVariable>(); if (xr.NodeType == XmlNodeType.Element && xr.Name == "stateVariable") StateVariable hint = new StateVariable(); hint.SendEvents = xr.GetAttribute("sendEvents"); string curElement = string.Empty; if (xr.NodeType == XmlNodeType.Element && xr.Name != "allowedValueList") if (xr.NodeType == XmlNodeType.EndElement && xr.Name != "allowedValueList") if (xr.NodeType == XmlNodeType.Text) hint.DataType = xr.Value; if (xr.NodeType == XmlNodeType.Element && xr.Name == "allowedValueList") string curElement2 = string.Empty; if (xr.NodeType == XmlNodeType.Element) if (xr.NodeType == XmlNodeType.EndElement) if (xr.NodeType == XmlNodeType.Text) hint.AllowedValueList.Add(xr.Value); } while (xr.NodeType != XmlNodeType.EndElement || xr.Name != "allowedValueList"); } while (xr.NodeType != XmlNodeType.EndElement || xr.Name != "stateVariable"); private void makeAddPortMappingSOAP(RootDevice dev, DeviceService srv, string NewRemoteHost, string NewExternalPort, string NewProtocol, string NewInternalPort, string NewPortMappingDescription, string NewLeaseDuration) string InternalAddress = string.Empty; IPAddress[] addrs = Dns.GetHostAddresses(Dns.GetHostName()); foreach (IPAddress addr in addrs) if (addr.AddressFamily == AddressFamily.InterNetwork) InternalAddress = addr.ToString(); string strData = "<u:AddPortMapping xmlns:u=\"" + srv.Type + "\">" + "<NewRemoteHost></NewRemoteHost>" + "<NewExternalPort>" + NewExternalPort + "</NewExternalPort>" + "<NewProtocol>" + NewProtocol + "</NewProtocol>" + "<NewInternalPort>" + NewInternalPort + "</NewInternalPort>" + "<NewInternalClient>" + InternalAddress + "</NewInternalClient>" + "<NewEnabled>1</NewEnabled>" + "<NewPortMappingDescription>" + NewPortMappingDescription + "</NewPortMappingDescription>" + "<NewLeaseDuration>" + NewLeaseDuration + "</NewLeaseDuration>" + string result = PostSOAP(dev, srv, strData, "AddPortMapping"); private void makeDeletePortMappingSOAP(RootDevice dev, DeviceService srv, string NewRemoteHost, string NewExternalPort, string NewProtocol) string strData = "<u:DeletePortMapping xmlns:u=\"" + srv.Type + "\">" + "<NewRemoteHost>" + NewRemoteHost + "</NewRemoteHost>" + "<NewExternalPort>" + NewExternalPort + "</NewExternalPort>" + "<NewProtocol>" + NewProtocol + "</NewProtocol>" + "</u:DeletePortMapping>"; string result = PostSOAP(dev, srv, strData, "DeletePortMapping"); private string makeGetExternalIPAddress(RootDevice dev, DeviceService srv) string strData = "<u:GetExternalIPAddress xmlns:u=\"" + srv.Type + "\">" + "</u:GetExternalIPAddress>"; string result = PostSOAP(dev, srv, strData, "GetExternalIPAddress"); if (result.IndexOf("<NewExternalIPAddress>") > -1) result = result.Substring(result.IndexOf("<NewExternalIPAddress>") + 22, result.IndexOf("</NewExternalIPAddress>") - (result.IndexOf("<NewExternalIPAddress>") + 22)); private string PostSOAP(RootDevice dev, DeviceService srv, string soapData, string action) string soap = "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + "<s:Body>" + soapData + "</s:Body>" + string strData = "POST " + srv.BaseUrl + srv.ControlUrl + " HTTP/1.1\r\n" + "HOST: " + dev.Host + ":" + dev.Port + "\r\n" + "Content-Length: " + Encoding.UTF8.GetBytes(soap).Length.ToString() + "\r\n" + "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n" + "SOAPACTION: \"" + srv.Type + "#" + action + "\"\r\n\r\n" + soap; byte[] data = Encoding.Default.GetBytes(strData); IPAddress ipaddr = (Dns.GetHostAddresses(dev.Host))[0]; IPEndPoint IPep = new IPEndPoint(ipaddr, int.Parse(dev.Port)); TcpClient tc = new TcpClient(AddressFamily.InterNetwork); ns.Write(data, 0, data.Length); byte[] buffer = new byte[4096], readBuff; int ReadSize = ns.Read(buffer, 0, buffer.Length); readBuff = new byte[ReadSize]; Array.Copy(buffer, 0, readBuff, 0, ReadSize); strData = Encoding.Default.GetString(readBuff); public Result addPortMapping(string NewRemoteHost, string NewExternalPort, string NewProtocol, string NewInternalPort, string NewPortMappingDescription, string NewLeaseDuration) if (this.r.Status == ResultTypes.Success) this.makeAddPortMappingSOAP(this.devices[0], this.service, NewRemoteHost, NewExternalPort, NewProtocol, NewInternalPort, NewPortMappingDescription, NewLeaseDuration); r.Status = ResultTypes.Faild; public Result deletePortMapping(string NewRemoteHost, string NewExternalPort, string NewProtocol) if (this.r.Status == ResultTypes.Success) this.makeDeletePortMappingSOAP(this.devices[0], this.service, NewRemoteHost, NewExternalPort, NewProtocol); r.Status = ResultTypes.Faild; public Result getExternalIPAddress() if (this.r.Status == ResultTypes.Success) r.Message = this.makeGetExternalIPAddress(this.devices[0], this.service); r.Status = ResultTypes.Faild;
这是调用方法 upnpLib upnp = new upnpLib(upnpLib.InternetConnectTypes.IPv4); upnpLib.Result r = upnp.addPortMapping("200,200,200,200", "8000", "TCP", "11500", "this is uPnP Test.", "0"); MessageBox.Show(r.Status == upnpLib.ResultTypes.Success ? "成功" : "失败");
这里是获取路由器uPnP命令列表
upnpLib upnp = new upnpLib(upnpLib.InternetConnectTypes.IPv4); IList<upnpLib.ServicePoint> hints = upnp.ActionList;
该文章在 2021/2/2 17:42:03 编辑过
|
|