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()
接受套接字时添加套接字,我使用第二个(主线程)读取从客户端发送的数据。
我选择了上面的代码,因为我认为问题出在其中,但是我是套接字编程的新手,我知道你们中的一些人希望看到代码的其他部分。当我被问到时,我会添加更多相关代码。
我不知道为什么会这样,有人知道为什么吗?
我尝试了什么?
- 我试过等待数据包 - 但这只会导致
服务器永远循环。等待数据包我的意思是在
DataInputStream
包含足够的字节之前不要继续。
- 我已通过
setTCPNoDelay(false)
禁用 Nagels Algorithm
。
- 尝试发送不同的数据类型,但同样失败
- 我尝试将第一个数据包更改为
String
,这导致 String
出现在 DataInputStream
中。
- 我试过转发使用的端口,我试过在两台计算机上禁用防火墙。
更新 1
我一直在听取评论中的建议,这导致了一些发现:
- 关闭
DataOutputStream
成功发送所有个数据包到客户端。
- 也可以构建自己的缓冲区并在服务器中对其进行解码。但是,此后仍然无法发送任何消息。
- 它作为一个 JAR 文件工作,因为 IntelliJ 很好(Eclipse 在 IDE 中 运行ning 时抛出了同样的错误)
更新二:
我认为这个 是相关的。它声明当客户端“不优雅地”关闭它的套接字时发送 SocketException。而且因为我的客户端关闭(因为它不在循环中)并且我没有正确关闭套接字 - 它会“不正常地”关闭并且数据将会丢失。因此错误。
问题已经解决,解决方案也比较合理。我的客户端不在循环中运行,而是发送数据并关闭程序。听起来不错,但我忘了正确关闭客户端的套接字。
第二个'packet'没有到达的原因是我犯了这个小错误。数据包在通过本地网络的途中,但客户端套接字不正确 在数据包到达服务器之前关闭了它的套接字,这就是我收到 SocketException 错误的原因。参见 。
我通过放置 socket.close()
解决了这个问题,其中 socket
是客户端的套接字,在我发送了所有我想发送的消息之后。
我正在尝试设置一个服务器可以与多个客户端通信的程序。程序写在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()
接受套接字时添加套接字,我使用第二个(主线程)读取从客户端发送的数据。
我选择了上面的代码,因为我认为问题出在其中,但是我是套接字编程的新手,我知道你们中的一些人希望看到代码的其他部分。当我被问到时,我会添加更多相关代码。
我不知道为什么会这样,有人知道为什么吗?
我尝试了什么?
- 我试过等待数据包 - 但这只会导致
服务器永远循环。等待数据包我的意思是在
DataInputStream
包含足够的字节之前不要继续。 - 我已通过
setTCPNoDelay(false)
禁用Nagels Algorithm
。 - 尝试发送不同的数据类型,但同样失败
- 我尝试将第一个数据包更改为
String
,这导致String
出现在DataInputStream
中。 - 我试过转发使用的端口,我试过在两台计算机上禁用防火墙。
更新 1
我一直在听取评论中的建议,这导致了一些发现:
- 关闭
DataOutputStream
成功发送所有个数据包到客户端。 - 也可以构建自己的缓冲区并在服务器中对其进行解码。但是,此后仍然无法发送任何消息。
- 它作为一个 JAR 文件工作,因为 IntelliJ 很好(Eclipse 在 IDE 中 运行ning 时抛出了同样的错误)
更新二:
我认为这个
问题已经解决,解决方案也比较合理。我的客户端不在循环中运行,而是发送数据并关闭程序。听起来不错,但我忘了正确关闭客户端的套接字。
第二个'packet'没有到达的原因是我犯了这个小错误。数据包在通过本地网络的途中,但客户端套接字不正确 在数据包到达服务器之前关闭了它的套接字,这就是我收到 SocketException 错误的原因。参见
我通过放置 socket.close()
解决了这个问题,其中 socket
是客户端的套接字,在我发送了所有我想发送的消息之后。