TCP Server与Client,应该由谁负责关闭连接?
TCP Server与Client,应该由谁负责关闭连接?其实两边都可以发起主动的关闭请求,但是涉及到具体的实现代码,会有不同。
下面是一个基础的TCPServer的代码1:
import java.io.DataInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
public class EchoServer {
public static void main(String[] args) {
// declaration section:
// declare a server socket and a client socket for the server
// declare an input and an output stream
ServerSocket echoServer = null;
String line;
DataInputStream is;
PrintStream os;
Socket clientSocket = null;
// Try to open a server socket on port 9999
// Note that we can't choose a port less than 1023 if we are not
// privileged users (root)
try {
echoServer = new ServerSocket(9999);
} catch (IOException e) {
System.out.println(e);
}
// Create a socket object from the ServerSocket to listen and accept
// connections.
// Open input and output streams
try {
clientSocket = echoServer.accept();
is = new DataInputStream(clientSocket.getInputStream());
os = new PrintStream(clientSocket.getOutputStream());
// As long as we receive data, echo that data back to the client.
line = is.readLine();
os.println(line);
os.close();
is.close();
} catch (IOException e) {
System.out.println(e);
}
}
}
上面是一个基础的EchoServer
。注意这里:
clientSocket = echoServer.accept();
is = new DataInputStream(clientSocket.getInputStream());
os = new PrintStream(clientSocket.getOutputStream());
// As long as we receive data, echo that data back to the client.
line = is.readLine();
os.println(line);
os.close();
is.close();
可以看到,这个EchoServer
只accept一次客户连接,然后就主动关闭和客户端的连接,并退出了。我们可以执行起来这个server:
然后使用telnet进行请求:
此时可以看到EchoServer
也已经关闭:
使用Wireshark查看协议包的流程:
注意到第53号packet,从端口号可以看出,是服务端主动向客户端发起的关闭连接请求。
如果我们从EchoServer
里面去掉这两行:
os.close();
is.close();
然后把服务端的读取客户端逻辑代码调整如下:
while (true) {
line = is.readLine();
os.println(line);
}
可以看到上面的代码会让服务端进入一个无限循环,不断读入客户端的请求。当然这个Server不是多线程或异步式的,因此它只能接受一个连接请求。
调整好代码后重新启动服务器:
然后使用telnet
进行请求:
可以看到服务端会持续echo客户端发来的数据,并且服务端不再主动退出连接。
此时我们可以让客户端主动关闭连接:
此时查看服务端:
可以看到服务端还在循环里没有退出,但此时已经不再能接受客户端新的请求了:
如果我们查看协议包,可以看到这次是客户端主动发起的关闭连接请求:
注意上面蓝色高亮现实的1386号packet。从端口号可以看出,是客户端主动发起的关闭请求。
实际上上面的这种场景就是”长连接”,但是为了让服务端能够妥善地退出循环,客户端需要与服务端约定一个协议,比如客户端发送一个命令数据给服务端,告知自己要关闭连接了,这样服务端好知道关掉连接。
这个话题展开讲会很大,包括服务端的多线程设计等等,在这篇文章就不展开了。