简体   繁体   English

Java Socket连接仅在调试模式下有效

[英]Java Socket connection only works in debug mode

I want to implement a Server which listens endless on a specific port to receive data from many clients (never in parallel, only serial). 我想实现一个服务器,该服务器在特定端口上进行无限侦听,以接收来自许多客户端的数据(从不并行,仅串行)。 The first thing I tried is to run the server and then launch a few clients in serial (one after the other). 我尝试的第一件事是运行服务器,然后依次启动几个客户端(一个接一个)。

This sounded very easy to implement, but I actually got into the problem, that the code works only when I run it in debug mode with at least one breakpoint in the server code (but the same fault as when running it normally without a breakpoint), very strange to me. 这听起来很容易实现,但实际上我遇到了一个问题,即代码只有在调试模式下运行时才有效,并且服务器代码中至少有一个断点(但与正常情况下没有断点的情况下发生的故障相同) ,对我来说很奇怪。

However here is the server code: 但是,这是服务器代码:

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

And here the client code: 这是客户端代码:

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

this is the console output when running in debug mode with breakpoint in the server code row System.out.println("Accepted"); 这是在服务器代码行System.out.println("Accepted");具有断点的调试模式下运行时的控制台输出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...

And the output when running in normal mode / without breakpoints in debug-mode: 在正常模式下运行时的输出/在调试模式下没有断点的情况下:

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

I don't get any exception... Can someone help? 我没有例外...有人可以帮忙吗? It's my first attempt to re-use a socket connection in java. 这是我在Java中重用套接字连接的第一次尝试。

EDIT: Checking inputStream.available returns different values 编辑:检查inputStream.available返回不同​​的值

I just added a System.out.println(inputStream.available()); 我刚刚添加了System.out.println(inputStream.available()); before the while in server code. 服务器代码中的while之前。 This prints 此打印

  • always 7 in debug-mode with breakpoint 始终7在调试模式下断点
  • 7 (in first run) and 0 (in all other attemps) afterwards in non-debug mode / without breakpoints 在非调试模式下/无断点的情况下,第一次运行为7 (首次运行),之后为0 (在所有其他尝试)

EDIT 2: First wait until inputStream.available != 0 This solution also works for me. 编辑2:首先等待,直到inputStream.available!= 0此解决方案也适用于我。 However, I removed this code snippet here, because checking of available() seems not to be the correct way for that! 但是,我在这里删除了此代码段,因为检查available()似乎不是正确的方法! -> see the solution! ->查看解决方案!

EDIT 3: New server code, which uses NonEmptyInputStream which checks per PushbackInputStream for non-empty streams: 编辑3:新的服务器代码,它使用NonEmptyInputStream ,它按每个PushbackInputStream检查非空流:

As this uses the EOFException it seems not to be an optimal solution to me, so I also removed this code snippet (instead see solution below). 由于此方法使用EOFException ,对我来说似乎不是最佳解决方案,因此我也删除了此代码段(请参见下面的解决方案)。 The usage of exceptions in "correct" code is discussed in the comments below... 下面的注释中讨论了“正确”代码中异常的用法。

InputStream.available() can return 0 if there is no data yet, meaning the client didn't send some yet or at least it is not arrived yet. 如果还没有数据, InputStream.available()可以返回0 ,这意味着客户端还没有发送数据,或者至少还没有到达。 If you add a breakpoint the client has more time to send the data. 如果添加断点,客户端将有更多时间发送数据。

You can either add logic like your client first sends how many objects it writes, the server reads the amount and then reads that many objects before it stops reading. 您可以添加逻辑,例如客户端首先发送它写入的对象数,服务器读取数量然后在停止读取之前读取那么多对象。

Another possibility would be to insert a PushbackInputStream between the ObjectInputStream and the InputStream and then do a read() on the PushbackInputStream , check the result for -1 which means end-of-stream and if it was not -1 , use unread() to push the read byte back into the stream before using the ObjectInputStream methods. 另一种可能性是在ObjectInputStreamInputStream之间插入一个PushbackInputStream ,然后对PushbackInputStream进行read() ,检查结果是否为-1这意味着流的末尾),如果不是-1 ,则使用unread()在使用ObjectInputStream方法之前将读取的字节推回流中。

Here you have an example of your originally posted class rewritten with the last pattern: 在这里,您有一个使用最后一个模式重写的最初发布的类的示例:

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

or here again with try-with-resources which is preferable over manually closing AutoClosable s. 或再次使用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);
    }
}

available() is not a valid test for end of stream. available()对于流结束不是有效的测试。 See the Javadoc. 请参阅Javadoc。 You should read from the object stream until EOFException is caught. 您应该从对象流中读取,直到捕获到EOFException

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM