6

シンプルなクライアント/サーバーアプリがあります。サーバーは、N秒以内にデータが入らない場合にタイムアウトが発生し、ソケット接続が閉じられるように設定されています。これはSocket.setSoTimeout()を介して行います。クライアントがハングした場合、それはすべて正常に機能します。ただし、クライアントが停止した場合(たとえば、Ctrl-Cで強制終了した場合)、readLine()がタイムアウトすることはありません。

違いが生じる場合は、サーバーコードを次に示します。

public void run()
{
    PrintWriter out = null;
    BufferedReader in = null;

    try {
        sock.setSoTimeout(10000);

        out = new PrintWriter(sock.getOutputStream(), true);
        in = new BufferedReader(new InputStreamReader(sock.getInputStream()));

        String input;
        while ((input = in.readLine()) != null) {

シグナルハンドラーをクライアントに挿入してABENDメッセージをサーバーに送信しようとしましたが、機能していません(ABENDが送信される前にソケットが閉じられたと思われますが、実際に計算に時間を費やしたことはありません。それを)。

定期的にウェイクアップし、ソケットの状態をチェックして、ソケットが閉じているかどうかを確認する方法はありますか?または(さらに良いことに)ソケットが閉じた場合にreadLine()がハングしませんか?ある種のバッファなしリーダーを使用する必要がありますか?readLineのようなメカニズムをサポートするバッファなしのリーダーは存在しますか?

LinuxでJava6を使用しています。

編集:私はアイドル期間中に自分でクライアントを殺しています。この時点で、すべてのデータが送受信されています。クライアントプログラムが実行されていないことを(ps経由で)確認しました。Javaプロセスは実際に強制終了されました。netstatを使用すると、ソケットが両端で閉じられていることがわかりますが、readLine()はまだハングしています。

4

3 に答える 3

1

あなたは問題を誤診したと思います。

ソケットの入力側が閉じている場合、readLine()呼び出しはその閉じを確認する必要があります。バッファリングされたすべてのデータが消費された後、呼び出しはを返す必要がありnullます。(ソケットが正常に閉じられている場合はIOExceptionは発生しませんが、接続がタイムアウトした場合はIOExceptionが発生する可能性があります...など)。

最も明白な説明は、ソケットがまだ閉じられていないということです。もう一方の端がソケットを閉じる状況を見て、これがまだ発生していない理由を理解してください。


これらのどれも解決策ではありませんが、完全を期すために答えます。

定期的にウェイクアップし、ソケットの状態をチェックして、ソケットが閉じているかどうかを確認する方法はありますか?

別のスレッドがそれを行うことができますが、これはできません。

または(さらに良いことに)ソケットが閉じた場合にreadLine()がハングしませんか?

それが起こるはずです。

ある種のバッファなしリーダーを使用する必要がありますか?

それは役に立たないでしょう。readLine()自分で実装する必要があり、同じ時点でコードがブロックされます。ブロッキング動作は、リーダーチェーンのバッファリング層と文字デコード層の下で発生しています。

readLineのようなメカニズムをサポートするバッファなしのリーダーは存在しますか?

いいえ、そうではありません。上記を参照。

于 2013-02-07T14:23:09.813 に答える
1

そこにない問題を追いかけるのに何時間も費やすとき、あなたはそれを嫌いではありませんか?Stephen CIにSSCCEを提供しようとしたところ、機能しているため、そのような例を提供できなかったことがわかりまし。私のデバッグコードは問題を引き起こしていました...

記録のために、ここに動作するコードがあります(他の誰かが同様の問題を抱えている場合に備えて):

sscceServer.java

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;


public class sscceServer
{
    public static class EchoHandlerThread implements Runnable
    {
        private final Socket sock;
        private final int id;

        public EchoHandlerThread(Socket s, int i)
        {
            sock = s;
            id = i;
        }

        public void run()
        {
            try {
                //----- set socket read timeout to 10 seconds -----
                sock.setSoTimeout(10000);

                PrintWriter out = new PrintWriter(sock.getOutputStream(), true);
                BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream()));

                String input;
                while ((input = in.readLine()) != null) {
                    System.out.println("[" + id + "] <" + input + ">");
                }

                out.close();
                in.close();
                sock.close();

                System.out.println("\tConnection #" + id + " closed");
            }
            catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        }
    }

    public static class Listener
    {
        private final InetAddress bindip;
        private final int portnum;

        public Listener(String ipstr, int pn)
        {
            try {
                bindip = InetAddress.getByName(ipstr);
                portnum = pn;
            }
            catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        }

        public void start()
        {
            try {
                ServerSocket srvsock = new ServerSocket(portnum, 0, bindip);
                System.out.println("Listening on " + bindip.getHostAddress() + ":" + portnum);

                int connum = 0;
                while (true) {
                    Socket sock = srvsock.accept();

                    connum++;
                    InetAddress ipaddr = sock.getInetAddress();
                    System.out.println("Connection #" + connum + " from: " + ipaddr.getHostAddress());

                    new Thread(new EchoHandlerThread(sock, connum)).start();
                }
            }
            catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        }
    }


    public static void main(String[] args)
    {
        Listener lsnr = new Listener("localhost", 8988);
        lsnr.start();
    }
}

sscceClient.java

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public final class sscceClient
{
    public static void main(String[] args)
    {
        try {
            Socket sock = new Socket("localhost", 8909);

            PrintWriter out = new PrintWriter(sock.getOutputStream(), true);
            BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream()));

            out.println("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
            out.println("Ut sem ante, mollis ut porttitor at, aliquet vel nulla.");
            out.println("Suspendisse quis sapien ante, a cursus nunc.");

            //---- sleep for 20 seconds -----
            Thread.sleep(20000);

            out.close();
            in.close();
            sock.close();
        }
        catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
}

助けてくれてありがとう!

于 2013-02-07T18:33:22.187 に答える
0

Javadocによると、readLine()メソッドはIOExceptionをスローします。また、IOExceptionのJavadocによると、例外は割り込みでスローされると予想されます。コードを書かなくても、キャッチすることでストリームが途中で終了する場合に対処できると思いますIOException

于 2013-02-07T14:21:45.630 に答える