[c#] 协议模拟编程之ADSL模式下IP自动换
在编写一些自动发贴机之类的小软件时,经常会用到自动更换IP的地方,手动切换的话太麻烦了,因此我们总会相当用脚本或自动化程序来代替手工切换ip的活。如果家里连的是“宽带连接”,几句命令就可以自动切换了。
set WShell=createobject("WScript.Shell") WShell.run "RasDial 宽带连接 /Disconnect",vbhide,true WShell.run "RasDial 宽带连接 用户名 密码",vbhide,true
注意保存为Vbs脚本,如上图。这是很简单的脚本完成的功能,它可以隐藏运行。
下面我们还是说说用C#的代码完成IP自动切换,毕竟很多程序如果手动去切换IP会很不协调,程序会运行出错。
要将已经存在的ADSL宽带连接从连接状态断开,然后再连接,从而强制重新自动分配IP,从而改变IP,完成一系列这样的功能,除了显式调用上述代码中的“RasDial.exe”之外,在网上还可以引用System32目录下的“rasapi32.dll”,以及" Wininet.dll ”一种方法。
下面是具体步骤:
1.引用命名空间:
using System.Runtime.InteropServices;
接下来就是调用Wininet.dll的API函数,用于宽带网络拨号
[System.Runtime.InteropServices.DllImport("Wininet.dll")] public static extern Int32 InternetDial(IntPtr hwndParent, string lpszConnectoid, Int32 dwFlags, ref Int32 lpdwConnection, Int32 dwReserved);
顺带申明一下这个函数所引用的类型,这些类型都是直接从Pinvoke.net查找并复制过来的,用于填补InternetDial的参数dwFlags,INTERNET_DIAL_SHOW_OFFLINE是手动拨号(将“取消”按钮替换为“脱机工作”按钮),INTERNET_DIAL_FORCE_PROMPT是系统提示下的手动拨号, INTERNET_DIAL_UNATTENDED是自动拨号。
[Flags] public enum InternetDialFlags { INTERNET_DIAL_FORCE_PROMPT = 0x2000, INTERNET_DIAL_SHOW_OFFLINE = 0x4000, INTERNET_DIAL_UNATTENDED = 0x8000 }
这样一来,我们就可以直接调用这样一句函数用于连接网络了。
int temp = 0; Adsl.InternetDial(IntPtr.Zero, "", (int)Adsl.InternetDialFlags.INTERNET_DIAL_UNATTENDED, ref temp, 0);
接下来断开网络就稍微"复杂"一点了,先让我们引用RasHangUp这样一个API32函数。这里顺便将RasHangUp需要用的参数类型和结构都直接申明在里面了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public const int RAS_MaxDeviceType = 16; 2 public const int RAS_MaxDeviceName = 128; 3 public const int MAX_PATH = 260; 4 public const int ERROR_BUFFER_TOO_SMALL = 603; 5 public const int ERROR_SUCCESS = 0; 6 7 [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Auto)] 8 public struct RASCONN 9 { 10 public int dwSize; 11 public IntPtr hrasconn; 12 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxEntryName)] 13 public string szEntryName; 14 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxDeviceType)] 15 public string szDeviceType; 16 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxDeviceName)] 17 public string szDeviceName; 18 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)] 19 public string szPhonebook; 20 public int dwSubEntry; 21 public Guid guidEntry; 22 public int dwFlags; 23 public Guid luid; 24 } 25 [DllImport("rasapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] 26 public static extern int RasEnumConnections( 27 [In, Out] RASCONN[] rasconn, 28 [In, Out] ref int cb, 29 [Out] out int connections); 30 public const int RAS_MaxEntryName = 256; 31 //挂断拨号,断开网络链接 32 [DllImport("rasapi32.dll", SetLastError = true)] 33 public static extern uint RasHangUp(IntPtr hRasConn); 34
函数部分就完成了,接下来我们可以这样写:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public void DisConnect() 2 { 3 System.Adsl.RASCONN[] connections = new System.Adsl.RASCONN[1];//创建新连接 4 connections[0].dwSize = Marshal.SizeOf(typeof(System.Adsl.RASCONN)); //未连接申请内存空间 5 int connectionCount = 0;//设置连接数 6 int cb = Marshal.SizeOf(typeof(System.Adsl.RASCONN));// 7 int ret = Adsl.RasEnumConnections(connections, ref cb, out connectionCount); 8 Adsl.RasHangUp(connections[0].hrasconn); 9 10 }
代码实在是很简单,一看就明白,因此没必要多啰嗦了,相信各位比我还在行。这个也就是很久以前就流行于网络的方法了。但是这样一个方法其实并不是总能兼容地跑在我们各种各样的机器上,很多电脑和网络环境其实都无法真正实现。
在这里干脆给大家添上上述功能实现的完整代码吧,以免被我说得思路更加不清晰了。^.^
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Runtime.InteropServices; 6 7 namespace System 8 { 9 /// <summary> 10 /// http://www.cnblogs.com/uu102 11 /// 凌晨的搜索者 12 /// </summary> 13 public class Adsl 14 { 15 public const int RAS_MaxDeviceType = 16; 16 public const int RAS_MaxDeviceName = 128; 17 public const int MAX_PATH = 260; 18 public const int ERROR_BUFFER_TOO_SMALL = 603; 19 public const int ERROR_SUCCESS = 0; 20 21 [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Auto)] 22 public struct RASCONN 23 { 24 public int dwSize; 25 public IntPtr hrasconn; 26 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxEntryName)] 27 public string szEntryName; 28 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxDeviceType)] 29 public string szDeviceType; 30 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxDeviceName)] 31 public string szDeviceName; 32 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)] 33 public string szPhonebook; 34 public int dwSubEntry; 35 public Guid guidEntry; 36 public int dwFlags; 37 public Guid luid; 38 } 39 [DllImport("rasapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] 40 public static extern int RasEnumConnections( 41 [In, Out] RASCONN[] rasconn, 42 [In, Out] ref int cb, 43 [Out] out int connections); 44 public const int RAS_MaxEntryName = 256; 45 //挂断拨号,断开网络链接 46 [DllImport("rasapi32.dll", SetLastError = true)] 47 public static extern uint RasHangUp(IntPtr hRasConn); 48 49 [Flags] 50 public enum InternetDialFlags 51 { 52 INTERNET_DIAL_FORCE_PROMPT = 0x2000, 53 INTERNET_DIAL_SHOW_OFFLINE = 0x4000, 54 INTERNET_DIAL_UNATTENDED = 0x8000 55 } 56 [System.Runtime.InteropServices.DllImport("Wininet.dll")] 57 public static extern Int32 InternetDial(IntPtr hwndParent, string lpszConnectoid, Int32 dwFlags, ref Int32 lpdwConnection, Int32 dwReserved); 58 public void DisConnect() 59 { 60 System.Adsl.RASCONN[] connections = new System.Adsl.RASCONN[1];//创建新连接 61 connections[0].dwSize = Marshal.SizeOf(typeof(System.Adsl.RASCONN)); //未连接申请内存空间 62 int connectionCount = 0;//设置连接数 63 int cb = Marshal.SizeOf(typeof(System.Adsl.RASCONN));// 64 int ret = Adsl.RasEnumConnections(connections, ref cb, out connectionCount); 65 Adsl.RasHangUp(connections[0].hrasconn); 66 67 } 68 public string AdslName { get; set; } 69 public string Uid { get; set; } 70 public string Pwd { get; set; } 71 public Adsl(string adslName, string uid, string pwd) 72 { 73 this.AdslName = adslName; 74 this.Uid = uid; 75 this.Pwd = pwd; 76 77 } 78 public System.Diagnostics.Process Connect() 79 { 80 /* int temp = 0; 81 Adsl.InternetDial(IntPtr.Zero, "", (int)Adsl.InternetDialFlags.INTERNET_DIAL_UNATTENDED, ref temp, 0);*/ 82 System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo(); 83 startInfo.FileName = "RasDial"; 84 if (string.IsNullOrEmpty(this.AdslName)) this.AdslName= "宽带连接"; 85 startInfo.Arguments = string.Format("{0} {1} {2}",this.AdslName,this.Uid,this.Pwd); 86 startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; 87 System.Diagnostics.Process process = System.Diagnostics.Process.Start(startInfo); 88 return process; 89 } 90 public System.Diagnostics.Process ReDial() 91 { 92 DisConnect(); 93 return Connect(); 94 } 95 public static System.Diagnostics.Process ClearCookies(string cmd) 96 { 97 System.Diagnostics.Process p = new System.Diagnostics.Process(); 98 p.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; 99 p.StartInfo.FileName = "RunDll32.exe"; 100 // 关闭Shell的使用 101 p.StartInfo.UseShellExecute = false; 102 // 重定向标准输入 103 p.StartInfo.RedirectStandardInput = true; 104 // 重定向标准输出 105 p.StartInfo.RedirectStandardOutput = true; 106 //重定向错误输出 107 p.StartInfo.RedirectStandardError = true; 108 p.StartInfo.CreateNoWindow = true; 109 110 p.Start(); 111 p.StandardInput.WriteLine(cmd); 112 p.StandardInput.WriteLine("exit"); 113 return p; 114 } 115 116 117 118 119 } 120 121 } 122
以上所述是PPPOE下连接方法,如果是路由器下的连接,则有很大不同,由于时间关系,下次再补充说说 路由器下自动更换IP的实现吧!
///******************************************************
///本文作者:凌晨的搜索者
///博客地址:http://www.cnblogs.com/uu102
///本文属于原创,如果有您需要的内容想要转载,请保留此段签名注释,否则作者将保留追究法律责任的权利。
///******************************************************