在从ObjectInputStream(BufferedInputStream(Socket.getInputStream))读取之前Socket关闭了

时间:2013-08-29 12:14:10

标签: java sockets objectinputstream

我编写了一个小型的客户端/服务器程序,它已经工作过一次,但在添加了Threads和一些真正的输入数据之后,我总是得到一个封闭的Socket,然后才能读取Object(String)。程序始终打印“客户端已关闭连接!”来自ProcessDataThread中的函数handleConnection。

ClientCode:

synchronized private static void sendToServer(){
        Socket clientSocket = null;
    BufferedOutputStream socketOut = null;
        ObjectOutputStream out = null;
    try{ 

        String xmlToSend = "<startTag>\n<someOtherTag id=\"5555\">\n12345\n</someOtherTag>\n</startTag>\n";

        Log.d(TAG, "Trying to send the following to the Server:" + xmlToSend);

        //TODO load these from file
        clientSocket = new Socket( "10.0.2.2", 7777);
        socketOut = new BufferedOutputStream(clientSocket.getOutputStream());
        out = new ObjectOutputStream(socketOut);
        out.writeObject(xmlToSend);
        out.flush();

    }catch(Exception ex){
        Log.e(TAG, "Could not write File to Server.", ex);
    }
    finally{
        try{
            if(clientSocket != null){
                clientSocket.close();
            }
            if(out != null){
                out.close();
            }
        }catch(IOException ex){
            Log.e(TAG, "Could not close Socket.");
        }
    }
}

ServerCode:

ReceiverThread:

public void run()
{
    try {
        ServerSocket server = new ServerSocket(port);
        //Only block for 10 Seconds and try again
        server.setSoTimeout(10000);
        while(!server.isClosed() && !stopped){
            //Run
             Socket client = null;
              try
              {
                client = server.accept();
                System.out.println("Accepted ClientConnection from " + client.getRemoteSocketAddress());
                new ProcessDataThread(client).start();
              }
              catch( SocketTimeoutException tx){
                  //nothing
              }
              catch ( IOException e ) {
                e.printStackTrace();
              }
              finally {
                if ( client != null )
                  try { client.close(); } catch ( IOException e ) { e.printStackTrace(); }
              }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }

}

ProcessDataThread:

public class ProcessDataThread extends Thread {

Socket client;

public ProcessDataThread(Socket sock) {
    // xmlToProcess = xmlString;
    this.client = sock;
}

private String handleConnection() {

    BufferedInputStream socketIn = null;
    ObjectInputStream in = null;
    String xmlToProcess = null;
    try {
        if(!client.isClosed()){
            System.out.println("Trying to read from Stream;");
            socketIn = new BufferedInputStream(client.getInputStream());
            in = new ObjectInputStream(socketIn);

            Object xmlString = in.readObject();
            System.out.println("Read some Object from Stream:" + xmlString.toString());
            if (xmlString instanceof String) {
                xmlToProcess = (String) xmlString;
                System.out.println("Received the following XML:\n" + xmlToProcess);
            }
        }else{
            System.out.println("Client has already closed Connection!");
        }
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (EOFException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            if (socketIn != null) {
                socketIn.close();
            }
            if(client != null){
                client.close();
            }
        } catch (IOException ioex) {
            ioex.printStackTrace();
        }
    }
    return xmlToProcess;
}

@Override
public void run() {

    String xmlToProcess = handleConnection();

    if (xmlToProcess == null || xmlToProcess.isEmpty()) {
        // Es konnte kein String vom Client gelesen werden.
        return;
    }

            System.out.println(xmlToProcess);
 }
}

我对jboi的建议做了一些改变。这就是我现在所拥有的。错误保持不变。我甚至没有阅读服务器中的Stream,因为client.getClosed() 总是如此!

在客户端代码中:

clientSocket = new Socket( "10.0.2.2", 7777);
clientSocket.setTcpNoDelay(true);
socketOut = new BufferedOutputStream(clientSocket.getOutputStream());
out = new ObjectOutputStream(socketOut);
out.writeObject(xmlToSend);
out.flush();
socketOut.flush();
//Close Output on Socket to signalize the Server that we finished writing!
clientSocket.shutdownOutput();

in = clientSocket.getInputStream();
byte[] receivedData = new byte[8192];
while(in.read(receivedData) != -1) {
    //Wait for the Server to Close the Connection
}

在服务器代码中

socketIn = new BufferedInputStream(client.getInputStream());
in = new ObjectInputStream(socketIn);
Object xmlString = in.readObject();
System.out.println("Read some Object from Stream:" + xmlString.toString());
if (xmlString instanceof String) {
    xmlToProcess = (String) xmlString;
System.out.println("Received the following XML:\n" + xmlToProcess);
}

out = client.getOutputStream();
out.write(1);
//Signalize the Client that we have read everything
client.shutdownOutput();

4 个答案:

答案 0 :(得分:1)

问题似乎是客户端和服务器无法识别彼此的状态:

  1. 客户端向服务器发送数据的服务器已关闭连接
  2. 服务器向客户端发送/读取数据,客户端已关闭连接

要么无法相互协调,要么解决方案是建立适当的状态机。 Google中的一些示例(如果您搜索(客户端和服务器状态机))会为您的应用程序提供数学上确定的状态机示例:希望此注释对您有所帮助。

因此,从解决方案的角度研究此问题并没有用处,并且可能开始使用诸如telnet等之类的协议。

答案 1 :(得分:0)

您不能在同一个套接字上使用缓冲输入流和另一种流。缓冲流将从另一个窃取数据。下定决心。 ObjectInputStream将完成您需要的一切。只需使用它。

编辑重新编辑,&#39;套接字关闭&#39;表示关闭你的套接字,然后继续使用它。

答案 2 :(得分:0)

在服务器能够读取数据之前,您的客户端很可能已关闭finally块中的套接字。

在你的客户端最终阻止你应该使用socket.shutdownOutput,然后在客户端读取所有传入的数据,直到EOF,然后关闭套接字。

在你的服务器上,你读到EOF,然后发送一个对象作为一种确认,例如消息中的字节数。您也可以在客户端使用socket.shutdownOutput()结束发送。这会在数据末尾再次显示EOF。客户端收到此EOF,它最终会关闭套接字。

答案 3 :(得分:0)

好吧,现在我感觉很蠢。 我自己关闭了服务器代码中的Socket。 接受连接后,在finally块中执行以下内容:

try {
    client.close();
} catch (IOException e) {
    e.printStackTrace();
}

最终阻塞的原因是因为我之前没有使用Threads,所以ReceiverThread也处理了Connection,因此在使用它之后关闭套接字。 然后我将代码移动到新的Thread并忘记删除最后一个块!