- PR -

クライアント-サーブレット間の通信について

投稿者投稿内容
swat
常連さん
会議室デビュー日: 2002/03/21
投稿数: 33
お住まい・勤務地: 埼玉県
投稿日時: 2004-03-23 16:47
swatです。

7Mというサイズで検証していないので、できなかったor役に立たなかったらごめんなさいなんですが、

Hashtableをメンバに持つ自前のクラスを作って、Serializableではなく、Externalizableをimplementsして、readExternal、writeExternalを実装したらどうでしょう?
Externalizableだと、読み込み書出しの実装をする必要がありますが、クラス情報の書出し方法が違うため、Serializableよりはサイズが小さくなると思います。以前、RMIで受け渡しをするクラスにこの方法を導入して、直列化されたサイズを約3分の2くらいまで減らしたことがあります。そのときは数十KBくらいのインスタンスでしたが。

コードだと、こんな感じだと思います。(すみません、検証してませんが)
コード:
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Hashtable;
import java.util.Iterator;

public class MyHash implements Externalizable {
  
  private Hashtable table = new Hashtable();
  private int nufOfEntry;

  public void readExternal(ObjectInput in)
    throws IOException, ClassNotFoundException {
      int num = in.readInt();
      
      for(int i=0; i<num; i++){
        String key = in.readUTF();
        String val = in.readUTF();
        table.put(key, val);
      }      
  }

  public void writeExternal(ObjectOutput out) throws IOException {
    int num = table.size();
    out.writeInt(num);
    for (Iterator iter = table.keySet().iterator(); iter.hasNext(); ) {
      String key = (String) iter.next();
      String val = (String) table.get(key);
      out.writeUTF(key);
      out.writeUTF(val);
    }
  }

  public Object get(Object key) {
    return table.get(key);
  }

  public Object put(Object key, Object value) {
    return table.put(key, value);
  }

}



参考になれば幸いです。
_________________
****** swat ******
http://www.h7.dion.ne.jp/~s_wat/
http://d.hatena.ne.jp/swat/
シュン
ぬし
会議室デビュー日: 2004/01/06
投稿数: 328
お住まい・勤務地: 東京都
投稿日時: 2004-03-24 11:01
swatさん同様、自分のイメージをコード化してみました。この方が私の意図が伝わるでしょうか?

・#readObject(ObjectInputStream)の実装は省略しています。
・このままですと、重複するvalueの検出アルゴリズムが低速です。より賢いロジックはそちらでお考え下さい^^;
・JDBC ResultSetが返す全てのデータを転送する場合、そのデータ全てに対してFlyweight化の効果を得るために、「同様の方針でシリアライズ/デシリアライズを行う、2次元データが格納可能なコレクション」を作成する、ということになると思います。

コード:
public class CompressedHashMap extends HashMap{
	private void writeObject(ObjectOutputStream s)throws IOException
	{
		s.defaultWriteObject();
		s.writeInt(size());
		
		ArrayList values = new ArrayList(size());
		for (Iterator i = entrySet().iterator(); i.hasNext(); ) {
			Map.Entry e = (Map.Entry) i.next();
			s.writeObject(e.getKey());//キー値オブジェクトの書き込み
			int index = values.indexOf(e.getValue());
			if(index == -1){
				values.add(e.getValue());
				index = values.size()-1;
			}
			s.writeInt(index);//値オブジェクトへのポインタ(リスト上の位置)を書き込み
		}
		s.writeObject(values.toArray());//値オブジェクトのリストを書き込み
	}	
}


なっちゃん
会議室デビュー日: 2004/03/19
投稿数: 7
投稿日時: 2004-03-24 13:26
なっちゃんです。
Externalizableでためしました。
データのせいかもしれませんが逆に転送するオブジェクトが大きくなってしまいました。
転送したクラスの属性はString型とBigDecimal型でnullデータの置き換え(空文字列と0)
等で大きくなったのかな???

お役に立てなくて申し訳ありませんでした。
しょむ
ぬし
会議室デビュー日: 2001/09/06
投稿数: 430
投稿日時: 2004-03-24 14:35
7Mはそもそも大きすぎるかと。

