上次写了篇使用的博客,收到了不少宝贵意见,后来又懒得去改进,所以也没有新的文章。最近,由于学校宿舍也装校园网了,不再是用Dr.Com,我满怀心喜地试用了Srun3000,结果发现会出现连接上就一两秒掉网现象,并且提示说我的网络出现问题,与服务器连接断开,怒了!我试过各种办法,当然不包括换系统(我用的Win7),还是不行,网卡驱动也都是正常的。于是我试着用抓了次HTTP包,发现了问题所在。
原来,srun3000会在发送了连接的包后,又自动发了个注销的包,所以导致我网络中断,并且它在提示错误后就马上自动退出了,导致我产生了程序产生致命错误的假象……好吧,先上个图,看下srun3000的“罪证”:
先后发的两条数据,第一条便是登录,第二条便是注销(为什么会自动注销,我用ollydbg跟进看了一会,由于汇编太难看了,而且我又比较懒,所以没分析出来),这导致了我网络的中断。为了验证我的想法,我使用Fiddler手动把登录的包重发了一次,果然能正常上网了,而且到第二天都没有掉过。所以大家可以看到我这篇文章,同样使用客户端的方式,基于HTTP协议来开发一个代替Srun3000的软件。
1、功能:连接、注销、程序开机启动、自动登录、记住密码、连接后自动最小化
2、界面:WPF窗口、通知栏图标、软件功能设置、异步连接断开
3、效果:
4、基本原理:
从抓到的数据来看,连接和断开都使用的是POST,只需要根据它的格式依照Post数据过去就可以实现连接和断开。
连接:
POST http://172.30.16.53/cgi-bin/srun_portal HTTP/1.1Content-Type: application/x-www-form-urlencodedUser-Agent: my sessionHost: 172.30.16.53Content-Length: 138Pragma: no-cacheaction=login&username=******&password=******&drop=0&type=2&n=23&ip=0&mbytes=0&minutes=0&ac_id=3&mac=**:**:**:**:**:**&nas_ip=172.30.12.244
断开:
POST http://172.30.16.53/cgi-bin/srun_portal HTTP/1.1Content-Type: application/x-www-form-urlencodedUser-Agent: my sessionHost: 172.30.16.53Content-Length: 87Pragma: no-cacheaction=logout&ac_id=3&username=******&mac=**:**:**:**:**:**&type=2&nas_ip=172.30.12.244
为了安全起见,我把上面的username、password、mac三个字段的值都用“*”号代替了。
5、核心代码
现在我在C#客户端只需要分别使用HttpWebRequest仿照进行请求就行了,我贴上连接的核心代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 private FuncConnectDelegate = Connect; // 连接委托 2 // 连接执行函数 3 private string Connect() 4 { 5 try 6 { 7 var settings = Properties.Settings.Default; 8 Uri uri = new Uri("http://" + settings.GateIP + settings.RelativeUri); 9 // 新建请求10 var request = HttpWebRequest.Create(uri);11 request.Method = "POST";12 request.ContentType = "application/x-www-form-urlencoded";13 // 请求体14 var body = Encoding.ASCII.GetBytes(15 "action=login&username=" + UserName +16 "&password=" + Password +17 "&drop=0&type=2&n=23&ip=0&mbytes=0&minutes=0&ac_id=3&mac=" + _MacAddress +18 "&nas_ip=" + settings.NasIP19 );20 request.ContentLength = body.Length;21 request.Timeout = 5000;22 var requestStream = request.GetRequestStream();23 requestStream.Write(body, 0, body.Length);24 requestStream.Close();25 // 发送请求并接收结果26 string responseBody;27 var response = request.GetResponse();28 var responseStream = response.GetResponseStream();29 using (StreamReader reader = new StreamReader(responseStream))30 responseBody = reader.ReadToEnd();31 if (responseBody.Contains("login_ok"))32 {33 _State = ConnectionState.Connected;34 return "连接成功!";35 }36 else if (responseBody.Contains("online_num_error"))37 {38 //var ping = new System.Net.NetworkInformation.Ping();39 //ping.Send("www.baidu.com");40 _State = ConnectionState.Connected;41 return "已经连接上,请不要重复登录!";42 }43 else if (responseBody.Contains("username_error"))44 return "帐号错误,请重新输入!";45 else if (responseBody.Contains("password_error"))46 return "密码错误,请重新输入!";47 else48 return "连接失败:" + responseBody;49 }50 catch (HttpListenerException ex)51 {52 return "HTTP请求出错,请检查网络是否正常!错误代码:" + ex.ErrorCode; 53 }54 catch (Exception ex)55 {56 return "连接失败!错误详情:" + ex.Message;57 }58 }
基本情况就是通过POST请求获取返回体,然后根据返回体的内容判断连接状态,这些返回数据牲也是使用Fiddler抓取的,比如“login_ok”、“online_num_error”、“username_error”、“password_error”、“logout_ok”等。当然这仅仅只是数据通信的部分,还有其它与界面相关的处理就不多说了,另外断开操作与连接操作也非常相似,也就不贴了。经过我的观察,由于Srun3000并没有在线检测机制,它只是通知认证网关把相应的MAC地址放行,而且认证服务器也不管回收离线地址(需要Srun3000自己去POST logout请求),所以我也不用去ping了,也不用写心跳包了,so easy。
接下来,我顺便贴上修改注册表使程序开机启动的代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 private void AutoStartupChanged() 2 { 3 RegistryKey HKLM = Registry.LocalMachine; 4 // 确认当前状态 5 string name = AppDomain.CurrentDomain.FriendlyName; 6 name = name.Substring(0, name.LastIndexOf('.')); 7 var run = HKLM.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run"); 8 bool hasValue = run.GetValue(name) != null; 9 try10 {11 if (!hasValue && AutoStartup) // 添加启动12 {13 run = HKLM.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true);14 run.SetValue(name, AppDomain.CurrentDomain.BaseDirectory + name + ".exe");15 }16 else if (hasValue && !AutoStartup) // 删除启动17 {18 run = HKLM.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true);19 run.DeleteValue(name);20 }21 }22 catch (System.Exception ex)23 {24 Message = "操作失败:" + ex.Message;25 }26 }
主要也就是使用了SOFTWARE\Microsoft\Windows\CurrentVersion\Run下面的项来增加删除开机启动,这里不采用Windows服务来写的原因是,我想让这个软件成为“绿色”可携带的版本。
其它也就不多说了,此软件目前为止用了一个星期,效果不错,没掉过线也。
转载请注明原址: