0

BufferedReaderを使用してソケットから読み取る場合 、readLine()メソッドが返すことを示します

行終了文字を含まない、行の内容を含む文字列、またはストリームの末尾に到達した場合は null

ストリームの終わりに達したことをどのように知るのでしょうか? これを決定するために使用する文字のシーケンス。

PipedStreams を使用する別の接続を適切に閉じるために、同じ文字シーケンスの送信をシミュレートしたいと考えています。


編集: これが問題のコードです。応答から、そのようなシーケンスはないように見え、PipedOutput ストリームで close() を呼び出すと、出力ストリームで readLine() のブロックが解除されるはずです。現時点ではこれを行っているようには見えないため、混乱したので、どこか別のバグである可能性があると考えています。

何が起こっているかというと、incomingEventIn.close()がブロックしているときに回線がブロックされているように見えるということinputLine = incomingEventIn.readLine()です。inputLine = incomingEventIn.readLine()他のスレッドで実行されていない場合は、正常に実行されincomingEventIn.close()ます。なぜこうなった?

public class SocketManager {

    private Socket socket = null;
    private PrintWriter out = null;
    private BufferedReader in = null;

    private PipedOutputStream incomingEventOutStream = null;
    private PrintWriter incomingEventOut = null;
    private BufferedReader incomingEventIn = null;
    private PipedOutputStream incomingResponsOutStream = null;
    private PrintWriter incomingResponseOut = null;
    private BufferedReader incomingResponseIn = null;

    private ArrayList<AsteriskLiveComsEventListener> listeners = new ArrayList<AsteriskLiveComsEventListener>();
    private final ExecutorService eventsDispatcherExecutor;

    private String ip;
    private int port;

    private Object socketLock = new Object();

    public SocketManager(String ip, int port) {
        this.ip = ip;
        this.port = port;
        eventsDispatcherExecutor = Executors.newSingleThreadExecutor();
    }

    public void connect() throws UnableToConnectException, AlreadyConnectedException {
        synchronized(socketLock) {
            if (socket != null && !socket.isClosed()) {
                throw (new AlreadyConnectedException());
            }
            try {
                socket = new Socket(ip, port);
                out = new PrintWriter(socket.getOutputStream(), true);
                in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

                incomingEventOutStream = new PipedOutputStream();
                incomingEventIn = new BufferedReader(new InputStreamReader(new PipedInputStream(incomingEventOutStream)));
                incomingEventOut = new PrintWriter(incomingEventOutStream);

                incomingResponsOutStream = new PipedOutputStream();
                incomingResponseIn = new BufferedReader(new InputStreamReader(new PipedInputStream(incomingResponsOutStream)));
                incomingResponseOut = new PrintWriter(incomingResponsOutStream);

            } catch (IOException e) {
                throw (new UnableToConnectException());
            }
            new Thread(new IncomingEventThread()).start();
            new Thread(new SocketThread()).start();
        }
    }

    public void disconnect() throws NotConnectedException {
        disconnect(false);
    }

    private void disconnect(boolean notRequested) throws NotConnectedException {
        synchronized(socketLock) {
            if (!isConnected()) {
                throw (new NotConnectedException());
            }

            try {
                incomingEventIn.close();
            } catch (IOException e2) {}
            // IT NEVER GETS TO HERE!
            incomingEventOut.close();
            try {
                incomingResponseIn.close();
            } catch (IOException e1) {}
            System.out.println("disconnecting");
            incomingResponseOut.close();
            try {
                socket.shutdownInput();
            } catch (IOException e) {}
            try {
                socket.shutdownOutput();
            } catch (IOException e) {}
            try {
                socket.close();
            } catch (IOException e) {}

            if (notRequested) {

                System.out.println("disconnecting event");
                dispatchEvent(new ConnectionLostEvent());
            }
        }
    }

    public boolean isConnected() {
        synchronized(socketLock) {
            return (socket != null && !socket.isClosed());
        }
    }

    public void addEventListener(AsteriskLiveComsEventListener a) {
        synchronized(listeners) {
            listeners.add(a);
        }
    }

    public void removeEventListener(AsteriskLiveComsEventListener a) {
        synchronized(listeners) {
            listeners.remove(a);
        }
    }

    private void dispatchEvent(final AsteriskLiveComsEvent e) {
        synchronized (listeners) {
            synchronized (eventsDispatcherExecutor) {
                eventsDispatcherExecutor.execute(new Runnable()
                {
                    public void run()
                    {
                        for(int i=0; i<listeners.size(); i++) {
                            listeners.get(i).onAsteriskLiveComsEvent(e);
                        }
                    }
                });
            }
        }
    }

    public JSONObject sendRequest(JSONObject request) throws JSONException, NotConnectedException {
        synchronized(socketLock) {
            System.out.println("sending request "+request.toString());
            out.println(request.toString());
            try {
                return new JSONObject(incomingResponseIn.readLine());
            } catch (IOException e) {
                // lets close the connection
                try {
                    disconnect(true);
                } catch (NotConnectedException e1) {}
                throw(new NotConnectedException());
            }
        }
    }

private class SocketThread implements Runnable {

