2

適切にフラッシュすることを拒否するjava.net.SocketOutputStreamに不満を感じています!当たり前のことを見落としているに違いない。以下のGroovyスクリプトでは、Galaxy Nexus Android 4.0.2電話で実行されている単純なソケットサーバーに接続しようとしていますが、5秒のタイムアウトが経過した直後にソケットクローズ例外が発生します。

SocketClient.groovy

import java.net.*
socket = new Socket()
socket.connect(new InetSocketAddress(InetAddress.getByAddress([172,17,57,21] as byte[]), 58789), 5000)
println "Connected!"
socket.withStreams { input, output ->
    println "Processing ${input.class.name} and ${output.class.name} streams..."
    output.withWriter {
        it << 'echo testing\n\n'; 
        it.flush();
        output.flush()
        def readerThread = Thread.start {
            println "Request written, reading response..."; println input.text
        }
        println "Waiting 5 secs for read to complete."
        readerThread.join(5000)
    }
    println "Stream closed!"
}

出力ストリームの直接フラッシュからライターによる間接ラッピングやフラッシュまで、さまざまなフラッシュ手段を試しました。ストリームが閉じてソケットが閉じ、ソケットからの読み取りがクラッシュするまで、サーバーにデータは表示されません。私は何が間違っているのですか?以下にAndroidコードもインライン化します。これは、ソケットサーバーを起動する単純なアクティビティです。

MyServer.java

package com.example;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

public class MyServer extends Activity
{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        RawSocketServer rawSocketServer = new RawSocketServer();
        String port = rawSocketServer.getLocalPort();
        TextView textView = (TextView) this.findViewById(R.id.mainTextView);
        textView.setText("Server bound to port " + port);
        rawSocketServer.start();
    }
}

RawSocketServer.java

package com.example;

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

/**
 * Created by IntelliJ IDEA.
 * User: cliff
 * Date: 5/9/12
 * Time: 4:03 PM
 */
public class RawSocketServer {

    public static final int PORT = 0;
    private ServerSocket serverSocket;

    public RawSocketServer() {
        this(PORT);
    }

    public RawSocketServer(int port) {
        try {
            this.serverSocket = new ServerSocket(port);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("server cannot bind to port " + port);
        }
    }

    public void start() {
        new Thread(new Runnable() {
            public void run() {
                go();
            }
        }).start();
    }

    private void go() {
        Socket socket = null;
        while (true) {
            try {
                socket = this.serverSocket.accept();
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException("cannot accept from server socket" + e);
            }
            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException("Could not get input stream from socket. " + e);
            }
            PrintWriter writer = null;
            try {
                writer = new PrintWriter(socket.getOutputStream());
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException("Could not get output stream from socket. " + e);
            }
            try {
                for (String line = reader.readLine(); line !=null; line = reader.readLine()) {
                    writer.print(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException("Error reading/writing from/to socket. " + e);
            }
        }
    }

    public String getLocalPort() {
        return "" + serverSocket.getLocalPort();
    }
}
4

2 に答える 2

1

私は疑問に思っています....あなたはそこに「それ<<'エコーテスト'」を持っています。Writerでそれを使用することは、行末が書き込まれないことを意味します。サーバーはreadLineを使用しているため、行末が必要です。したがって、データは到着する可能性がありますが、readLineは行の終わりを待つため、終了していません。修正は、たとえば「it <<'echotesting\n'」または「it<<'echotesting'<<'\n'」を実行することです。

Android APIについてはよくわかりませんが、「writer.print(line);」で同じ問題が発生する可能性があります。これは、readLineで読み取られた行に、末尾の行が含まれていないと思われるためです。しかし、それは二度と読まれないので、現時点では問題ないはずです。

于 2012-05-14T10:53:50.343 に答える
1

私はついにBlackdragの助けを借りてこれを理解しました。私の問題は複数の分野にありました。(blackdragが示唆したように)改行が欠落しているため、クライアントの読み取りがハングします。また、クライアントが書き込みストリームを閉じることはないため、サーバーの読み取りループがハングします。これにより、書き込みストリームを閉じると、読み取りストリームを閉じるソケットが閉じられるという鶏が先か卵が先かという問題が発生します。会話が終了し、サーバーが読み取りを停止してソケットを閉じる必要があることを示す「プロトコル」を入力する必要がありました。クライアントに「完了」文字列を書き込むと、そのインジケーターになります。動作しているクライアントとサーバーの完全なソースは次のとおりです:(これはひどいAndroidコードであることはわかっていますが、当初は新しいGalaxyNexusで通信をテストすることだけを目的としていました。

SocketClient.groovy

import java.net.*
socket = new Socket()
socket.connect(new InetSocketAddress(InetAddress.getByAddress([172,17,57,21] as byte[]), 58302), 5000)
println "Connected!"
socket.withStreams { input, output ->
    println "Processing ${input.class.name} and ${output.class.name} streams..."
    output.withWriter {
        it << 'my name is cliff\ndone\n'; 
        it.flush();
        output.flush()
        def readerThread = Thread.start {
            println "Request written, reading response..."; println input.text
        }
        println "Waiting 5 secs for read to complete."
        readerThread.join(60000)
    }
    println "Stream closed!"
}

MyServer.java

package com.example;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

public class MyServer extends Activity
{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        RawSocketServer rawSocketServer = new RawSocketServer();
        String port = rawSocketServer.getLocalPort();
        TextView textView = (TextView) this.findViewById(R.id.mainTextView);
        textView.setText("Server bound to port " + port);
        rawSocketServer.start();
    }
}

RawSocketServer.java

package com.example;

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

/**
 * Created by IntelliJ IDEA.
 * User: cliff
 * Date: 5/9/12
 * Time: 4:03 PM
 */
public class RawSocketServer {

    public static final int PORT = 0;
    private ServerSocket serverSocket;

    public RawSocketServer() {
        this(PORT);
    }

    public RawSocketServer(int port) {
        try {
            this.serverSocket = new ServerSocket(port);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("server cannot bind to port " + port);
        }
    }

    public void start() {
        new Thread(new Runnable() {
            public void run() {
                go();
            }
        }).start();
    }

    private void go() {
        Socket socket = null;
        while (true) {
            try {
                socket = this.serverSocket.accept();
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException("cannot accept from server socket" + e);
            }
            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException("Could not get input stream from socket. " + e);
            }
            PrintWriter writer = null;
            try {
                writer = new PrintWriter(socket.getOutputStream());
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException("Could not get output stream from socket. " + e);
            }
            try {
                for (String line = reader.readLine(); line !=null; line = reader.readLine()) {
                    if(line.trim().equalsIgnoreCase("done")) break;
                    writer.println(line);
                    writer.flush();
                }
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException("Error reading/writing from/to socket. " + e);
            }
        }
    }

    public String getLocalPort() {
        return "" + serverSocket.getLocalPort();
    }
}
于 2012-05-17T15:35:26.340 に答える