WiFiとホットスポット開発-tcp接続リアルタイムログを表示
19094 ワード
私は長年Androidスマートデバイスの開発に従事し、携帯電話、MiFi、スマートドアロックなどの製品を作ったことがあります.携帯電話のほか、他の製品は後期のメンテナンスとバージョンの反復の過程で、デバイスのログを分析して問題を特定する必要があります.例えば、スマートドアロックは、故障したとき、いつもノートパソコンを持って、デバイスのusbデバッグスイッチを開けた後、問題の再現とログ分析をusb線接続デバイスで行います.もちろん、ログの取得方法は多種多様で、ネット上でアップロードすることもできます.しかし、必ず現場を見る必要があります.現場を見ると問題があります.ノートパソコンは持ち歩いているわけではありません.携帯電話は確かに持ち歩いています.そのため、携帯電話側でリアルタイムに設備のログを見ることができますか.答えは肯定的だ.MiFiとスマートドアロックはホットスポットを開放しているため、デバッグした携帯電話は設備のホットスポットに接続でき、グループネットワークを行った後、リアルタイムのログ表示を実現することができる.この方法では、データケーブルもノートパソコンも必要なく、usbデバッグスイッチもオンにする必要はありません.まず、サービス・エンド(プロビジョニング・エンド)について説明します.ここではスレッド・プールが使用されていることに注意してください.そのため、サービス・エンドは1対多の応答を行う基礎的な能力を備えています.
コードには、他のデバイス制御インタフェースが省略されています.リアルタイムログ表示インタフェースと、リアルタイム表示インタフェースを終了することに注意してください.
実はキューからログの内容をループして対端に送信します.では、ログはどこでキューに参加しますか?私はログを記録する方法をApplicationに書きましたが、工事記録ログ全体が最終的にこの方法に進みます.では、ログを記録しながらそのキューに参加すればいいです.
このキューは、リアルタイムログの表示コマンドを受信したときに初期化され、リアルタイムログの表示を終了したときに空になります(ログはキューに参加しません):
サービス側はこのようにして、次にクライアントを見ます.
実際には、1つのスレッドがサービス側から返されたデータをブロックして読み取り、もう1つのスレッドがキューからデータを繰り返してUIスレッドに送信してUIリフレッシュを行うほど複雑ではないことがわかります.
/**
* @ tcp
*/
public void startTCP() {
if (runnableTcp != null) {
isStart = false;
runnableTcp = null;
}
try {
runnableTcp = new TcpReceive();
threadTcp = new Thread(runnableTcp);
isStart = true;
threadTcp.start();
} catch (Exception e) {
logd(" TCP :" + e.getMessage());
}
try {
mExe = Executors.newCachedThreadPool();//
} catch (Exception e) {
logd(" :" + e);
}
}
private class TcpReceive implements Runnable {
Socket socket = null;
ServerSocket server = null;
public void run() {
try {
//server = new ServerSocket(53858);
if (server == null) {
server = new ServerSocket();
server.setReuseAddress(true);
server.bind(new InetSocketAddress(53858));
}
allSockets = new HashSet();
while (isRunning) {
if (!server.isClosed()) {
//logd("serverSocket "+server.hashCode()+" 53858 ...");
socket = server.accept();
}
if (socket != null) {
allSockets.add(socket);
//logd(" socket " + socket.hashCode() + " , socket :" + allSockets.size());
mExe.execute(new EchoThread(socket));
}
}
} catch (IOException e) {
logd("serverSocket "+e);
}
}
}
public class EchoThread extends Thread {
Socket socket;
PrintWriter out;
BufferedReader in;
public EchoThread(Socket _socket){
socket = _socket;
try {
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException e) {
logd("PrintWriter BufferedReader "+e);
}
}
public void run() {
try {
while (isStart) {
if (socket == null || socket.isClosed() || !socket.isBound() || !socket.isConnected()) {
break;
}
String line = in.readLine();
String ip = socket.getInetAddress().toString();
if (ip.contains("/")) {
ip = ip.substring(1, ip.length());
}
if (line == null){
logd("line ");
break;
}
String temp[] = line.split("/");
if(temp == null || temp.length <2 ||!temp[0].equals(TcpConfig._HEAD_)){
return;
}else{
line = temp[1];
}
if (!line.equals(TcpConfig.GET_DEVICE_INFO) && !line.contains(TcpConfig.RESTART_TEST_GET_RES)){
logd("Tcp app :" + line + ";app ip :" + ip);
}
if (line.equals(TcpConfig.GET_REAL_TIME_LOGS)) {
isRealTimeLogs = true;
App.getInstance().setRealTimeLogQueque(mQueue);
String logs = null;
while (isRealTimeLogs) {
try {
logs = mQueue.take();
out.println(logs);
Thread.sleep(20);
} catch (Exception e) {
e.printStackTrace();
logd(e);
}
}
out.print("false,quit.");
}
if (!isCmds(line)) {
out.println("Request Error");
}
out.flush();
out.close();
socket.close();
allSockets.remove(socket);
}
} catch (IOException e) {
e.printStackTrace();
logd("socket :" + e);
} finally {
try {
if (in != null) {
// logd("BufferedReader ,hashCode:" + in.hashCode());
in.close();
}
if (out != null) {
// logd("PrintWriter ,hashCode:" + out.hashCode());
out.close();
}
if (socket != null) {
// logd("socket "+socket.hashCode()+" ");
socket.close();
allSockets.remove(socket);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
コードには、他のデバイス制御インタフェースが省略されています.リアルタイムログ表示インタフェースと、リアルタイム表示インタフェースを終了することに注意してください.
if (line.equals(TcpConfig.GET_REAL_TIME_LOGS)) {
isRealTimeLogs = true;
App.getInstance().setRealTimeLogQueque(mQueue);
String logs = null;
while (isRealTimeLogs) {
try {
logs = mQueue.take();
out.println(logs);
Thread.sleep(20);
} catch (Exception e) {
e.printStackTrace();
logd(e);
}
}
out.print("false,quit.");
}
if(line.equals(TcpConfig.CANCEL_REAL_TIME_LOGS)){
isRealTimeLogs = false;
mQueue.clear();
App.getInstance().setRealTimeLogQueque(null);
out.print(true);
}
実はキューからログの内容をループして対端に送信します.では、ログはどこでキューに参加しますか?私はログを記録する方法をApplicationに書きましたが、工事記録ログ全体が最終的にこの方法に進みます.では、ログを記録しながらそのキューに参加すればいいです.
/**
* @ Log
*/
public static void showTestInfo(final Object msg) {
if (msg == null || msg.toString().isEmpty()) {
return;
}
String appMsg = getDateToStringStyle("MM-dd HH:mm:ss,SSS", new Date()) + ":" + msg.toString();
if (logger == null) {
logger = Logger.getLogger(TGTConfig.TAG);
}
logger.warn(appMsg);
if(mQueue != null){
mQueue.add(appMsg);
}
}
このキューは、リアルタイムログの表示コマンドを受信したときに初期化され、リアルタイムログの表示を終了したときに空になります(ログはキューに参加しません):
private static PriorityBlockingQueue mQueue;
public void setRealTimeLogQueque(PriorityBlockingQueue queue){
mQueue = queue;
}
サービス側はこのようにして、次にクライアントを見ます.
private void startRealTimeLog(){
cmd = TcpConfig.GET_REAL_TIME_LOGS;
new Thread(sendTcp).start();
new Thread(new Runnable() {
@Override
public void run() {
doloop();
}
}).start();
}
private void stopRealTimeLog(){
cmd = TcpConfig.CANCEL_REAL_TIME_LOGS;
new Thread(sendTcp).start();
}
private void doloop(){
String res = null;
while (isStart){
try{
res = mQueue.take();
addIntoList(res);
Thread.sleep(50);
}catch (Exception e){
e.printStackTrace();
logd(e);
}
}
logd("loop quit.");
}
private void addIntoList(String string){
if (realTimeLogs.size() > MAX_LINE) {
realTimeLogs.removeFirst();
}
realTimeLogs.add(string);
uiHandler.removeMessages(MSG_REFRESH_UI);
uiHandler.sendMessageDelayed(Message.obtain(uiHandler,MSG_REFRESH_UI,0,0,realTimeLogs),100);
}
Runnable sendTcp = new Runnable() {
@Override
public void run() {
BufferedReader in = null;
PrintWriter out = null;
Socket socket = new Socket();
try {
socket.connect(new InetSocketAddress(TcpUtil.hostIP, TcpConfig.port), 10 * 1000);
if (!cmd.isEmpty()) {
while (socket.isConnected() && !socket.isClosed()) {
try {
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
out.println(TcpConfig._HEAD_ + "/" + cmd);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
logd(line);
mQueue.add(line);
}
break;
} catch (Exception e) {
e.printStackTrace();
logd(e);
}
}
}
} catch (IOException e) {
e.printStackTrace();
logd(e);
} finally {
try {
if (in != null)
in.close();
if (socket != null)
socket.close();
if (out != null)
out.close();
} catch (IOException e) {
logd(e);
}
}
}
};
実際には、1つのスレッドがサービス側から返されたデータをブロックして読み取り、もう1つのスレッドがキューからデータを繰り返してUIスレッドに送信してUIリフレッシュを行うほど複雑ではないことがわかります.