    @Override
    public void run() {
        String inputLine = null;
        try {
            while((inputLine = in.readLine()) != null) {
                // determine if this is a response or event and send to necessary location
                JSONObject lineJSON = new JSONObject(inputLine);
                if (lineJSON.getString("type").equals("response")) {
                    incomingResponseOut.println(inputLine);
                    incomingResponseOut.flush();
                }
                else if (lineJSON.getString("type").equals("event")) {
                    incomingEventOut.println(inputLine);
                    incomingEventOut.flush();
                }
            }

            if (isConnected()) {
                try {
                    disconnect(true);
                } catch (NotConnectedException e) {}
            }
        } catch (IOException e) {
            // try and disconnect (if not already disconnected) and end thread
            if (isConnected()) {
                try {
                    disconnect(true);
                } catch (NotConnectedException e1) {}
            }
        }
    }

}

private class IncomingEventThread implements Runnable {

    @Override
    public void run() {
        String inputLine = null;
        try {
            while((inputLine = incomingEventIn.readLine()) != null) {
                JSONObject lineJSON = new JSONObject(inputLine);
                String eventType = lineJSON.getString("eventType");
                // determine what type of event it is and then fire one that represents it
                if (eventType.equals("channelAdded")) {
                    JSONObject a = lineJSON.getJSONObject("payload");
                    Hashtable<String,Object> data = new Hashtable<String,Object>();
                    Object[] keys = a.keySet().toArray();
                    for(int i=0; i<keys.length; i++) {
                        data.put((String) keys[i], a.get((String) keys[i]));
                    }
                    dispatchEvent(new ChannelAddedEvent(data));
                }
                else if (eventType.equals("channelRemoved")) {
                    dispatchEvent(new ChannelRemovedEvent(lineJSON.getJSONObject("payload").getInt("channelId")));
                }
                else if (eventType.equals("channelsToRoom")) {
                    ArrayList<Integer> data = new ArrayList<Integer>();
                    JSONObject a = lineJSON.getJSONObject("payload");
                    JSONArray ids = a.getJSONArray("channelIds");
                    for(int i=0; i<ids.length(); i++) {
                        data.add(ids.getInt(i));
                    }
                    dispatchEvent(new ChannelsToRoomEvent(data));
                }
                else if (eventType.equals("channelToHolding")) {
                    dispatchEvent(new ChannelToHoldingEvent(lineJSON.getJSONObject("payload").getInt("channelId")));
                }
                else if (eventType.equals("channelVerified")) {
                    dispatchEvent(new ChannelVerifiedEvent(lineJSON.getJSONObject("payload").getInt("channelId")));
                }
                else if (eventType.equals("serverResetting")) {
                    dispatchEvent(new ServerResettingEvent());
                }
            }
        } catch (IOException e) {}
        System.out.println("here");
    }

}

編集 2:inputLine = incomingEventIn.readLine()デバッガーの前にいくつかのブレークポイントを配置すると、正常に実行されてnull が返さ れるため、どこかでデッドロックの問題だと思います。普通に動かそうとすると固まる。

編集 3:グレイの回答のおかげで解決しました。ロックアップの原因となった出力の前に、入力ストリームが閉じられています。それは逆である必要があります。最初に出力ストリームを閉じると、ストリームが閉じられ、readLine()メソッドのブロックが解除されたことが入力ストリームに通知されます。

4

4 に答える 4

3

ストリームの終わりに達したことをどのように知るのでしょうか? これを決定するために使用する文字のシーケンス。

これに対する答えは OS に依存しますが、私がよく知っている OS では、EOF 文字は読み取られません。OS は、基になる呼び出し元に、ストリーム (ファイル記述子) が EOF に達したことを示す戻り値を返します。JVM は戻り値を確認し、メソッドに応じて、または呼び出し元に適切な戻り値 ( null-1、...) を返します。InputStreamReader

PipedStreams を使用する別の接続を適切に閉じるために、同じ文字シーケンスの送信をシミュレートしたいと考えています。

から読み取っている場合はPipedReader、関連する を閉じますPipedWriterReaderorはInputStream、適切な EOF 値を呼び出し元に返します。

編集:

あなたIncomingEventThreadはから読んでいるのでincomingEventIndisconnect()メソッドはincomingEventOut最初のものを閉じる必要があります。スレッドは内側自体を閉じる必要があります。次に、応答を閉じる必要があります。

スレッド callはありませんdisconnect(...)。すべてのストリームではなく、リーダーとライターのみを閉じる必要があります。

于 2013-07-22T21:49:08.840 に答える
2

1つもありません。OS は、ソースに応じて、ファイル サイズ、TCP FIN ビット、またはその他の帯域外メカニズムを介して、ストリームがいつ終了するかを認識します。私が知っている唯一の例外は、キーボードで入力すると、ターミナルドライバーが Ctrl/d または Ctrl/z を EOF として認識することですが、これも OS であり、Java ストリームやリーダーではありません。

于 2013-07-22T22:04:00.590 に答える
2

この質問をチェックしてください: filestream のファイルの終わりの文字は何ですか?

于 2013-07-22T21:45:38.493 に答える