最近在做項目的時候,遇到這樣一個問題,如何判斷 Socket 遠程端連接是否關閉,如果關閉的話,就要重建連接Socket的類提供了一些已經封裝好的方法, 如 isClosed()、isConnected()、isInputStreamShutdown()、isOutputStreamShutdown()等,在測試時發現,這些方法都是本地端的狀態,無法判斷遠端是否已經斷開連接。
其實在socket類中有一個方法sendUrgentData,它會往輸出流發送一個字節的數據,只要對方Socket的SO_OOBINLINE屬性沒有打開,就會自動舍棄這個字節(在Java 中是拋出異常),而SO_OOBINLINE屬性默認情況下就是關閉的。
以下是示例代碼僅供參考:
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/6146749
http://ivan4126.blog.163.com/blog/static/20949109220135284278806/