尽管TCP和UDP都使用相同的网络层(IP),TCP却向应用层提供与UDP完全不同的服务。
TCP提供一种面向连接的、可靠的字节流服务。
TCP协议介绍
面向连接意味着两个使用 TCP的应用(通常是一个客户和一个服务器)在彼此交换数据之前必须先建立一个TCP连接。这一过程与打电话很相似,先拨号振铃,等待对方摘机说“喂”,然后才说明是谁。
TCP提供的连接是可靠的,TCP通过超时重发、接收确认、全体检验和、重排序和丢弃重复等手段,在不可靠的网络层的IP协议基础上实现了可靠的传输。
TCP的长连接
在TCP的协议里面的描述,连接一旦建立起来,如果不主动发送FIN信号,这个通道会一直保留。并且,结束还需要四次握手才能彻底拆除当前的TCP通道。
上面的一切都是建立在理想情况下,TCP的协议规定。实际情况往往十分复杂,比如网络的突然中断,设备突然断电等等,这些都会导致TCP的非正常中断,所以在实际的应用当中,判定当前TCP的连接状态显得十分的重要。
通过Socket API判定连接状态
在实际的变成当中,TCP连接的实现一般都是采用的Socket的方式实现。关于这方面的知识我不做过多的介绍。大家可以参阅相关的资料。随便一搜都是大把的资料
JAVA的Socket类当中并没有提供直接的接口,用于判定当前的连接状态。
1、isConected(),主要用于判定你是否成功连接过,如果你最近成功连接上,那么就会返回 true 。而当前的连接可能因为某些原因,已经中断了。
2、isClosed(), 这个接口仅仅能判定你是否关闭了这个Socket,只要你不关闭Socket,一直会返回false。
上面这两个方法都不能确定,当前的TCP连接的状态。
那么我们应该如何判定当前的通道状态呢?其实有一个简单的方法,那就是发送一些数据,如果能够发送成功就说明当前的连接没有问题。这是最直接,同时也是我们最常使用的一种方法。
不管因为什么原因,导致当前通道中断,Socket的写操作都会抛出一个IOExeption,使用读的方式同样能达到相同的效果。
这样就可以在捕获了的异常里面进行TCP通道的重建操作。
不给代码的行为都是耍流氓。下面给出Client端的代码。
/**
* Created by Kiplening 3/9/2016.
*/
public class Client {
public static void main(String[] args) {
Socket socket = null;
try {
socket = new Socket("192.168.1.129", 8000);
} catch (IOException e) {
e.printStackTrace();
}
OutputStream os = null;
try {
os = socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
while (true){
BufferedReader reader = new BufferedReader(
new InputStreamReader(System.in));
String line = null;
try {
line = reader.readLine();
} catch (IOException e) {
e.printStackTrace();
}
try {
os.write(line.getBytes());
} catch (IOException e) {
System.out.println("连接中断!尝试重连。。。");
//todo: 重连操作
//e.printStackTrace();
}
}
}
}
代码测试结果
在双端正常工作时,可在客户端输入内容发送。一旦服务器断网,或者关掉服务程序。此时只要不发送内容,整个程序没有任何异常,一旦发送内容,便会抛出IOExcption。提示你重新建立连接。
关于上面提到的isConnected()和isClosed()方法的测试我就不做了,大家可以自己去验证下。
StackOverflow