最近在作項目的時候,遇到這樣一個問題,如何判斷 Socket 遠程端鏈接是否關閉,若是關閉的話,就要重建鏈接Socket的類提供了一些已經封裝好的方法, 如 isClosed()、isConnected()、isInputStreamShutdown()、isOutputStreamShutdown()等,在測試時發現,這些方法都是本地端的狀態,沒法判斷遠端是否已經斷開鏈接。java
其實在socket類中有一個方法sendUrgentData,它會往輸出流發送一個字節的數據,只要對方Socket的SO_OOBINLINE屬性沒有打開,就會自動捨棄這個字節(在Java 中是拋出異常),而SO_OOBINLINE屬性默認狀況下就是關閉的。服務器
如下是示例代碼僅供參考:socket
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
public
class
Nksocket
extends
Thread{
public
String ip=
null
;
//鏈接服務器的IP
public
Integer port=
null
;
//鏈接服務器的端口
private
Socket socket=
null
;
//套節字對象
private
boolean
close =
false
;
// 關閉鏈接標誌位,true表示關閉,false表示鏈接
private
Integer sotimeout=
1
*
1
*
10
;
//超時時間,以毫秒爲單位
//------------------------------------------------------------------------------
public
Nksocket(){
init();
}
public
Nksocket(String ip,Integer port){
setIp(ip);
setPort(port);
init();
}
/**
* 初始化socket對象
*/
public
void
init(){
try
{
InetAddress address = InetAddress.getByName(getIp());
socket =
new
Socket(address,getPort());
socket.setKeepAlive(
true
);
//開啓保持活動狀態的套接字
socket.setSoTimeout(sotimeout);
//設置超時時間
close=!Send(socket,
"2"
);
//發送初始數據,發送成功則表示已經鏈接上,發送失敗表示已經斷開
}
catch
(UnknownHostException e) {
e.printStackTrace();
}
catch
(IOException e){
e.printStackTrace();
}
}
/**
* 讀數據線程
*/
public
void
run() {
while
(
true
){
//---------讀數據---------------------------
close = isServerClose(socket);
//判斷是否斷開
if
(!close){
//沒有斷開,開始讀數據
String readtext = ReadText(socket);
if
(readtext!=
null
&& readtext.trim().length()>
0
){
System.out.println(
"讀取數據:"
+readtext);
}
}
//---------建立鏈接-------------------------
while
(close){
//已經斷開,從新創建鏈接
try
{
System.out.println(
"從新創建鏈接:"
+getIp()+
":"
+getPort());
InetAddress address = InetAddress.getByName(getIp());
socket =
new
Socket(address,getPort());
socket.setKeepAlive(
true
);
socket.setSoTimeout(sotimeout);
close = !Send(socket,
"2"
);
System.out.println(
"創建鏈接成功:"
+getIp()+
":"
+getPort());
}
catch
(Exception se){
System.out.println(
"建立鏈接失敗:"
+getIp()+
":"
+getPort());
close=
true
;
}
}
}
}
/**
* 發送數據,發送失敗返回false,發送成功返回true
* @param csocket
* @param message
* @return
*/
public
Boolean Send(Socket csocket,String message){
try
{
PrintWriter out =
new
PrintWriter(socket.getOutputStream(),
true
);
out.println(message);
return
true
;
}
catch
(Exception se){
se.printStackTrace();
return
false
;
}
}
/**
* 讀取數據,返回字符串類型
* @param csocket
* @return
*/
public
String ReadText(Socket csocket){
try
{
csocket.setSoTimeout(sotimeout);
InputStream input = csocket.getInputStream();
BufferedReader in =
new
BufferedReader(
new
InputStreamReader(input));
char
[] sn =
new
char
[
1000
];
in.read(sn);
String sc =
new
String(sn);
return
sc;
}
catch
(IOException se){
return
null
;
}
}
/**
* 判斷是否斷開鏈接,斷開返回true,沒有返回false
* @param socket
* @return
*/
public
Boolean isServerClose(Socket socket){
try
{
socket.sendUrgentData(
0xFF
);
//發送1個字節的緊急數據,默認狀況下,服務器端沒有開啓緊急數據處理,不影響正常通訊
return
false
;
}
catch
(Exception se){
return
true
;
}
}
/**
* 測試
* @param ags
*/
public
static
void
main(String[] ags){
Nksocket nksocket =
new
Nksocket(
"127.0.0.1"
,
8090
);
nksocket.start();
}
//------------------------------------------------------------------------------
public
String getIp() {
return
ip;
}
public
void
setIp(String ip) {
this
.ip = ip;
}
public
Integer getPort() {
return
port;
}
public
void
setPort(Integer port) {
this
.port = port;
}
}
|
參考資料:測試
http://blog.csdn.net/xyz_lmn/article/details/6146749this
http://ivan4126.blog.163.com/blog/static/20949109220135284278806/spa