1. TcpClient.Connected: 属性获取截止到最后一次 I/O 操作时的 Client 套接字的连接状态。
2. TcpClient.Client.Connected: 属性获取截止到最后的 I/O 操作时 Socket 的连接状态。Connected 属性的值反映最近操作时的连接状态。 如果您需要确定连接的当前状态,请进行非阻止、零字节的 Send 调用。 如果该调用成功返回或引发 WAEWOULDBLOCK 错误代码 (10035),则该套接字仍然处于连接状态;否则,该套接字不再处于连接状态。(MSDN上还有一段代码)
3. TcpClient.Available: 如果远程主机处于关机状态或关闭了连接,Available 可能会引发 SocketException。
4. TcpClient.Client.Available: 如果远程主机处于关机状态或关闭了连接,则 Available 会引发 SocketException。
5. Socket.Poll: http://msdn.microsoft.com/zh-cn/library/vstudio/system.net.sockets.socket.poll(v=vs.100).aspx (主要看Mode为SelectRead时Poll的返回值)
6. 有网友提供如下方法:
2. TcpClient.Client.Connected: 属性获取截止到最后的 I/O 操作时 Socket 的连接状态。Connected 属性的值反映最近操作时的连接状态。 如果您需要确定连接的当前状态,请进行非阻止、零字节的 Send 调用。 如果该调用成功返回或引发 WAEWOULDBLOCK 错误代码 (10035),则该套接字仍然处于连接状态;否则,该套接字不再处于连接状态。(MSDN上还有一段代码)
3. TcpClient.Available: 如果远程主机处于关机状态或关闭了连接,Available 可能会引发 SocketException。
4. TcpClient.Client.Available: 如果远程主机处于关机状态或关闭了连接,则 Available 会引发 SocketException。
5. Socket.Poll: http://msdn.microsoft.com/zh-cn/library/vstudio/system.net.sockets.socket.poll(v=vs.100).aspx (主要看Mode为SelectRead时Poll的返回值)
6. 有网友提供如下方法:
if (s.Poll(-1, SelectMode.SelectRead))
{
int nRead = s.Receive();
if (nRead == 0)
{
//socket连接已断开
}
}
接关闭软件! 不能检测出对方断开连接(tcpClient.Close)!
2. 根据TcpClient.Client.Available后面的说明做验证,发现当对方关闭了连接后获取Available还是不回引发异常!
3. 经测试,上述网友提供的方法倒是可以检测 物理网络不通、对方关闭套接字 !但是网上有人说,即使网络正常nRead也可能为0!这种情况我还没有遇到过
2. 根据TcpClient.Client.Available后面的说明做验证,发现当对方关闭了连接后获取Available还是不回引发异常!
3. 经测试,上述网友提供的方法倒是可以检测 物理网络不通、对方关闭套接字 !但是网上有人说,即使网络正常nRead也可能为0!这种情况我还没有遇到过
不知道Client端已經不存在了, 笨笨的繼續傳遞資料給Client(是我笨吧…Orz)
當然會導致程式發生Exception……….
Server真的會不知道嗎~~會他當然會知道 但是預設為兩小時後[1]~這早就發生Exception…
經過[1]中發現, 原來可以設定
Keep-Alive來保持Socket長連接, 並且偵測網路異常拋出Exception
當Client端發生不正常斷線時, Server端將會立刻知道~~~
Keep-Alive使用方法寫在Comment裡嚕~ 這裡紀錄一下
using
System.Net.Sockets;
using
System.Net;
public
class
ServerSocketObject
{
public
Socket ClientToServerSocket;
private
Socket ListenSocket;
private
IPEndPoint ServerIPEndPoint;
public
ManualResetEvent BeginAccpetControl=
new
ManualResetEvent(
false
);
//==========================
private
Boolean IsBeginAccept =
true
;
public
List<
byte
> Reply_Message =
new
List<
byte
>();
public
ServerSocketObject()
{
string
LocalIP = Dns.GetHostByName(Dns.GetHostName()).AddressList[0].ToString();
ServerIPEndPoint =
new
IPEndPoint(IPAddress.Parse(LocalIP), 2266);
ListenSocket =
new
Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
ListenSocket.Bind(ServerIPEndPoint);
ListenSocket.Listen(1);
//ip pool 設為 1
ListenSocket.IOControl(IOControlCode.KeepAliveValues, KeepAlive(1, 1000, 1000),
null
);
//將這個Socket使用<b style="background: rgb(255, 102, 255); color: rgb(0, 0, 0);">keep</b>-alive來保持長連線
//KeepAlive函數參數說明: onOff:是否開啟<b style="background: rgb(255, 102, 255); color: rgb(0, 0, 0);">Keep</b>-Alive(開 1/ 關 0) ,
//keepAliveTime:當開啟<b style="background: rgb(255, 102, 255); color: rgb(0, 0, 0);">keep</b>-Alive後經過多久時間(ms)開啟偵測
//keepAliveInterval: 多久偵測一次(ms)
}
private
byte
[] KeepAlive(
int
onOff,
int
keepAliveTime,
int
keepAliveInterval)
{
byte
[] buffer =
new
byte
[12];
BitConverter.GetBytes(onOff).CopyTo(buffer, 0);
BitConverter.GetBytes(keepAliveTime).CopyTo(buffer, 4);
BitConverter.GetBytes(keepAliveInterval).CopyTo(buffer, 8);
return
buffer;
}
public
void
BeginAccept()
{
while
(IsBeginAccept)
{
BeginAccpetControl.Reset();
ListenSocket.BeginAccept(
new
AsyncCallback(BeginAcceptCallBack), ListenSocket);
BeginAccpetControl.WaitOne();
//等待Clinet...
}
//===================
}
private
void
BeginAcceptCallBack(IAsyncResult state)
{
Socket Listener = (Socket)state.AsyncState;
ClientToServerSocket = Listener.EndAccept(state);
//Client連線成功
ClientToServerSocket.BeginReceive(buffer, 0, BufferSize, 0,
new
AsyncCallback(ReceivedCallBack), ClientToServerSocket);
//連線成功後 開始接收Server所傳遞的資料
BeginAccpetControl.Set();
}
private
void
ReceivedCallBack(IAsyncResult ar)
{
Socket state = (Socket)ar.AsyncState;
if
(state.Connected ==
true
)
{
try
{
int
bytesRead = state.EndReceive(ar);
if
(bytesRead > 0)
//當 bytesRead大於0時表示Server傳遞資料過來 等於0時代表Client"正常"斷線
{
for
(
int
num = 0; num < bytesRead; num++)
{
Reply_Message.Add(buffer[num]);
//收集資料
}
state.BeginReceive(buffer, 0, BufferSize, 0,
new
AsyncCallback(ReceivedCallBack), ClientToServerSocket);
}
else
{
//處理Client端"正常"斷線的事件
}
}
catch
(Exception ee)
{
//這裡就是當設定好<b style="background: rgb(255, 102, 255); color: rgb(0, 0, 0);">Keep</b>-alive後, 假設Clinet端發生"不正常斷線(網路異常)"時, 將會
//跑進來這個Exception裡,再加以處理
state.Shutdown(SocketShutdown.Both);
state.Close();
}
}
else
{
IsConntect =
false
;
state.Close();
}
}
}
|