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

在 Blackdrag 的帮助下,我终于想通了。我的问题出在多个领域。由于缺少换行符(如 blackdrag 建议的那样),客户端读取将挂起。由于客户端从不关闭其写入流,服务器读取循环也会挂起。这导致了先有鸡还是先有蛋的问题,即关闭写入流会关闭关闭读取流的套接字。我最终需要输入一个“协议”,如果你愿意的话,它会指示对话何时完成,服务器应该停止读取并关闭套接字。在客户端上写入“完成”字符串成为该指标。工作客户端和服务器的完整源代码如下:(我知道这是糟糕的 Android 代码,但它最初只是为了测试我的新 Galaxy Nexus 上的通信,我'

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 回答
1

我想知道....那里有“它<<'回声测试'”。在 Writer 上使用它意味着 afaik 没有写入行尾。由于您的服务器使用 readLine,它需要一个行结尾。因此数据可能到达,但 readLine 没有完成,因为它等待行尾。然后修复将是例如“it << 'echo testing\n'”或“it << 'echo testing' << '\n'”。

现在我不太了解Android API,但是您的服务器在“writer.print(line);”中可能有同样的问题,因为我认为用readLine 读取的行不再包含行尾。不过既然没有再读,那现在应该没问题了。

于 2012-05-14T10:53:50.343 回答