• ベストアンサー

Cliant から Server の Socket 管理

サーバアプリを作成しています。 ServerSocket を生成してから 基本的に read() でクライアントからの データを待機しています。 その状態でクライアント側から close 処理を行いたいのですが どういう形にすれば正しく終了できるのでしょうか? クライアントから Socket の close() を行うと 空のデータが2回送られてきます。 例外が発生しているので finally で close させようと 思ったのですがビルドエラーになります。 どうかご教授お願いします。

  • Java
  • 回答数2
  • ありがとう数3

質問者が選んだベストアンサー

  • ベストアンサー
  • _ranco_
  • ベストアンサー率58% (126/214)
回答No.2

ご質問のシナリオでは、サーバがread()ブロックしている間にクライアントがSocketをクローズするわけですから、そのときサーバのread()は(どんな入力オブジェクトからのreadかによって)、-1を返したり例外(多くの場合EOFException)を投げます。 closeは相手に対する出力操作なので、 > 空のデータが2回送られてきます。 この場合はTCPのFINとACKを送信します。 >「処理されない例外の型 IOException」と表示されてしまいます。 これは、あなたのコードには自分のSocketのclose()に対するtry/catchが書かれていないからです。 というわけで、現状では-1ではなく例外がクライアントソケットクローズのサインなので、その例外処理の中でサーバの対応を行います。

Zepetto
質問者

お礼

非常に丁寧な回答ありがとうございます。 ようやく分かりました! ありがとうございました!

その他の回答 (1)

  • _ranco_
  • ベストアンサー率58% (126/214)
回答No.1

> 空のデータが2回送られてきます。 たぶん、送信バッファのフラッシュです。 > 例外が発生しているので finally で close させようと 通常は、例外処理の中でサーバのソケット(Socket)をcloseします。

Zepetto
質問者

お礼

>> 空のデータが2回送られてきます。 > たぶん、送信バッファのフラッシュです。 これはクライアントで Socket を閉じたためでしょうか? 必ず2回送られるものなんでしょうか? >> 例外が発生しているので finally で close させようと > 通常は、例外処理の中でサーバのソケット(Socket)をcloseします。 例外処理の中でサーバのソケットをクローズしようとコードを書いても 「処理されない例外の型 IOException」と表示されてしまいます。 例外処理で Socket を閉じるという考え方が 正しい方向と思っていいんでしょうか?

