- PR -

ソケット通信について

1
投稿者投稿内容
もの
会議室デビュー日: 2005/11/09
投稿数: 8
投稿日時: 2005-11-09 01:58
お世話になっております。

ソケット通信を勉強しているのですが、なかなかうまくいきません。
16個のファイルの送信を行うと、2回に1回、エラーが出てしまう感じです。

送信側のソケット関係を疑い、やけくそになってclose()の処理をしてみましたが
改善されませんでした。

何かヒントをいただけると幸いです。

デバッグ出力:-----------------------------------------------------
default.aviファイル送信開始
default.aviのファイルをストリームに書き出しました。
default.aviファイル送信開始
java.net.SocketException: Connection reset by peer: socket write error
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(Unknown Source)
at java.net.SocketOutputStream.write(Unknown Source)
at MySendListener.actionPerformed(myListener.java:196)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
Source)
以下省略



長くて申し訳ありませんが、ソースを付属いたします。

送信側:-----------------------------------------------------

public void actionPerformed(ActionEvent e){

for (int k=0;k< tx.file.length ;k++){

System.out.println(tx.file[k].getName()+"ファイル送信開始");

try{

socket = new Socket("localhost",20000);
out = socket.getOutputStream();

fin = new FileInputStream(tx.file[k]);
stack = new ByteArrayOutputStream();

byte b[] = new byte[255];
int len = -1;

while((len=fin.read(b,0,b.length))!=-1){

stack.write(b,0,len);

}

stack.flush();

byte buf2[] = stack.toByteArray();
out.write(buf2, 0, buf2.length);

out.flush();
out.close();

fin.close();
stack.close();
socket.close();

System.out.println(tx.file[k].getName()+"のファイルをストリームに書き出しました。");


}catch(Exception fe){

fe.printStackTrace();

}finally{

try{

fin=null;
out=null;
out=null;
stack = null;
socket=null;

if(fin != null){fin.close();System.out.println("finが閉じていませんでした");}
if(out != null){out.close();System.out.println("outが閉じていませんでした");}
if(stack != null){stack.close();System.out.println("stackが閉じていませんでした");}
if(socket != null){ socket.close();System.out.println("socketが閉じていませんでした");}

}catch(Exception fe){

fe.printStackTrace();

}

}


}

}

受信側:-----------------------------------------------------
public static void main(String[] args) {

recive rc = new recive();

for(int i=0;i<16;i++){

try{

serversocket = new ServerSocket(20000);

System.out.println("リクエスト待ち");
socket = serversocket.accept();

System.out.println("リクエストがありました");
in = socket.getInputStream();

fout = new FileOutputStream("D://test"+i+".avi");

stack = new ByteArrayOutputStream();

byte b[] = new byte[255];

int len = -1;

while((len= in.read(b,0,b.length))!=-1){

stack.write(b,0,len);

}
stack.flush();
byte buf2[] = stack.toByteArray();

fout.write(buf2, 0, buf2.length);
fout.flush();
fout.close();
stack.close();

socket.close();
serversocket.close();

System.out.println("ストリームをファイルに書き出しました。");

fout.close();

}catch(Exception e){

e.printStackTrace();

}finally{

try{

in=null;
fout=null;
stack=null;
socket=null;
serversocket=null;

if(in != null){fout.close();System.out.println("foutが閉じていませんでした");}
if(fout != null){fout.close();System.out.println("foutが閉じていませんでした");}
if(stack != null){stack.close();System.out.println("stacktが閉じていませんでした");}
if(socket != null){socket.close();System.out.println("socketが閉じていませんでした");}
if(serversocket != null){ serversocket.close();System.out.println("serversocketが閉じていませんでした");}

}catch(Exception fe){

fe.printStackTrace();

}


}

}
}


ByteArrayに読み込む部分などはまるまる
こちらを参考にさせていただきました。
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=18864&forum=12
K
大ベテラン
会議室デビュー日: 2004/04/07
投稿数: 174
投稿日時: 2005-11-09 02:21
パッとみただけでもかなりツッコミどころ満載なので、まずはもっとシンプルなサンプルコードを参照してみたほうがいいでしょう。

ちょっと検索してみたら以下のようなサイトがありました。
http://ysserve.int-univ.com/sugsi/Lecture/java/L5/05-03-02.html

クライアント側はわざわざ一度ByteArrayOutputStreamに書き出していますが、何故直接
SocketのOutputStreamに書き出さないのでしょう?
コブラ
ぬし
会議室デビュー日: 2003/07/18
投稿数: 1038
お住まい・勤務地: 神奈川
投稿日時: 2005-11-09 02:38
> stack.write(b,0,len);

