0

我已经编写了一个小型客户端/服务器程序,它已经工作过一次,但是在向它添加线程和一些真实的输入数据之后,我总是在能够读取对象(字符串)之前得到一个关闭的套接字。程序总是打印“客户端已经关闭连接!” 来自 ProcessDataThread 中的函数句柄连接。

客户代码:

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.");
        }
    }
}

服务器代码:

接收线程:

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();
    }

}

进程数据线程:

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 的建议做了一些更改。这就是我现在得到的。错误保持不变。我什至没有阅读服务器中的流,因为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

4 回答 4

1

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

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

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

因此,从解决方案的角度研究这个问题并可能开始使用适当的协议(如:telnet 等)是没有用的。

于 2019-06-25T19:24:37.723 回答
0

好吧,现在我觉得自己很愚蠢。我自己关闭了服务器代码中的套接字。接受连接后,在 finally 块内执行以下操作:

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

有这个 finally 块的原因是因为我之前没有使用线程,所以 ReceiverThread 也确实处理了连接,因此在使用它后关闭了套接字。然后我将代码移动到新线程,忘记删除 finally 块!

于 2013-08-29T16:51:31.367 回答
0

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

编辑重新编辑,“套接字关闭”意味着关闭了套接字,然后继续使用它。

于 2013-08-29T12:37:01.577 回答
0

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

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

在您的服务器上,您读取到 EOF,然后发送一个对象作为确认,例如消息中的字节数。socket.shutdownOutput()您还可以像在客户端所做的那样结束发送。这又在数据末尾放置了一个 EOF。这个 EOF 被客户端接收到,它最终会关闭套接字。

于 2013-08-29T13:50:28.883 回答