リモートモニタリングシステムにおける制御端インタフェース応答の遅い浅い分析


     

私のサービス側と徳玉のクライアント
やっとつながって正常に通信できるようになりました-----ログイン要求、インタフェース転送、操作要求、リモート操作(マウス操作、キーボード操作)
 
しかし
つながったかつながったか
しかし、接続後の通信速度が遅いのは卵の痛みだ.
彼のクライアントで私のサービス側がほとんど動かないのを見た.
 
これはどうしてつまむのですか.
これはどうしてつまむのですか.
これはどうしてつまむのですか.
長い間考えていたが、なぜか分からなかった.
 
まず最も簡単な考え方から分析を始める
スクリーンショットのサイズは20 KBくらいです
一秒に50枚の画像を送っても
圧縮なし
帯域幅も8 MBPSあればOK
 
私たちは同じローカルエリアネットワークのイントラネットです
ルーティングによって提供されるネットワーク内帯域幅はこれよりはるかに高い.
 
同じネットワークでなくても
電気通信のADSLを使っています
帯域幅は2 BPS
あの1秒で10枚以上の画像が届くんだね
どうしてこんなカードが?
 
明らかに
多くの人が私が前に考えていたネット通信に問題を起こしたわけではありません.
流量が大きすぎて圧縮が必要です
(もちろん、後期にさらに最適化する際にはこれが考えられますが、現在このカードの卵が痛い画面がほとんど動かない場合はこれによるものではないはずです)
 
今日の授業でソフトウェアの性能テストについて議論しました.
ソフトウェアのパフォーマンスをテストするには
まず、パフォーマンスに影響を与えるボトルネックがどこにあるかを理解する必要があります.
 
この例では、ほとんどが画像が大きすぎると思います.
ネットが届かない
 
私が知りたいのは
サーバからクライアントに画像を生成し、クライアントに画像を表示する
この中でいったいその時間が多いのだろうか.
我々は以下の方法で分析を行う.
             
       
                     
                                 


                         ------------------------------------------
                                
                        ------------------------------------------
                                  
                        ------------------------------------------
                              
                        -----------------------------------------
                              
                        ------------------------------------------
                              
                        ------------------------------------------
                               
                        ------------------------------------------

以上の機能を実現するには,対応する情報に対応するシステム時間を出力するためのツールクラスを実現する.
 
/**
 *         
 * @author mzd
 */
public class Log {
	/**
	 *     INFO       
	 * @param INFO
	 */
	public static void recordTime(String INFO) {
		System.out.println(INFO + getCurrentTime());
	}

	/**
	 *       ,        
	 * @return
	 */
	public static String getCurrentTime() {
		Calendar c = new GregorianCalendar();
		int hour = c.get(Calendar.HOUR_OF_DAY);
		int min = c.get(Calendar.MINUTE);
		int second = c.get(Calendar.SECOND);
		int millsecond = c.get(Calendar.MILLISECOND);
		String time = hour + " " + min + " " + second + " " + millsecond;
		return time;
	}
}

 
そして
サーバ側は,スクリーンショットを,スクリーンショットをパッケージングする前に,スクリーンショットをパッケージングした後,スクリーンショットを送信する前に,スクリーンショットを送信した後にそれぞれこのツールクラスのrecordTime()メソッドを呼び出す.
クライアントは、メッセージを受信する前に、最初のメッセージを受信したときに、今回のすべてのメッセージを受信したときに、メッセージがピクチャに解封される前に、メッセージがピクチャに解封された後にそれぞれツールクラスのrecordTime()メソッドを呼び出す
メソッドを呼び出すたびに記録する情報を記録できます
情報に基づいて各プロセスの時間を分析できる
 
次に、私たちが取得したメッセージをランダムに3つのグループに切り取って分析します(実際に取得したメッセージは数千グループです).
 
サーバ側
クライアント
スクリーンショット0点36分11秒433スクリーンショット画像送信開始0点36分11秒433スクリーンショット画像パッケージング開始0点36分11秒433スクリーンショットパッケージング完了0点36分11秒810スクリーンショット画像送信終了0点36分12秒0
ImageMessageの読み取りを開始する準備->0時36分16秒941 int->0時36分17秒606 byte[]->0時36分17秒783 byte[to Image]->0時36分17秒783変換画像の読み取りが完了し、インタフェースに表示する準備->0時36分17秒841が完了しました.0時36分17秒841
スクリーンショット0点36分12秒230スクリーンショット画像送信開始0点36分12秒230スクリーンショット画像パッケージング開始0点36分12秒230スクリーンショット画像パッケージング完了0点36分12秒745スクリーンショット画像送信終了0点36分12秒931
ImageMessageの読み込みを開始する準備->0時36分17秒841 int->0時36分18秒548 byte[]->0時36分18秒741 byte[to Image]->0時36分18秒741変換画像の読み込みが完了し、画面に表示する準備->0時36分18秒801が完了しました.0点36分18秒801
スクリーンショット0点36分13秒166スクリーンショット画像送信開始0点36分13秒166スクリーンショット画像パッケージング開始0点36分13秒166スクリーンショット画像パッケージング完了0点36分13秒666スクリーンショット画像送信終了0点36分13秒856
ImageMessageの読み取りを開始する準備->0時36分18秒801 int->0時36分19秒500 byte[]->0時36分19秒682 byte[to Image]->0時36分19秒682変換画像の読み取りが完了し、インタフェースに表示する準備->0時36分19秒780表示が完了しました.0時36分19秒780
 
