Java Socket连接仅适用于调试模式

时间:2016-08-24 13:14:16

标签: java sockets debugging

我想实现一个服务器,它在特定端口上监听无休止的接收来自许多客户端的数据(从不并行,只有串行)。我尝试的第一件事是运行服务器,然后连续启动一些客户端(一个接一个)。

这听起来非常容易实现,但实际上我遇到了问题,代码只有在我在调试模式下运行时才能运行,并且服务器代码中至少有一个断点(但是与正常运行时相同的错误)断点),对我来说很奇怪。

但是这里是服务器代码:

public class TaskExecutionServer {
    public TaskExecutionServer(final int port) {
        new Thread() {
            @Override
            public void run() {
                try {
                    int counter = 0;
                    ServerSocket serverSocket = new ServerSocket(port);

                    while(true) {
                        System.out.println("Waiting for client...");
                        Socket socket = serverSocket.accept();
                        System.out.println("Accepted");
                        InputStream inputStream = socket.getInputStream();
                        ObjectInputStream objectStream = new ObjectInputStream(inputStream);
                        while(inputStream.available() > 0 ) {
                            String to = (String)objectStream.readObject();
                            System.out.println(to);
                            System.out.println(++counter);
                        }
                        objectStream.close();
                        inputStream.close();

                        System.out.println("Closing socket");
                        socket.close();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
    public static void main(String args[]) {
        new TaskExecutionServer(2003);
    }
}

这里是客户端代码:

public class TaskSenderClient {
  public static void main(String args[]){
    try{
        Socket s = new Socket("localhost",2003);
        OutputStream os = s.getOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(os);

        oos.writeObject("test");
        oos.close();
        os.close();
        s.close();
    }catch(Exception e){
        System.out.println("Client exception");
        e.printStackTrace();
    }
  }
}

这是在调试模式下运行时的控制台输出,在服务器代码行System.out.println("Accepted");中有断点:

Waiting for client...
Accepted
test
1
Closing socket
Waiting for client...
Accepted
test
2
Closing socket
Waiting for client...
Accepted
test
3
Closing socket
Waiting for client...

在调试模式下以正常模式运行/没有断点时的输出:

Waiting for client...
Accepted
test
1
Closing socket
Waiting for client...
Accepted
Closing socket
Waiting for client...
Accepted
Closing socket
Waiting for client...

我没有得到任何例外......有人可以帮忙吗?这是我第一次尝试在java中重用套接字连接。

编辑:检查inputStream.available返回不同​​的值

我刚在服务器代码中的System.out.println(inputStream.available());之前添加了while。这打印

  • 在调试模式下使用断点
  • 始终为7
  • 7(在第一次运行中)和0(在所有其他尝试中)之后在非调试模式下/没有断点

编辑2:首先等到inputStream.available!= 0 这个解决方案对我也有用。但是,我在此删除了此代码段,因为检查available()似乎不是正确的方法! - >看到解决方案!

编辑3:新服务器代码,使用NonEmptyInputStream检查每个PushbackInputStream非空流:

由于这使用EOFException,它似乎不是我的最佳解决方案,因此我也删除了此代码段(请参阅下面的解决方案)。 "中的例外用法正确"代码在下面的评论中讨论......

2 个答案:

答案 0 :(得分:3)

如果还没有数据,

InputStream.available()可以返回0,这意味着客户端尚未发送一些数据,或者至少尚未到达。如果添加断点,客户端有更多时间发送数据。

您可以添加逻辑,就像客户端首先发送它写入的对象一样,服务器读取数量,然后在停止读取之前读取那么多对象。

另一种可能性是在PushbackInputStreamObjectInputStream之间插入InputStream,然后在read()上执行PushbackInputStream,检查结果-1表示流末尾,如果不是-1,请在使用unread()方法之前使用ObjectInputStream将读取的字节推回流中。

这里有一个用最后一个模式重写的原始发布类的示例:

public class TaskExecutionServer {
    public TaskExecutionServer(final int port) {
        new Thread() {
            @Override
            public void run() {
                try {
                    int counter = 0;
                    ServerSocket serverSocket = new ServerSocket(port);

                    while(true) {
                        System.out.println("Waiting for client...");
                        Socket socket = serverSocket.accept();
                        System.out.println("Accepted");
                        InputStream inputStream = socket.getInputStream();
                        PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream);
                        ObjectInputStream objectStream = new ObjectInputStream(pushbackInputStream);
                        for(int i; (i = pushbackInputStream.read()) != -1;) {
                            pushbackInputStream.unread(i);
                            String to = (String) objectStream.readObject();
                            System.out.println(to);
                            System.out.println(++counter);
                        }
                        objectStream.close();
                        pushbackInputStream.close();
                        inputStream.close();

                        System.out.println("Closing socket");
                        socket.close();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

    public static void main(String args[]) {
        new TaskExecutionServer(2003);
    }
}

或者再次使用try-with-resources,这比手动关闭AutoClosable s更好。

public class TaskExecutionServer {
    public TaskExecutionServer(final int port) {
        new Thread() {
            @Override
            public void run() {
                try (ServerSocket serverSocket = new ServerSocket(port)) {
                    int counter = 0;

                    while(true) {
                        System.out.println("Waiting for client...");
                        try (Socket socket = serverSocket.accept();
                             InputStream inputStream = socket.getInputStream();
                             PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream);
                             ObjectInputStream objectStream = new ObjectInputStream(pushbackInputStream)) {
                            System.out.println("Accepted");
                            for(int i; (i = pushbackInputStream.read()) != -1;) {
                                pushbackInputStream.unread(i);
                                String to = (String) objectStream.readObject();
                                System.out.println(to);
                                System.out.println(++counter);
                            }
                            System.out.println("Closing socket");
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

    public static void main(String args[]) {
        new TaskExecutionServer(2003);
    }
}

答案 1 :(得分:1)

"st"不是流结束的有效测试。见Javadoc。您应该从对象流中读取,直到available()被捕获。