gpt4 book ai didi

java - 通过套接字发送对象导致 SocketException

转载 作者:行者123 更新时间:2023-12-04 12:04:22 28 4
gpt4 key购买 nike

如何阻止 SocketException 的发生?

我正在尝试将序列化对象从客户端简单传输到本地计算机上的服务器。

我已经能够使用以下代码的细微变化来发送字符串,但是当我尝试发送对象时

Customer customerToReceive = (Customer) input.readObject();// EXCEPTION OCCURS RIGHT HERE

我收到一个我不明白如何解释的 SocketException。

java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(Unknown Source)
at java.io.ObjectInputStream$PeekInputStream.read(Unknown Source)
at java.io.ObjectInputStream$BlockDataInputStream.read(Unknown Source)
at java.io.ObjectInputStream$BlockDataInputStream.readFully(Unknown Source)
at java.io.ObjectInputStream.defaultReadFields(Unknown Source)
at java.io.ObjectInputStream.readSerialData(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at MattServer.runCustomerServer(MattServer.java:44)
at MattServer.<init>(MattServer.java:14)
at MattServerTest.main(MattServerTest.java:10)

这是客户端代码,它似乎根本没有提示: 公开课 MattClient { 套接字客户端; ObjectOutputStream输出; 对象输入流输入; 字符串消息;

public MattClient()
{
runCustomerClient();
}

public void runCustomerClient()
{
try
{
//Connection:
System.out.println("Attempting connection...");
client = new Socket("localhost",12345);
System.out.println("Connected to server...");

//Connect Streams:

//output.flush();
System.out.println("Got IO Streams...");

//SEND MESSAGES:
try
{
for(int i = 1;i<=10;i++)
{
output = new ObjectOutputStream(client.getOutputStream());
Customer customerToSend = new Customer("Matt", "1234 fake street", i);
System.out.println("Created customer:");
System.out.println(customerToSend.toString());
output.writeObject(customerToSend);
output.flush();
};
message = "TERMINATE";
System.out.println(message);
output.writeObject(message);
output.reset();
output.flush();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch(Exception e2)
{
e2.printStackTrace();
}
finally
{

}
}
catch (IOException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
catch(Exception e3)
{
e3.printStackTrace();
}
finally
{

}
}

反抗的服务器:

public class MattServer
{
ServerSocket server;
Socket socket;
ObjectInputStream input;
ObjectOutputStream output;
String message;

public MattServer()
{
runCustomerServer();
}

public void runCustomerServer()
{
try
{
server = new ServerSocket(12345,100000);
while(true)
{
//CONNECTION:
System.out.println("Waiting for connection");
socket = server.accept();
System.out.println("Connection received...");

//CONNECT STREAMS:
//output = new ObjectOutputStream(socket.getOutputStream());
//output.flush();
input = new ObjectInputStream(socket.getInputStream());
System.out.println("Got IO Streams...");

//PROCESS STREAMS:
System.out.println("Connection successful!");
do
{
System.out.println("Started loop");
try
{
System.out.println("in try...");
System.out.println(socket.getInetAddress().getHostName());
Customer customerToReceive = (Customer) input.readObject();// EXCEPTION OCCURS RIGHT HERE
Object o = input.readObject();
System.out.println("Object of class " + o.getClass().getName() + " is " + o);
System.out.println("Got customer object");
System.out.println(customerToReceive.toString());
}
catch(ClassNotFoundException cnfE)
{
System.out.println("Can't convert input to string");
}
} while(!message.equals("TERMINATE"));

System.out.println("Finished.");

}
}
catch(IOException ioE)
{
ioE.printStackTrace();
}
finally
{
try
{
input.close();
socket.close();
server.close();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

最佳答案

此异常是过早关闭连接的结果,即客户端发送了它的数据并立即关闭了连接。在这种情况下,服务器通常无法读取客户端发送的所有数据,并且在服务器端看到的传输过程中连接终止。

请注意,flush()-ing 网络 OutputStream 并不意味着或保证任何/所有数据已实际传输。在最好的情况下,这只会确保所有数据都传递到本地计算机上的网络堆栈,这将自行决定何时实际传输数据。

对此的一种解决方案是让服务器在准备就绪时关闭连接。然后客户端应该等待,例如在阻塞的 read() 操作中,然后当 server 发出传输结束信号时,将收到指定异常的通知。

另一种方法是实现自己的确认,这样客户端将等待服务器发回确认消息,之后双方可以安全地关闭连接。

作为引用,在像您这样的情况下,有一些套接字选项会影响连接的行为,即:

SO_LINGERTCP_NODELAY

(这些套接字选项不是您的问题的解决方案,但在某些情况下可能会改变观察到的行为。)

编辑:

看来 SO_LINGER 选项与观察到的行为的相关性并不像我从引用文档中所认为的那样明显。因此,我会尽量使这一点更清楚:

在 Java 中,基本上两种方法可以通过 close() 终止 TCP 连接:

  1. 没有启用SO_LINGER 选项。在这种情况下,会立即发送 TCP 连接重置 (RST) 并返回对close() 的调用。在接收到 RST 后尝试使用连接(读取或写入)时,连接的对等方将收到一个异常,指出“连接已重置”。

    <
  2. 使用启用 SO_LINGER 选项。在这种情况下,会生成一个 TCP FIN 以有序地关闭连接。然后,如果对等方没有在给定的时间范围内确认发送的数据,则会发生超时,并且发出 close() 的本地方会像案例 #1 一样继续,发送 RST,然后声明连接“已终止”。

因此,通常人们希望启用 SO_LINGER 以允许对等方处理数据,然后干净地断开连接。如果 SO_LINGER 未启用并且 close() 被调用之前所有数据都已被对等方处理(即'太早') 命名的异常重新重置 连接发生在对等方。

如上所述,TCP_NODELAY 选项可能以不确定的方式改变观察到的行为,因为写入的数据更有可能已经通过网络传输调用close() 之前导致连接重置。

关于java - 通过套接字发送对象导致 SocketException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13827625/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com