私たちの2日間の機械の時間は違いますが、直接加減演算をして2台の機械の世界差を得ることはできません.
しかし、これは私たちが連続的に測定した3つのデータです.
だから、各データのグループの相互比較分析は多くの問題を得ることができます.
 
まずサーバ側を見てみましょう
1回のメッセージ送信中
サーバがスクリーンショットからスクリーンショット画像の送信を開始するまでの時間消費はほぼ0
スクリーンショット画像の送信から画像のパッケージング開始までの時間消費もほぼ0
ただし、パッケージ化からパッケージ化完了までの時間は500+MS
パッケージ完了から送信完了までの時間は約200 MS
 
このように、画像のセットを送信するたびに
700+MSを消費しました
 
クライアントを見て
私たちの驚くべき発見は
クライアントがメッセージを読むたびに
次のメッセージ(中間のreadブロック)を再読み込みするまでの時間はほぼ700 MSに達した.
一方、1つのメッセージの読み取り開始から1セットのメッセージの読み取り終了までの時間は200 MS未満である
つまり、
クライアントから見る
ほとんどの時間は
ネットワークはまだ空いています
 
画像伝送についてどう考えたか振り返ってみましょう
1つのスレッドで単独で実現することを想定しています
1秒で50個の画像が届くことを望んでいます
 
などと、
よし
問題のキーポイントがやっと出てきた
(私も長いことくだらないことを言っていた)
私たちが望んでいるのは1秒に50個の画像を送ることです.
デルの実装方法は、サーバでスレッドを起動することです.
20 MSのスクリーンショットなしで一度にクライアントに画像を送信
これで1秒に50回できると思った
 
実は私たちは忘れました
独立したスレッド内
メソッドの実行はシリアルであり,マルチスレッド間の並列関係ではない.
(ここではマルチスレッド間と独立した単一スレッド内に注意)
つまり
/**
 *                        
 * @author mzd
 */
public class CastScreenThread extends Thread {
	//     ,                
	ScreenImageMessage _screenImageMessage = null;
	BufferedImage _screenImage = null;
	ArrayList<OnlineClientInfo> _clientsList = null; //      
	OnlineClientInfo clientInfo = null;

	public void run() {
		_clientsList = OnlineClientTableModel.getOnlineClients();
		//          ,    
		while (_clientsList.size()>0) {
			try {
				castScreenImage();
				Thread.sleep(20);
			} catch (Exception ef) {
				ef.printStackTrace();
			}
		}
	}

	/**
	 *                 
	 * @param screenImageMessage
	 */
	public void castScreenImage() {
		_screenImageMessage = this.getScreenImageMessage();	
		for (int i = 0; i < _clientsList.size(); i++) {
			clientInfo = _clientsList.get(i);
			try {
				//          
				if (clientInfo.isMonitor()) {
					//            
					Log.recordTime("        ");
					clientInfo.getThread().sendMessage(_screenImageMessage);
					Log.recordTime("        ");
				}
			} catch (Exception e) {
				System.out.println("          " + e.getMessage());
				e.printStackTrace();
			}
		}
	}

	private ScreenImageMessage getScreenImageMessage() {
		_screenImage = ServerTools.shotScreen();
		Log.recordTime("  ");
		_screenImageMessage = new ScreenImageMessage();
		_screenImageMessage.setBufferedImage(_screenImage);
		_screenImageMessage.setReciverID(0);
		_screenImageMessage.setSenderID(0);
		return _screenImageMessage;
	}
}

 
セグメントコードが果たす役割
ただ私たちが画像を送信するたびに(送信時間7-900 MS)、
スレッドは20 MS休止し、次の画像(送信時間7-900 MS)を送信し、
画像を送るのに必要な7-900 MSは私たちが考えていないものです.
この例は、1つのピクチャ休止20 MSを送信して次のピクチャを送信するスレッドを起動しただけである.
 
 
 
