package com.netease.LDNetDiagnoService; import java.io.IOException; import java.net.HttpURLConnection; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import android.content.Context; import android.telephony.TelephonyManager; import android.text.TextUtils; import com.netease.LDNetDiagnoService.LDNetPing.LDNetPingListener; import com.netease.LDNetDiagnoService.LDNetSocket.LDNetSocketListener; import com.netease.LDNetDiagnoService.LDNetTraceRoute.LDNetTraceRouteListener; import com.netease.LDNetDiagnoUtils.LDNetUtil; /** * 网络诊断服务 通过对制定域名进行ping诊断和traceroute诊断收集诊断日志 * * @author panghui * */ public class LDNetDiagnoService extends LDNetAsyncTaskEx<String, String, String> implements LDNetPingListener, LDNetTraceRouteListener, LDNetSocketListener { private String _appCode; // 客户端标记 private String _appName; private String _appVersion; private String _UID; // 用户ID private String _deviceID; // 客户端机器ID,如果不传入会默认取API提供的机器ID private String _dormain; // 接口域名 private String _carrierName; private String _ISOCountryCode; private String _MobileCountryCode; private String _MobileNetCode; private boolean _isNetConnected;// 当前是否联网 private boolean _isDomainParseOk;// 域名解析是否成功 private boolean _isSocketConnected;// conected是否成功 private Context _context; private String _netType; private String _localIp; private String _gateWay; private String _dns1; private String _dns2; private InetAddress[] _remoteInet; private List<String> _remoteIpList; private final StringBuilder _logInfo = new StringBuilder(256); private LDNetSocket _netSocker;// 监控socket的连接时间 private LDNetPing _netPinger; // 监控ping命令的执行时间 private LDNetTraceRoute _traceRouter; // 监控ping模拟traceroute的执行过程 private boolean _isRunning; private LDNetDiagnoListener _netDiagnolistener; // 将监控日志上报到前段页面 private boolean _isUseJNICConn = false; private boolean _isUseJNICTrace = true; private TelephonyManager _telManager = null; // 用于获取网络基本信息 public LDNetDiagnoService() { super(); } /** * 初始化网络诊断服务 * * @param theAppCode * @param theDeviceID * @param theUID * @param theDormain */ public LDNetDiagnoService(Context context, String theAppCode, String theAppName, String theAppVersion, String theUID, String theDeviceID, String theDormain, String theCarrierName, String theISOCountryCode, String theMobileCountryCode, String theMobileNetCode, LDNetDiagnoListener theListener) { super(); this._context = context; this._appCode = theAppCode; this._appName = theAppName; this._appVersion = theAppVersion; this._UID = theUID; this._deviceID = theDeviceID; this._dormain = theDormain; this._carrierName = theCarrierName; this._ISOCountryCode = theISOCountryCode; this._MobileCountryCode = theMobileCountryCode; this._MobileNetCode = theMobileNetCode; this._netDiagnolistener = theListener; // this._isRunning = false; _remoteIpList = new ArrayList<String>(); _telManager = (TelephonyManager) context .getSystemService(Context.TELEPHONY_SERVICE); sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory); } @Override protected String doInBackground(String... params) { if (this.isCancelled()) return null; // TODO Auto-generated method stub return this.startNetDiagnosis(); } @Override protected void onPostExecute(String result) { if (this.isCancelled()) return; super.onPostExecute(result); // 线程执行结束 recordStepInfo("\n网络诊断结束\n"); this.stopNetDialogsis(); if (_netDiagnolistener != null) { _netDiagnolistener.OnNetDiagnoFinished(_logInfo.toString()); } } @Override protected void onProgressUpdate(String... values) { if (this.isCancelled()) return; // TODO Auto-generated method stub super.onProgressUpdate(values); if (_netDiagnolistener != null) { _netDiagnolistener.OnNetDiagnoUpdated(values[0]); } } @Override protected void onCancelled() { this.stopNetDialogsis(); } /** * 开始诊断网络 */ public String startNetDiagnosis() { if (TextUtils.isEmpty(this._dormain)) return ""; this._isRunning = true; this._logInfo.setLength(0); recordStepInfo("开始诊断...\n"); recordCurrentAppVersion(); recordLocalNetEnvironmentInfo(); if (_isNetConnected) { // 获取运营商信息 //recordStepInfo("\n开始获取运营商信息..."); //String operatorInfo = requestOperatorInfo(); //if (operatorInfo != null) { //recordStepInfo(operatorInfo); //} // TCP三次握手时间测试 recordStepInfo("\n开始TCP连接测试..."); _netSocker = LDNetSocket.getInstance(); _netSocker._remoteInet = _remoteInet; _netSocker._remoteIpList = _remoteIpList; _netSocker.initListener(this); _netSocker.isCConn = this._isUseJNICConn;// 设置是否启用C进行connected _isSocketConnected = _netSocker.exec(_dormain); // 诊断ping信息, 同步过程 if (!(_isNetConnected && _isDomainParseOk && _isSocketConnected)) {// 联网&&DNS解析成功&&connect测试成功 recordStepInfo("\n开始ping..."); _netPinger = new LDNetPing(this, 4); recordStepInfo("ping...127.0.0.1"); _netPinger.exec("127.0.0.1", false); recordStepInfo("ping本机IP..." + _localIp); _netPinger.exec(_localIp, false); if (LDNetUtil.NETWORKTYPE_WIFI.equals(_netType)) {// 在wifi下ping网关 recordStepInfo("ping本地网关..." + _gateWay); _netPinger.exec(_gateWay, false); } recordStepInfo("ping本地DNS1..." + _dns1); _netPinger.exec(_dns1, false); recordStepInfo("ping本地DNS2..." + _dns2); _netPinger.exec(_dns2, false); } if (_netPinger == null) { _netPinger = new LDNetPing(this, 4); } if (_netPinger != null) { //recordStepInfo("ping..." + LDNetUtil.OPEN_IP); //_netPinger.exec(LDNetUtil.OPEN_IP, true); } // 开始诊断traceRoute recordStepInfo("\n开始traceroute..."); _traceRouter = LDNetTraceRoute.getInstance(); _traceRouter.initListenter(this); _traceRouter.isCTrace = this._isUseJNICTrace; _traceRouter.startTraceRoute(_dormain); return _logInfo.toString(); } else { recordStepInfo("\n\n当前主机未联网,请检查网络!"); return _logInfo.toString(); } } /** * 停止诊断网络 */ public void stopNetDialogsis() { if (_isRunning) { if (_netSocker != null) { _netSocker.resetInstance(); _netSocker = null; } if (_netPinger != null) { _netPinger = null; } if (_traceRouter != null) { _traceRouter.resetInstance(); _traceRouter = null; } cancel(true);// 尝试去取消线程的执行 if (sExecutor != null && !sExecutor.isShutdown()) { sExecutor.shutdown(); sExecutor = null; } _isRunning = false; } } /** * 设置是否需要JNICTraceRoute * * @param use */ public void setIfUseJNICConn(boolean use) { this._isUseJNICConn = use; } /** * 设置是否需要JNICTraceRoute * * @param use */ public void setIfUseJNICTrace(boolean use) { this._isUseJNICTrace = use; } /** * 打印整体loginInfo; */ public void printLogInfo() { System.out.print(_logInfo); } /** * 如果调用者实现了stepInfo接口,输出信息 * * @param stepInfo */ private void recordStepInfo(String stepInfo) { _logInfo.append(stepInfo + "\n"); publishProgress(stepInfo + "\n"); } /** * traceroute 消息跟踪 */ @Override public void OnNetTraceFinished() { } @Override public void OnNetTraceUpdated(String log) { if (log == null) { return; } if (this._traceRouter != null && this._traceRouter.isCTrace) { if (log.contains("ms") || log.contains("***")) { log += "\n"; } _logInfo.append(log); publishProgress(log); } else { this.recordStepInfo(log); } } /** * socket完成跟踪 */ @Override public void OnNetSocketFinished(String log) { _logInfo.append(log); publishProgress(log); } /** * socket更新跟踪 */ @Override public void OnNetSocketUpdated(String log) { _logInfo.append(log); publishProgress(log); } /** * 输出关于应用、机器、网络诊断的基本信息 */ private void recordCurrentAppVersion() { // 输出应用版本信息和用户ID recordStepInfo("应用code:\t" + _appCode); recordStepInfo("应用名称:\t" + this._appName); recordStepInfo("应用版本:\t" + this._appVersion); // recordStepInfo("用户id:\t" + _UID); // 输出机器信息 recordStepInfo("机器类型:\t" + android.os.Build.MANUFACTURER + ":" + android.os.Build.BRAND + ":" + android.os.Build.MODEL); recordStepInfo("系统版本:\t" + android.os.Build.VERSION.RELEASE); if (_telManager != null && TextUtils.isEmpty(_deviceID)) { _deviceID = _telManager.getDeviceId(); } recordStepInfo("机器ID:\t" + _deviceID); // 运营商信息 if (TextUtils.isEmpty(_carrierName)) { _carrierName = LDNetUtil.getMobileOperator(_context); } recordStepInfo("运营商:\t" + _carrierName); if (_telManager != null && TextUtils.isEmpty(_ISOCountryCode)) { _ISOCountryCode = _telManager.getNetworkCountryIso(); } recordStepInfo("ISOCountryCode:\t" + _ISOCountryCode); if (_telManager != null && TextUtils.isEmpty(_MobileCountryCode)) { String tmp = _telManager.getNetworkOperator(); if (tmp.length() >= 3) { _MobileCountryCode = tmp.substring(0, 3); } if (tmp.length() >= 5) { _MobileNetCode = tmp.substring(3, 5); } } recordStepInfo("MobileCountryCode:\t" + _MobileCountryCode); recordStepInfo("MobileNetworkCode:\t" + _MobileNetCode+"\n"); } /** * 输出本地网络环境信息 */ private void recordLocalNetEnvironmentInfo() { recordStepInfo("诊断域名 " + _dormain + "..."); // 网络状态 if (LDNetUtil.isNetworkConnected(_context)) { _isNetConnected = true; recordStepInfo("当前是否联网:\t" + "已联网"); } else { _isNetConnected = false; recordStepInfo("当前是否联网:\t" + "未联网"); } // 获取当前网络类型 _netType = LDNetUtil.getNetWorkType(_context); recordStepInfo("当前联网类型:\t" + _netType); if (_isNetConnected) { if (LDNetUtil.NETWORKTYPE_WIFI.equals(_netType)) { // wifi:获取本地ip和网关,其他类型:只获取ip _localIp = LDNetUtil.getLocalIpByWifi(_context); _gateWay = LDNetUtil.pingGateWayInWifi(_context); } else { _localIp = LDNetUtil.getLocalIpBy3G(); } recordStepInfo("本地IP:\t" + _localIp); } else { recordStepInfo("本地IP:\t" + "127.0.0.1"); } if (_gateWay != null) { recordStepInfo("本地网关:\t" + this._gateWay); } // 获取本地DNS地址 if (_isNetConnected) { _dns1 = LDNetUtil.getLocalDns("dns1"); _dns2 = LDNetUtil.getLocalDns("dns2"); recordStepInfo("本地DNS:\t" + this._dns1 + "," + this._dns2); } else { recordStepInfo("本地DNS:\t" + "0.0.0.0" + "," + "0.0.0.0"); } // 获取远端域名的DNS解析地址 if (_isNetConnected) { recordStepInfo("远端域名:\t" + this._dormain); _isDomainParseOk = parseDomain(this._dormain);// 域名解析 } } /** * 域名解析 */ private boolean parseDomain(String _dormain) { boolean flag = false; int len = 0; String ipString = ""; Map<String, Object> map = LDNetUtil.getDomainIp(_dormain); String useTime = (String) map.get("useTime"); _remoteInet = (InetAddress[]) map.get("remoteInet"); String timeShow = null; if (Integer.parseInt(useTime) > 5000) {// 如果大于1000ms,则换用s来显示 timeShow = " (" + Integer.parseInt(useTime) / 1000 + "s)"; } else { timeShow = " (" + useTime + "ms)"; } if (_remoteInet != null) {// 解析正确 len = _remoteInet.length; for (int i = 0; i < len; i++) { _remoteIpList.add(_remoteInet[i].getHostAddress()); ipString += _remoteInet[i].getHostAddress() + ","; } ipString = ipString.substring(0, ipString.length() - 1); recordStepInfo("DNS解析结果:\t" + ipString + timeShow); flag = true; } else {// 解析不到,判断第一次解析耗时,如果大于10s进行第二次解析 if (Integer.parseInt(useTime) > 10000) { map = LDNetUtil.getDomainIp(_dormain); useTime = (String) map.get("useTime"); _remoteInet = (InetAddress[]) map.get("remoteInet"); if (Integer.parseInt(useTime) > 5000) {// 如果大于1000ms,则换用s来显示 timeShow = " (" + Integer.parseInt(useTime) / 1000 + "s)"; } else { timeShow = " (" + useTime + "ms)"; } if (_remoteInet != null) { len = _remoteInet.length; for (int i = 0; i < len; i++) { _remoteIpList.add(_remoteInet[i].getHostAddress()); ipString += _remoteInet[i].getHostAddress() + ","; } ipString = ipString.substring(0, ipString.length() - 1); recordStepInfo("DNS解析结果:\t" + ipString + timeShow); flag = true; } else { recordStepInfo("DNS解析结果:\t" + "解析失败" + timeShow); } } else { recordStepInfo("DNS解析结果:\t" + "解析失败" + timeShow); } } return flag; } /** * 获取运营商信息 */ private String requestOperatorInfo() { String res = null; String url = LDNetUtil.OPERATOR_URL; HttpURLConnection conn = null; URL Operator_url; try { Operator_url = new URL(url); conn = (HttpURLConnection) Operator_url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(1000 * 10); conn.connect(); int responseCode = conn.getResponseCode(); if (responseCode == 200) { res = LDNetUtil.getStringFromStream(conn.getInputStream()); if (conn != null) { conn.disconnect(); } } return res; } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { if (conn != null) { conn.disconnect(); } } return res; } /** * ping 消息跟踪 */ @Override public void OnNetPingFinished(String log) { this.recordStepInfo(log); } private static final int CORE_POOL_SIZE = 1;// 4 private static final int MAXIMUM_POOL_SIZE = 1;// 10 private static final int KEEP_ALIVE = 10;// 10 private static final BlockingQueue<Runnable> sWorkQueue = new LinkedBlockingQueue<Runnable>( 2);// 2 private static final ThreadFactory sThreadFactory = new ThreadFactory() { private final AtomicInteger mCount = new AtomicInteger(1); @Override public Thread newThread(Runnable r) { Thread t = new Thread(r, "Trace #" + mCount.getAndIncrement()); t.setPriority(Thread.MIN_PRIORITY); return t; } }; private static ThreadPoolExecutor sExecutor = null; @Override protected ThreadPoolExecutor getThreadPoolExecutor() { // TODO Auto-generated method stub return sExecutor; } }