我正在试图弄清楚这是否正常。因为没有错误,连接应该通过以下方式终止:
FIN ->
<- ACK
<- FIN
ACK ->
我在TCP连接结束时(通过SSL,但我也使用非加密方式得到它):
From To
1494 server client TCP search-agent > 59185 [PSH, ACK] Seq=25974 Ack=49460 Win=63784 Len=50
1495 client server TCP 59185 > search-agent [ACK] Seq=49460 Ack=26024 Win=63565 Len=0
1496 client server TCP 59185 > search-agent [PSH, ACK] Seq=49460 Ack=26024 Win=63565 Len=23
1497 client server TCP 59185 > search-agent [FIN, ACK] Seq=49483 Ack=26024 Win=63565 Len=0
1498 server client TCP search-agent > 59185 [PSH, ACK] Seq=26024 Ack=49484 Win=63784 Len=23
1499 client server TCP 59185 > search-agent [RST, ACK] Seq=49484 Ack=26047 Win=0 Len=0
客户端正常退出并到达 socket.close ,不应该正常关闭连接而不重置?
我在谷歌上找不到任何关于java的TCP流...
这是我的代码:
服务器:
package Security;
import java.io.*;
import java.net.*;
import javax.net.ServerSocketFactory;
import javax.net.ssl.*;
import java.util.*;
public class SSLDemoServer
{
private static ServerSocket serverSocket;
private static final int PORT = 1234;
public static void main(String[] args) throws IOException
{
int received = 0;
String returned;
ObjectInputStream input = null;
PrintWriter output = null;
Socket client;
System.setProperty("javax.net.ssl.keyStore", "key.keystore");
System.setProperty("javax.net.ssl.keyStorePassword", "vwpolo");
System.setProperty("javax.net.ssl.trustStore", "key.keystore");
System.setProperty("javax.net.ssl.trustStorePassword", "vwpolo");
try
{
System.out.println("Trying to set up server ...");
ServerSocketFactory factory = SSLServerSocketFactory.getDefault();
serverSocket = factory.createServerSocket(PORT);
System.out.println("Server started!\n");
}
catch (IOException ioEx)
{
System.out.println("Unable to set up port!");
ioEx.printStackTrace();
System.exit(1);
}
while(true)
{
client = serverSocket.accept();
System.out.println("Client trying to connect...");
try
{
System.out.println("Trying to create inputstream...");
input = new ObjectInputStream(client.getInputStream());
System.out.println("Trying to create outputstream...");
output = new PrintWriter(client.getOutputStream(), true);
System.out.println("Client successfully connected!");
while( true )
{
received = input.readInt();
returned = Integer.toHexString(received);
System.out.print(" " + received);
output.println(returned.toUpperCase());
}
}
catch(SSLException sslEx)
{
System.out.println("Connection failed! (non-SSL connection?)\n");
client.close();
continue;
}
catch(EOFException eofEx)
{
System.out.println("\nEnd of client data.\n");
}
catch(IOException ioEx)
{
System.out.println("I/O problem! (correct inputstream?)");
}
try {
input.close();
output.close();
}
catch (Exception e) {
}
client.close();
System.out.println("Client closed.\n");
}
}
}
客户端:
package Security;
import java.io.*;
import java.net.*;
import javax.net.ssl.*;
import java.util.*;
public class SSLDemoClient
{
private static InetAddress host;
private static final int PORT = 1234;
public static void main(String[] args)
{
System.setProperty("javax.net.ssl.keyStore", "key.keystore");
System.setProperty("javax.net.ssl.keyStorePassword", "vwpolo");
System.setProperty("javax.net.ssl.trustStore", "key.keystore");
System.setProperty("javax.net.ssl.trustStorePassword", "vwpolo");
System.out.println("\nCreating SSL socket ...");
SSLSocket socket = null;
try
{
host = InetAddress.getByName("192.168.56.101");
SSLSocketFactory factory = (SSLSocketFactory)
SSLSocketFactory.getDefault();
socket = (SSLSocket) factory.createSocket(host, PORT);
socket.startHandshake();
}
catch(UnknownHostException uhEx)
{
System.out.println("\nHost ID not found!\n");
System.exit(1);
}
catch(SSLException sslEx)
{
System.out.println("\nHandshaking unsuccessful ...");
System.exit(1);
}
catch (IOException e) {
e.printStackTrace();
}
System.out.println("\nHandshaking succeeded ...\n");
SSLClientThread client = new SSLClientThread(socket);
SSLReceiverThread receiver = new SSLReceiverThread(socket);
client.start();
receiver.start();
try
{
client.join();
receiver.join();
System.out.println("Trying to close...");
socket.close();
}
catch(InterruptedException iEx)
{
iEx.printStackTrace();
}
catch(IOException ioEx)
{
ioEx.printStackTrace();
}
System.out.println("\nClient finished.");
}
}
class SSLClientThread extends Thread
{
private SSLSocket socket;
public SSLClientThread(SSLSocket s)
{
socket = s;
}
public void run()
{
try
{
ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
for( int i = 1; i < 1025; i++)
{
output.writeInt(i);
sleep(10);
output.flush();
}
output.flush();
sleep(1000);
output.close();
}
catch(IOException ioEx)
{
System.out.println("Socket closed or unable to open socket.");
}
catch(InterruptedException iEx)
{
iEx.printStackTrace();
}
}
}
class SSLReceiverThread extends Thread
{
private SSLSocket socket;
public SSLReceiverThread(SSLSocket s)
{
socket = s;
}
public void run()
{
String response = null;
BufferedReader input = null;
try
{
input = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
try
{
response = input.readLine();
while(!response.equals(null))
{
System.out.print(response + " ");
response = input.readLine();
}
}
catch(Exception e)
{
System.out.println("\nEnd of server data.\n");
}
input.close();
}
catch(IOException ioEx)
{
ioEx.printStackTrace();
}
}
}
非常感谢,在非SSL连接上,我现在可以在没有重置的情况下获得良好的有序连接关闭。
但显然SSLSocket
不支持此方法?当我在我的SSL客户端中尝试它时,我得到以下异常:
Exception in thread "Thread-0" java.lang.UnsupportedOperationException: The method shutdownOutput() is not supported in SSLSocket
at com.sun.net.ssl.internal.ssl.BaseSSLSocketImpl.shutdownOutput(Unknown Source)
at Security.SSLClientThread.run(SSLDemoClient.java:99)
我的新代码如下:
package Security;
import java.io.*;
import java.net.*;
import javax.net.SocketFactory;
import javax.net.ssl.*;
public class SSLDemoClient
{
private static InetAddress host;
private static Socket socket;
private static final int PORT = 1234;
public static void main(String[] args)
{
System.setProperty("javax.net.ssl.keyStore", "key.keystore");
System.setProperty("javax.net.ssl.keyStorePassword", "vwpolo");
System.setProperty("javax.net.ssl.trustStore", "key.keystore");
System.setProperty("javax.net.ssl.trustStorePassword", "vwpolo");
System.out.println("\nCreating SSL socket ...");
try
{
host = InetAddress.getByName("192.168.56.101");
SocketFactory socketFactory = SSLSocketFactory.getDefault();
socket = socketFactory.createSocket(host, PORT);
}
catch(UnknownHostException uhEx)
{
System.out.println("\nHost ID not found!\n");
System.exit(1);
}
catch(SSLException sslEx)
{
System.out.println("\nHandshaking unsuccessful ...");
System.exit(1);
}
catch (IOException e) {
e.printStackTrace();
}
System.out.println("\nHandshaking succeeded ...\n");
SSLClientThread client = new SSLClientThread(socket);
SSLReceiverThread receiver = new SSLReceiverThread(socket);
client.start();
receiver.start();
try
{
client.join();
receiver.join();
System.out.println("Trying to close...");
socket.close();
}
catch(InterruptedException iEx)
{
iEx.printStackTrace();
}
catch(IOException ioEx)
{
ioEx.printStackTrace();
}
System.out.println("\nClient finished.");
}
}
class SSLClientThread extends Thread
{
private Socket socket;
public SSLClientThread(Socket s)
{
socket = s;
}
public void run()
{
try
{
ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
for( int i = 1; i < 1025; i++)
{
output.writeInt(i);
sleep(10);
output.flush();
}
output.flush();
sleep(1000);
socket.shutdownOutput();
}
catch(IOException ioEx)
{
System.out.println("Socket closed or unable to open socket.");
}
catch(InterruptedException iEx)
{
iEx.printStackTrace();
}
}
}
class SSLReceiverThread extends Thread
{
private Socket socket;
public SSLReceiverThread(Socket s)
{
socket = s;
}
public void run()
{
String response = null;
BufferedReader input = null;
try
{
input = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
try
{
response = input.readLine();
while(!response.equals(null))
{
System.out.print(response + " ");
response = input.readLine();
}
}
catch(Exception e)
{
System.out.println("\nEnd of server data.\n");
}
socket.shutdownInput();
}
catch(IOException ioEx)
{
ioEx.printStackTrace();
}
}
}
我没有正确使用它吗?或者我的SSLSocket不正确?因为使用非SSL连接没有问题。
答案 0 :(得分:8)
您的数据包日志显示客户端正在发送其最后一位数据,并通知服务器关闭连接。
服务器然后发回它的最后一位数据(可能是最后转换的整数)。客户端以RST
响应,表示客户端套接字已关闭以读取和 - 客户端说“对不起,我没有抓到最后一点数据,我不再听了。“
我不是Java大师,但似乎调用套接字.close()
的{{1}}方法会导致在套接字本身上调用OutputStream
方法。你真正希望在这里发生的事情(在客户端写完最后一个整数之后)是在套接字上调用.close()
方法。
答案 1 :(得分:4)
正如caf指出的那样,问题在于,当您应该致电close
时,您正在呼叫shutdownOutput
。这是因为您尝试实现的是半关闭,其中连接的每一侧都关闭它的输出流,以便向对等方指示没有更多数据待处理(EOF)。
有关关闭和关闭之间差异的说明,请参阅此简短的答案“close vs. shutdown”以及此较长的文章“Socket shutdown versus socket close”。另请参阅Orderly Versus Abortive Connection Release in Java。
答案 2 :(得分:0)
这里的真正的问题是,在另一端已经关闭其连接结束之后,一端正在写入。这是应用程序协议错误。