これは、送信用ソケットに書かんとスタックに書くもんなんかね!?
よう知らんのですが(笑)
もの
会議室デビュー日: 2005/11/09
投稿数: 8
投稿日時: 2005-11-09 03:02
引用:

ちょっと検索してみたら以下のようなサイトがありました。
http://ysserve.int-univ.com/sugsi/Lecture/java/L5/05-03-02.html

クライアント側はわざわざ一度ByteArrayOutputStreamに書き出していますが、何故直接
SocketのOutputStreamに書き出さないのでしょう?



mogeさん、早速の返信ありがとうございます。
実は最初は、下記のようなもっとシンプルなコードで書き出しを行ってみたのです。

この場合、見た目上ファイルの転送ができ、クライアントとサーバーで
ファイルサイズも一致していたのですが、実際にファイルを開くと、
破損ファイルになっていて読めなかったのです。

OutputStreamについて勉強不足で申し訳ないのですが、書き出しの際に
余計なバイトデータが含まれて(そんなことないか・・・)破損が
起きたのかな?と考え、過去ログを参考に一度ByteArrayに蓄積をしてみたということです。

ご提示いただいた先を参考に、もう一度作成してみようと思います。

最初のクライアント:

try{

FileInputStream fi = new FileInputStream(rm1.filename);

Socket so = new Socket(HOST,PORT);
OutputStreamWriter os = new OutputStreamWriter(so.getOutputStream());
//DataOutputStream os = new DataOutputStream(new BufferedOutputStream((so.getOutputStream())));

int i;
while((i = fi.read())!=-1){

os.write(i);
}

os.close();
fi.close();
so.close();

}catch(Exception se){

rm1.lb2.setText("サーバー側が開始されていません");
se.printStackTrace();

}

最初のサーバ:

try{

int i;

FileOutputStream fos = new FileOutputStream(ss2.filename);
ServerSocket server = new ServerSocket(PORT);

//while (true){

Socket ss = server.accept();
InputStreamReader in = new InputStreamReader(ss.getInputStream());
//DataInputStream in = new DataInputStream(new BufferedInputStream((ss.getInputStream())));

while((i = in.read())!=-1){

fos.write(i);
}
//}

fos.close();
in.close();
ss.close();
server.close();


}catch(Exception e){

System.out.println("サーバーを終了します");
ss2.lb2.setText("有効なファイル名を指定してください");

e.printStackTrace();

}
K
大ベテラン
会議室デビュー日: 2004/04/07
投稿数: 174
投稿日時: 2005-11-09 03:10
最初のコードのほうがはるかに正解に近そうですね。
転送しようとしているファイルはバイナリファイルですか?
そうであれば書き出し時にOutputStreamWriterをかませているのが原因ではないでしょうか?
Writer系はテキストファイル専用なので素直にそのままOutputStreamを使えば問題ないと思いますがどうでしょう?
もの
会議室デビュー日: 2005/11/09
投稿数: 8
投稿日時: 2005-11-09 04:11
引用:

mogeさんの書き込み (2005-11-09 03:10) より:
最初のコードのほうがはるかに正解に近そうですね。
転送しようとしているファイルはバイナリファイルですか?
そうであれば書き出し時にOutputStreamWriterをかませているのが原因ではないでしょうか?
Writer系はテキストファイル専用なので素直にそのままOutputStreamを使えば問題ないと思いますがどうでしょう?



moge様、ご指摘の通り、OutputStreamとInputStreamをそのまま使ったら転送に成功しました!

//送信側(改善後)
OutputStream os = so.getOutputStream();
//受信側(改善後)
InputStream in = ss.getInputStream();

OutputStreamは抽象クラス、抽象クラスは上記のように参照せずに他のクラスで
必ずラップ(?)すると思い込んで、Writer系のクラスをうっかり使ってしまいました。
本当にありがとうございます。

あと、関連した質問なのですが、クライアント側のファイル名と拡張子をサーバー側
に渡したいと思い、FileクラスをシリアライズしてObjectOutputStreamでサーバーに
渡すという方法をとってみたのですが、他にも簡便な方法はありますでしょうか?
初歩的な質問ばかりですみません。


[ メッセージ編集済み 編集者: もの 編集日時 2005-11-09 04:30 ]
スフレ
ぬし
会議室デビュー日: 2005/05/27
投稿数: 281
お住まい・勤務地: 東京
投稿日時: 2005-11-09 09:51
Fileのインスタンスを送るのは簡単ですが「やりすぎ」って気がしますね。どうせ送るならStringインスタンスでじゅうぶんではないでしょうか。

自分だったら、Javaに依存するのも嫌なので、

  • 先頭4オクテットはファイル名のバイト数
  • 次はUTF-8でエンコードしたファイル名
  • 8オクテットでファイルの長さ
  • ファイルの内容

などのようにフォーマットを決めて、それを送受信するようにします。
1

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