サーバ側で7MのExcelファイルを作って圧縮して送り出し、
クライアント側で伸長し、作業後、圧縮して戻して伸長、ってことと似たようなもんですよね。まぁ、テキストでもいいのですが。

根本的に、データやりとりのデザインを考慮しなおすのが一番よさそうですが…。
サーバとクライアントにデータをduplicateして持っておき、
クライアント側からのリクエストに応じてサーバ側で処理、
処理されて変更された部分のみを送受信するとか。
でくのぼう
大ベテラン
会議室デビュー日: 2003/10/06
投稿数: 162
投稿日時: 2004-03-24 15:01
個人的な興味が先行しているんですけど、、、

・シリアライズ処理にかかる純粋な時間は一体何秒(分)ですか?
・C/S間は一体何で繋がっていますか?(イントラ?The Internet?)
・その回線で7MBの転送を完了するには一体何秒(分)かかりますか?

これらの状況を吟味せずに、単に転送時間の短縮のみにフォーカスするのが
気持ち悪いなあと感じたもので、出来ましたらご回答ください。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2004-03-25 10:31
unibon です。こんにちわ。

数字にこだわりますが、たとえばフルカラー(24ビット)画像を UXGA(1600×1200)の大きさ非圧縮でも 5.5MB 程度であり、今回の 7MB はそれよりも大きい容量です。とても1画面に一度に表示できる情報量ではないです。
したがって、今現在もすでになんらかのページング処理をおこなわれているのだろうと思いますが、おそらく、たとえばクライアント側で JTable 等のスクロールなどでおこなわれているのではないかと推測します。
そのようなページングをクライアント内でおこなうのではなく、サーバーとクライアントで協調しておこなうようにしたほうが良いのではと考えます。
シュン
ぬし
会議室デビュー日: 2004/01/06
投稿数: 328
お住まい・勤務地: 東京都
投稿日時: 2004-03-25 13:22
クライアント側のレスポンスタイムを改善したいだけなら、送信側で適当な分割を行って逐次に送信し、受信側では受信次第部分ごとに描画処理に回すという手もあります。

JTableを利用した例を記述します。この例では、受信側は、一行分のデータを受信するごとに、DefaultTableModelに一行追加しています。送信側は、1セル分のデータごとに送信しています。PipeストリームでC/Sをエミュレートしています。

コード:
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.Vector;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

public class AsyncTableUpdate {

	public static void main(String args[])throws Exception{
		JFrame f = new JFrame("Test");
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		JTable t = new JTable(0,10);
		f.getContentPane().add(new JScrollPane(t));
		
		PipedOutputStream pout = new PipedOutputStream();
		PipedInputStream pin = new PipedInputStream(pout);
		final ObjectOutputStream oout = new ObjectOutputStream(pout);
		final ObjectInputStream oin = new ObjectInputStream(pin);
		
		setAsyncWrite(oout);
		setAsyncRead(t,oin);
		f.setSize(600,600);
		f.show();
	}

	public static void setAsyncWrite(final ObjectOutputStream out){
		Thread th = new Thread(){
			public void run(){
				try{
					for(int i = 0 ; i < 2000 ; i++){
						out.writeObject(String.valueOf(i+1));
						Thread.sleep(10);
					}
				}catch(Exception e){}
				finally{
					try{out.close();}catch(Exception e){}
				}
			}
		};
		th.setDaemon(true);
		th.start();
	}


	public static void setAsyncRead(final JTable table,final ObjectInputStream in){
		Thread th = new Thread(){
			public void run(){
				try{
					Vector rowdata = new Vector();
					while(true){
						rowdata.add(in.readObject());
						if(rowdata.size() == table.getColumnCount()){
							DefaultTableModel model = (DefaultTableModel)table.getModel();
							model.addRow(rowdata);
							rowdata = new Vector();
						}
					}
				}
				catch(Exception e){}
				finally{
					try{in.close();}catch(Exception e){}
				}
			}
		};
		th.setDaemon(true);
		th.start();
	}

}


なっちゃん
会議室デビュー日: 2004/03/19
投稿数: 7
投稿日時: 2004-04-06 12:05
つんきちさん、その後どうなりました?

スキルアップ/キャリアアップ(JOB@IT)