関連するQ&A

  • Socket プログラミングについて

    先日の質問ではありがとうございました。 今回はソースコードについてですが もしよろしければアドバイスお願いします。 Socket 制御を行うアプリを作成しています。 ・クライアントアプリ ・サーバアプリ の2つから構成していまして同PC上で動作させます。 クライアントから localhost 経由でサーバアプリに接続。 サーバアプリは ServerSocket を生成して accept しています。 サーバアプリで accept により Socket を生成すると その Socket を Thread に引き渡して適宜処理を行います。 その後、 再び別クライアントからの接続を待つために サーバアプリで accept したいのですが そのまま accept を呼び出しても そこで待機せずに新しい Socket を生成しています。 別クライアントからの接続を待機するにはどうしたらいいのでしょうか? ご教授お願いします。

    • ベストアンサー
    • Java
  • Socketの使用方法について

    Socketの使用方法について サーバ側クラスA クライアント側クラスB とあり、Aは常駐しておりBから接続が合った場合に処理を行い、 処理後には待機状態に再び戻ります。 上記の場合に Aのクラスは以下のように作成しましたが、★の部分でCloseではなく、このままこのソケットを使用して待機したいです。 (ほぼ同時刻に複数のアクセスがあるため、資源の事を考えて使いまわしたいです。) どのような手段があるのかご指導お願い致します。 又、そもそもソケットに関しての理解が足りないとも思いますので、参考サイトを教えていただけると幸いです。 クラスA ServerSocket svsock = new ServerSocket(port); while (true) { Socket socket = svsock.accept(); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); BufferedWriter out = new BufferedWriter(new PrintWriter(socket.getOutputStream(), true)); // 処理結果を受信 String line; if ((line = in.readLine()) != null) { System.out.println("受け取ったメッセージ : " + line); out.write("サーバで表示。"); out.newLine(); out.flush(); } socket.close(); // ★ }

    • ベストアンサー
    • Java
  • Socket + XML

    ・クライアントはサーバへXML形式のクエリを送信し、 ・サーバからXML形式のデータを受け取る という単純なプログラムを実装しています。 しかしサーバ側の、InputStreamを引数とするXMLパースメソッドでwaitしてしまって困っています。 かといって、クライアント側のOutputStreamを閉じると、クライアントのソケット自体も閉じてしまいます。 なるべく一度のコネクションで送受信を終了させたいのですが、よい方法はないでしょうか? 一応、BufferedReaderを利用してXML文章を文字列に落としてから StringReaderをbuilder.parseの引数に与えることで解決出来てはいるのですがスマートではない気がしまして。 [Server側]  ServerSocket server_sock = new ServerSocket(12345);  Socket sock = server_sock.accept();  /* XMLパーサビルダ生成 */  DocumentBuilderFactory fact = DocumentBuilderFactory.newInstance();  DocumentBuilder builder = fact.newDocumentBuilder();  /* ドキュメント docIn の解析 */  Document docIn = builder.parse(sock.getInputStream());//ここから動かない(clientがoutputを終了するまで待っている?)  (略)  /* 結果ドキュメント docOut の構築*/  Document docOut = builder.newDocument();  (略)  /* docOut 送信 */  TransformerFactory tfactory = TransformerFactory.newInstance();  Transformer transformer = tfactory.newTransformer();  transformer.transform(new DOMSource(docOut), new StreamResult(sock.getOutputStream()));  sock.getInputStream().close();  sock.getOutputStream().close();  sock.close(); [Client側]  Socket sock = new Socket("localhost", 12345);  /* XMLパーサビルダ生成 */  DocumentBuilderFactory fact = DocumentBuilderFactory.newInstance();  DocumentBuilder builder = fact.newDocumentBuilder();  /* クエリドキュメント docOut の構築*/  Document docOut = builder.newDocument();  (略)  /* docOut 送信 */  TransformerFactory tfactory = TransformerFactory.newInstance();  Transformer transformer = tfactory.newTransformer();  transformer.transform(new DOMSource(docOut), new StreamResult(sock.getOutputStream()));  sock.getOutputStream().flush();  //sock.getOutputSream().close();//これにすると、socketが閉じてしまう  /* 結果ドキュメント docIn の解析 */  Document docIn = builder.parse(sock.getInputStream());//サーバから結果が送信されないので、クライアントはここで停止  (略)

    • ベストアンサー
    • Java
  • SocketのSend関数でのCLOSEの検知 [Linux]

    Linux環境でSocket(dm:PF_INET,type:SOCK_STREAM)を使用しての、 Client&ServerプログラムをCで作成しているのですが、 そこでのSend関数の使い方についてご助力ください。 Client&Serverプログラムは下記のような動きをします。 [Client] ServerへConnectした後、複数のDataを数秒間隔でServerへ 送信(send関数使用)します。受信(recvやread関数等)は、 一切行いません。 [Server] ClientからのConnectを受け付けた後、Clientから受信(recv関数 使用)したDataを標準出力へ表示する。送信(sendやwrite関数 等)は、一切行いません。 さて、ここでもしClientプログラムがCloseを発行したり、マシン DOWN等の理由でConnectionが切断され、Server側のSocketが CLOSE_WAIT状態になった場合、Bufferに溜まっていたDataを すべて受けきった後、recv関数が0を返してくれるので 相手が終了したことがわかります。 ここからが質問のMainです。 では、もしServerプログラムがCloseを発行したり、マシン DOWN等の理由でConnectionが切断され、Client側のSocketが CLOSE_WAIT状態になっても、CLOSE_WAIT直後のsend関数が なぜか正常に処理されてしまいます。無論このDataは、 Server側は受け取りません。この次のsend関数実行時に EPIPEが返ってくるので、ここでようやくSocketが切断された ことが判ります。 これを何とかCLOSE_WAIT状態になった直後から、send関数で 切断を検知できるようにできないでしょうか。 よろしくお願いします。 以上

  • 自宅に固定IPを取得したサーバーがあります。(ubuntu serve

    自宅に固定IPを取得したサーバーがあります。(ubuntu server) そこには、以下のようなプログラムが動いています。(言語はここでは重要でないので特定しません) listen(ポート番号); try { socket=accept(); for { buf=socket.read(); socket.write(buf); } } finally { socket.close(); } ふつうのエコーをおこなう機能と思ってください。 これをバックグラウンドで動作させると、最初のうちは正しくクライアントのほうに 打った文字が表示されるのですが、あるときからサーバーからクライアントに writeしているのに、クライアントはそれを受け取らなくなり、表示されません。 例外なども発生していないので、コネクションは張られていると思います。 このとき、以下のようなことを考えていますが、これ以上どうやって調べていいのかわかりません。 ・サーバー側のルータのハード的故障 ・サーバのハード的故障 ・クライアントのハード的故障 ・ルータのタイムアウト ・サーバーのタイムアウト ・クライアントのタイムアウト もしかしたら違う原因も考えられるかもしれませんが。。 このような場合、どのようにして問題を解決すればいいのでしょうか? また、linuxのコマンドで調べる方法などありましたら、教えてください。

  • socketでのバイナリファイルの扱い方

    javaのsocketを用いてファイルの送信サーバ、受信クライアントを作成しているのですが テストプログラムとしてスレッド化せずに送信・受信部のみ作りました。 症状はバイナリデータの転送がうまくできないことです。ソースを抜粋すると サーバ側で BufferedOutputStream out = new BufferedOutputStream(socket.getOutputStream());//socketはSocketクラス BufferedInputStream in1 = new BufferedInputStream( new FileInputStream("test1.bmp")); BufferedInputStream in2 = new BufferedInputStream( new FileInputStream("test2.bmp")); while( (c = in1.read() ) != -1 ){   out.write(c); } while( (c = in2.read() ) != -1 ){   out.write(c); } クライアント側で BufferedOutputStream out1 = new BufferedOutputStream( new FileOutputStream("test1.out.bmp") ); BufferedOutputStream out2 = new BufferedOutputStream( new FileOutputStream("test2.out.bmp") ); BufferedInputStream in = new BufferedInputStream( s.getInputStream() ); while( ( c=in.read() ) != -1 ){   out1.write(c); } while( ( c=in.read() ) != -1 ){   out2.write(c); } とやっています。 クライアント側で1回目のin.readを抜けるときにはサーバ側は既に2回のwriteを終わっているようで ファイルはtest1.out.bmpにマージされていました。 サーバ側の1回目のwriteのオブジェクトがcloseしていないことが原因だと思い1回目のwriteが終わった時点でout.close()とした のですがそうやるとsocketも閉じてしまいsocket closeのエラーが生じてしまいました。 このようにならず1本のコネクションでバイナリのデータを複数送信する方法をご存知でしたら教えてください。 [環境] win2ksp1a,j2sdk1.4.1_03,java経験4ヶ月程度

  • NetworkStreamからのRead()で、処理が止まる(C#)

    C#で、サーバーを作っています。 Readで読み込んで、次に、 Writeで、「ありがとうございました!!」など、 書き出しているのですが、 いままで、それなりに動いたいました。 しかし、クライアント側で、何も書き出さないと、 Read()の部分で、プログラム止まって(待機して) しまっていることが分かりました。 クライアントが、何も書き出さないときは、 さっさと、「ありがとう・・」と書き出して、 終了したいのですが、30秒ほど待機して、 接続が切れてしまうようです(Writeもしない)。 Readは終端-1がくるまで、待機してしまうの だと思います(文字が送られないときは、これが ないので、待機してしまうのかな)。 例えば、送られてくるデータが、もともと無い、 ということを、あらかじめ認識し、 または、5秒くらいで、データが来なければ、 処理を次に移す、といった処理の仕方は、 できないでしょうか。 お願いします。

  • JAVAのソケット通信の接続数について

    JAVAのソケット通信の接続数について ServerSocket server= new ServerSocket( port ); server.setSoTimeout( 4000 ); Socket socket = server.accept();//クライアントからの接続をまつ 以上のコードを使っていますが、クライアントからの接続数を調べる方法はないでしょうか?

    • ベストアンサー
    • Java
  • Socket通信で、通信終了のイベントが発生しない

    クライアント(Windows)とサーバ(Unix)とSocket通信をするアプリを作っています。処理内容はクライアントのデータファイルをサーバに送信(アップデイト)し、サーバ側でデータを解析し、その結果を印刷するという手順です。 WinSockを使って、送信そのものはうまくいくのですが、サーバでデータを解析し結果を印刷するのに時間がかかり(10秒以上)、その間は送信終了のイベントが発生しません。これはサーバ側での処理を exec関数とwait関数で行っているので、正しい事態なのですが、データの送信が終わったら後はサーバ側で勝手にやって欲しいのです。サーバでの処理を system関数に置換えたり、バックグランド処理にしてもやはり処理が終わるまで送信終了のイベントが発生しません。何かいい方法をお教えください。

  • サーバ/クライアントプログラム

    クライアント側で dos.writeInt( 20 );で 20を書き込み  サーバ側は期待どうり表示されますが クライアント側で さっき書いた20を 読み込んでるはずなんですが int recv = dis.readInt(); System.out.println( "書き込みデータ " + recv ); の部分が無視されるんですが なぜさっき書いた20が 読み込めないんでしょうか? 解説をお願いします //サーバプログラム import java.net.*; import java.io.*; class a{ public static void main( String args[] ) { System.out.println( "Ready!" ); try { ServerSocket ss = new ServerSocket( 5000 ); while( true ) { Socket so = ss.accept(); InputStream i = so.getInputStream(); OutputStream os = so.getOutputStream(); DataInputStream dis = new DataInputStream( i ); DataOutputStream dos = new DataOutputStream( os); int recv = dis.readInt(); System.out.println( "受信データ " + recv ); dis.close(); dos.close(); i.close(); os.close(); } }catch ( Exception e ) { } } } //クライアントプログラム import java.net.*; import java.io.*; class b{ public static void main( String args[] ) { try { Socket so = new Socket( "localhost", 5000 ); InputStream i = so.getInputStream(); OutputStream os = so.getOutputStream(); DataInputStream dis = new DataInputStream( i ); DataOutputStream dos = new DataOutputStream( os ); dos.writeInt( 20 ); int recv = dis.readInt(); System.out.println( "書き込みデータ " + recv ); dis.close(); dos.close(); i.close(); os.close(); }catch( Exception e ) { } } }

専門家に質問してみよう