简体   繁体   English

Java中可靠的TCP / IP

[英]Reliable TCP/IP in Java

Is there a way to have reliable communications (the sender get informed that the message it sent is already received by the receiver) using Java TCP/IP library in java.net.*? 有没有办法在java.net中使用Java TCP / IP库进行可靠的通信(发送者得知它发送的消息已被接收者接收)。*? I understand that one of the advantages of TCP over UDP is its reliability. 我知道TCP over UDP的一个优点是它的可靠性。 Yet, I couldn't get that assurance in the experiment below: 然而,我无法在下面的实验中得到这样的保证:

I created two classes: 我创建了两个类:

1) echo server => always sending back the data it received. 1)echo server =>总是发回它收到的数据。

2) client => periodically send "Hello world" message to the echo server. 2)cli​​ent =>定期向echo服务器发送“Hello world”消息。

They were run on different computers (and worked perfectly). 它们在不同的计算机上运行(并且工作得很好)。 During the middle of the execution, I disconnected the network (unplugged the LAN cable). 在执行过程中,我断开了网络连接(拔掉了LAN电缆)。 After disconnected, the server still keep waiting for a data until a few seconds passed (it eventually raised an exception). 断开连接后,服务器仍会等待数据,直到几秒钟过去(最终引发异常)。 Similarly, the client also keep sending a data until a few seconds passed (an exception is raised). 同样,客户端也会继续发送数据,直到几秒钟过去(引发异常)。

The problem is, objectOutputStream.writeObject(message) doesn't guarantee the delivery status of the message (I expect it to block the thread, keep resending the data until delivered). 问题是, objectOutputStream.writeObject(message)不保证objectOutputStream.writeObject(message)的传递状态(我希望它阻止线程,继续重发数据直到传递)。 Or at least I get informed, which messages are missing. 或者至少我得到消息,哪些消息丢失了。

Server Code: 服务器代码:

import java.net.*;
import java.io.*;

import java.io.Serializable;

public class SimpleServer {
    public static void main(String args[]) {
        try {
            ServerSocket serverSocket = new ServerSocket(2002);
            Socket socket = new Socket();
            socket = serverSocket.accept();
            InputStream inputStream = socket.getInputStream();
            ObjectInputStream objectInputStream = new ObjectInputStream(
                    inputStream);

            while (true) {
                try {
                    String message = (String) objectInputStream.readObject();
                    System.out.println(message);
                    Thread.sleep(1000);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

Client code: 客户代码:

import java.net.*;
import java.io.*;

public class SimpleClient {
    public static void main(String args[]) {
        try {
            String serverIpAddress = "localhost"; //change this

            Socket socket = new Socket(serverIpAddress, 2002);
            OutputStream outputStream = socket.getOutputStream();
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(
                    outputStream);

            while (true) {
                String message = "Hello world!";
                objectOutputStream.writeObject(message);

                System.out.println(message);
                Thread.sleep(1000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

如果您需要知道哪些消息已到达对等应用程序,则对等应用程序必须发送确认。

If you want this level of guarantees it sounds like you really want JMS. 如果你想要这种级别的保证,听起来你真的想要JMS。 This can ensure not only that messages have been delivered but also have been processed correctly. 这不仅可以确保消息已经传递,而且还可以正确处理。 ie there is no point having very reliable delivery if it can be discarded due to a bug. 也就是说,如果因为一个错误而被丢弃,那么没有必要提供非常可靠的交付。

You can monitor which messages are waiting and which consumers are falling behind. 您可以监控哪些消息正在等待以及哪些消费者落后。 Watch a producer to see what messages it is sending, and have messages saved when it is down and are available when it restarts. 观察生产者以查看它正在发送的消息,并在消息关闭时保存消息,并在重新启动时可用。 ie reliable delivery even if the consumer is restarted. 即使重新启动消费者,即可靠的交付。

TCP is always reliable. TCP总是可靠的。 You don't need confirmations. 您不需要确认。 However, to check that a client is up, you might also want to use a UDP stream with confirmations. 但是,要检查客户端是否已启动,您可能还需要使用带有确认的UDP流。 Like a PING? 像PING一样? PONG! PONG! system. 系统。 Might also be TCP settings you can adjust. 可能也是您可以调整的TCP设置。

Your base assumption (and understanding of TCP) here is wrong. 您的基本假设(以及对TCP的理解)在这里是错误的。 If you unplug and then re-plug, the message most likely will not be lost. 如果您拔下插头然后重新插入,则该消息很可能不会丢失。
It boils down on how long to you want the sender to wait. 它归结为您希望发件人等待多长时间。 One hour, one day? 一小时,一天? If you'd make the timeout one day, you would unplug for two days and still say "does not work". 如果你有一天超时,你会拔掉两天,然后仍然说“不起作用”。

So the guaranteed delivery is that "either data is delivered - or you get informed". 因此,保证交付是“数据交付 - 或者您得到通知”。 In the second case you need to solve it on application level. 在第二种情况下,您需要在应用程序级别上解决它。

You could consider using the SO_KEEPALIVE socket option which will cause the connection to be closed if no data is transmitted over the socket for 2 hours. 您可以考虑使用SO_KEEPALIVE套接字选项,如果没有数据通过套接字传输2小时,将导致连接关闭。 However, obviously in many cases this doesn't offer the level of control typically needed by applications. 但是,显然在许多情况下,这并不能提供应用程序通常所需的控制级别。

A second problem is that some TCP/IP stack implementations are poor and can leave your server with dangling open connections in the event of a network outage. 第二个问题是某些TCP / IP堆栈实现很差,并且在网络中断的情况下可能使您的服务器保持悬空开放连接。

Therefore, I'd advise adding application level heartbeating between your client and server to ensure that both parties are still alive. 因此,我建议在客户端和服务器之间添加应用程序级别的心跳,以确保双方仍然活着。 This also offers the advantage of severing the connection if, for example a 3rd party client remains alive but becomes unresponsive and hence stops sending heartbeats. 这还提供了切断连接的优点,例如,如果第三方客户端仍然活着但变得没有响应并因此停止发送心跳。

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

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