Java TCP Socket编程:Client和Server在同一台电脑上通信良好,但无法通过局域网相互发送数据

Java TCP Socket Programming: Client and Server communicate well on the same computer, but fail to send data to each other over LAN

我正在尝试设置一个服务器可以与多个客户端通信的程序。程序写在Java。我在同一台机器上完成了所有工作,所以我决定尝试 LAN。我将程序转换为 JAR 文件,并尝试将我的笔记本电脑连接到我的 PC(两者都在同一个网络上)。连接成功,但不幸的是 only 1 消息到达服务器。正如您在下面的代码中看到的,我通过 DataOutputStream 发送了多条消息(意味着我写了多次 )。一个定义数据类型(在下面的示例中,0 表示它是一个字符串),另一个发送实际的消息数据。我还以字节为单位打印数据包的大小,它始终与 DataOutputStream 实例的大小相匹配。

DataOutputStream dOut = new DataOutputStream(clientSocket.getOutputStream());
String str = "Hello";
//Type
System.out.println("Type output size: 1");
dOut.writeByte(0);
//Message
System.out.println("Message output size: " + (str.getBytes(StandardCharsets.UTF_8).length + 2));
dOut.writeUTF(str);

System.out.println("Length of all: " + (dOut.size()));
dOut.flush();

所以现在当从客户端发送数据时,我们需要在服务器上处理它,下面的代码就是这样做的。它从调用的 Socket 客户端检索 InputStream 并将其插入 DataInputStream。这是因为在 LAN 上它变得很奇怪,因为流只包含 第一条消息

InputStream stream = client.getInputStream(); 
DataInputStream dIn = new DataInputStream(stream); 

while(dIn.available() > 0) {
   byte type = dIn.readByte();
    
  switch(type) {
                    
    case 0:
      System.out.println(dIn.readUTF());
      break;
    case 1:
      System.out.println(dIn.readInt());
      break;
    case 2:
      System.out.println(dIn.readByte());
      break;

    default:
      throw new IllegalStateException("Unexpected value: " + type);       
  }
}

如果您 运行 IDE 中的客户端假设笔记本电脑连接到同一网络,然后您 运行 PC 上的服务器连接到同一网络 它会起作用。但是,如果程序在 JARS 中,则不会。

实际的堆栈跟踪如下:

java.net.SocketException: Connection reset at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:323) at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:350) at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:803) at java.base/java.net.Socket$SocketInputStream.read(Socket.java:966) at java.base/java.net.Socket$SocketInputStream.read(Socket.java:961) at java.base/java.io.DataInputStream.readInt(DataInputStream.java:393)

堆栈跟踪没有告诉我任何信息,但它指向 switch case 中的 case 0:。它无法读取字符串,因为 DataInputStream 不包含任何数据(我猜?)。

我还要声明Server是多线程的!我有一个线程在通过 ServerSocket.accept() 接受套接字时添加套接字,我使用第二个(主线程)读取从客户端发送的数据。

我选择了上面的代码,因为我认为问题出在其中,但是我是套接字编程的新手,我知道你们中的一些人希望看到代码的其他部分。当我被问到时,我会添加更多相关代码。

我不知道为什么会这样,有人知道为什么吗?

我尝试了什么?

更新 1

我一直在听取评论中的建议,这导致了一些发现:

更新二: 我认为这个 是相关的。它声明当客户端“不优雅地”关闭它的套接字时发送 SocketException。而且因为我的客户端关闭(因为它不在循环中)并且我没有正确关闭套接字 - 它会“不正常地”关闭并且数据将会丢失。因此错误。

问题已经解决,解决方案也比较合理。我的客户端不在循环中运行,而是发送数据并关闭程序。听起来不错,但我忘了正确关闭客户端的套接字。

第二个'packet'没有到达的原因是我犯了这个小错误。数据包在通过本地网络的途中,但客户端套接字不正确 在数据包到达服务器之前关闭了它的套接字,这就是我收到 SocketException 错误的原因。参见

我通过放置 socket.close() 解决了这个问题,其中 socket 是客户端的套接字,在我发送了所有我想发送的消息之后。