僕らが叶えたかったものは叶わなかった
20 MSごとにクライアントから画像が送信されます
クライアントがサービス・エンド・インタフェースをリアルタイムで監視できるようにする
 
 
さあ、くだらない話はまた一段落した.
 
次に、本題の2つに入ります
 
問題の解決
 
私たちが望む20 MSごとにクライアントに画像を送信するには
実は簡単です
20 MSごとにスクリーンを切り、スレッドを起動して制御側に画像情報を送信します.
リアルタイムモニタリングが可能
 
 
そしてまた冒頭の古い話題に戻りました
ソフトウェアのパフォーマンス
スレッドの作成はコストがかかるアクションです
ずっと作成していたら・・・・・・
効率性とソフトウェアのパフォーマンスのために
伝説のスレッドプールで実現しよう
 
よし
実現の構想は終わった
くだらないことを言わないで、コードを直接見てください.
/**
 *                        
 * @author mzd
 */
public class CastScreenThread extends Thread {

	public void run() {
		//      
		ArrayList<OnlineClientInfo>	_clientsList = OnlineClientTableModel.getOnlineClients();
		//      ,      20
		ExecutorService exec = Executors.newFixedThreadPool(20);
		//          ,    
		while (_clientsList.size() > 0) {
			try {
				// 20              ,          
				ServerScreenImageSender sender = new ServerScreenImageSender();
				exec.execute(sender);
				Thread.sleep(20);
			} catch (Exception ef) {
				ef.printStackTrace();
			}
		}
	}
}

 
/**
 *                        
 * @author mzd
 */
public class CastScreenThread extends Thread {
	ServerScreenImageSender sender;

	public void run() {
		//      ,      20
		ExecutorService exec = Executors.newFixedThreadPool(5);
		//          ,    
		while (true) {
			try {
				// 20              ,          
				sender = new ServerScreenImageSender();
				exec.execute(sender);
				Thread.sleep(20);
			} catch (Exception ef) {
				ef.printStackTrace();
			}
		}
	}
}

 
/**
 *                
 * @author mzd
 */
public class ServerScreenImageSender implements Runnable {
	//     ,                
	ScreenImageMessage _screenImageMessage = null;
	BufferedImage _screenImage = null;	
	OnlineClientInfo clientInfo = null;
	ArrayList<OnlineClientInfo> _clientsList = null; //      

	@Override
	public void run() {
		_clientsList = OnlineClientTableModel.getOnlineClients();
		castScreenImage();
	}

	/**
	 *                 
	 * @param screenImageMessage
	 */
	public void castScreenImage() {
		_screenImageMessage = this.getScreenImageMessage();	
		for (int i = 0; i < _clientsList.size(); i++) {
			clientInfo = _clientsList.get(i);
			try {
				//          
				if (clientInfo.isMonitor()) {
					//            
					Log.recordTime("        ");
					clientInfo.getThread().sendMessage(_screenImageMessage);
					Log.recordTime("        ");
				}
			} catch (Exception e) {
				System.out.println("          " + e.getMessage());
				e.printStackTrace();
			}
		}
	}
	
	private ScreenImageMessage getScreenImageMessage() {
		_screenImage = ServerTools.shotScreen();
		Log.recordTime("  ");
		_screenImageMessage = new ScreenImageMessage();
		_screenImageMessage.setBufferedImage(_screenImage);
		_screenImageMessage.setReciverID(0);
		_screenImageMessage.setSenderID(0);
		return _screenImageMessage;
	}
}

 
 
コードが出た
問題は解決しましたか?
焦らないで
私にはまだ勘定があるから,みんなと計算しなければならない.
 
前に言ったことを覚えています
各メッセージをパッケージ化して送信を開始し、送信が完了するまで
200 MSが必要
ここでは20 MSごとにスレッドを開いて画像を転送します
何が起こるんだ?
みんなに直接新聞を読んだせいでしょう.
sun.awt.image.ImageFormatException: Invalid JPEG file structure: two SOI markers
	at sun.awt.image.JPEGImageDecoder.readImage(Native Method)
	at sun.awt.image.JPEGImageDecoder.produceImage(JPEGImageDecoder.java:119)
	at sun.awt.image.InputStreamImageSource.doFetch(InputStreamImageSource.java:246)
	at sun.awt.image.ImageFetcher.fetchloop(ImageFetcher.java:172)
	at sun.awt.image.ImageFetcher.run(ImageFetcher.java:136)
Exception in thread "Thread-2" java.lang.NegativeArraySizeException
	at net.remote.client.main.RemoteThread.readMessage(RemoteThread.java:79)
	at net.remote.client.main.RemoteThread.process(RemoteThread.java:49)
	at net.remote.client.main.RemoteThread.run(RemoteThread.java:30)

 
これは直接画像を読むフォーマットが正しくありません
Exception in thread "Thread-2" java.lang.NegativeArraySizeException
	at net.remote.client.main.RemoteThread.readMessage(RemoteThread.java:79)
	at net.remote.client.main.RemoteThread.process(RemoteThread.java:49)
	at net.remote.client.main.RemoteThread.run(RemoteThread.java:30)

 
上の2つはクライアントで抱いた間違いです
java.net.SocketException: Software caused connection abort: socket write error
	at java.net.SocketOutputStream.socketWrite0(Native Method)
	at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:92)
	at java.net.SocketOutputStream.write(SocketOutputStream.java:124)
	at cn.javaeye.java_mzd.Monitor.Server.ClientThread.sendMessage(ClientThread.java:321)
	at cn.javaeye.java_mzd.Monitor.Server.ServerScreenImageSender.castScreenImage(ServerScreenImageSender.java:38)
	at cn.javaeye.java_mzd.Monitor.Server.ServerScreenImageSender.run(ServerScreenImageSender.java:22)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)        2 25 50 250

	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
	at java.lang.Thread.run(Thread.java:619)

 
これは私のサーバーのせいです.
 
何度かやってみた
いくつかの異なる誤りを得る
この問題は.....
 
 
こんな不思議なことはどうしてですか.
契約に問題があることは分かってる
ただ
協議の前はすべて良いのに
今すぐ問題が発生しますか?
理屈は簡単だ
下図を見る
           SendMessage         OutputStream   

         Thread 1                           Thread 2
               Out(m1)                              Out(j1)
               Out(m2)                              Out(j2)
               Out(m3)                              Out(j3)

      
  m1-m2-m3        
          
            (cpu  )
            m1-m2-m3
     m1-m2-j1
       m1-j1-j2
……………………
               
      
             



 
 
 
この問題を解決するには、より簡単なコードは必要ありません.
(sendMessageメソッドまたはoutputStreamの前にロック(synchronized)を追加してロックし、同時に1つのスレッドでしか使用できないようにする必要があります)
この半行コードのことは、私は代わりに貼らない.の
 
 
よし
言うべきことはほとんど言わなかった
もう終わりだ
再接続
ハハハ~~~~
やはりインターフェイスのほうが映りやすいですね
ああ~~
 
 
もしあなたが私を思うなら
問題は終わった
君は間違ってる
 
あなたは私のくどい程度を信じます
 
今、私たちは再び前に述べた圧縮問題に戻ります.
私は自分で何年か数学を学んだことがある.
もう一度みんなに勘定を計算してもらう
もし
もし私たちが1秒で本当に50枚の画像を出すことができたら
もしスクリーンショットのサイズが20 KBだったら(十分でしょう?)
それでは1秒の発生する流量はすべて20*50*8=8 MKPSです
私たちの電気通信のADSLはいくらですか?
2 MBPSはまだ理想的な状態です
あなたに8 MBPSのあなたをあげてすべて使うことができません(理想の状態*80%)
 
だから
あっしゅく
やはり垂らさなきゃ
 
圧縮するには
送信前に圧縮する必要があります
受け入れてから解凍する
△くだらない話じゃないですか.
 
現在
もう少し簡単に勘定しましょう.
広域ネットワークでリモートモニタリングを使用すると
両方の帯域幅は2 BPS
画像を20 KBから10 KBに圧縮しても(圧縮率は十分ですか?)
それでは1 secondでも25枚くらい送れます
でも20 MSで1枚
これで50枚です
たとえ言っても
おとなしくしろ
その画像の時間を長くしましょう.
短くて役に立たない
画像はどうしても公開されます
デスクトップ表示のリアルタイム性も低下
(わかりました?10分も経ったかもしれませんが、前の5分目の写真を送っています)
うん
どんなに細かくてももうやめたくない.
とりあえず20 MSから50 MSに変更しよう
 
前のソフトウェア性能に基づいてデータをテストする
僕らは知ってる
既存のネットワーク(ワイヤレスカードで寝室のワイヤレスルーティングにアクセス)
私たちがネット上で1つの画像情報を送信するのにかかる時間は200 MS程度です.
つまり
私たちは1 secondで5枚ぐらいの画像しか出せません.
大きさは800 MBPSのはずです
私たちのネットワークは簡単に耐えられます
 
圧縮後のデータとか具体的に
兄が何かZIPINPUTを見てから研究しましょう.
 
うん
きょうのくだらない話はこれで終わりだ
自分が夜7時から忙しくて今までのまとめでしょう.
この鳥のプログラムを一緒に書いた皆さんにもヒントを与えてほしいです.