如何检测客户端是否与服务器断开连接?
我有下面的代码在我的AcceptCallBack方法
static Socket handler = null;
public static void AcceptCallback(IAsyncResult ar)
{
//Accept incoming connection
Socket listener = (Socket)ar.AsyncState;
handler = listener.EndAccept(ar);
}
Run Code Online (Sandbox Code Playgroud)
我需要找到一种方法来尽快发现客户端已从handlerSocket 断开连接.
我试过了:
handler.Available;handler.Send(new byte[1], 0,
SocketFlags.None);handler.Receive(new byte[1], 0,
SocketFlags.None);当您连接到服务器并且想要检测服务器何时断开连接但是当您是服务器并且想要检测客户端断开连接时它们不起作用时,上述方法会起作用.
任何帮助将不胜感激.
我应该如何检查(TCP)套接字以确定它是否已连接?
我已经阅读了MSDN中的Socket.Connected属性,但它说它只根据最后一个I/O显示状态.这对我没用,因为我想在尝试从套接字读取之前这样做.备注部分还指出:
如果需要确定连接的当前状态,请进行非阻塞,零字节发送调用.如果调用成功返回或抛出WAEWOULDBLOCK错误代码(10035),则套接字仍然连接; 否则,套接字不再连接.
同一页面上的示例显示了如何执行此操作.(1)但Ian Griffiths的帖子说我应该从套接字读取,而不是通过它发送.
...在你打电话之后
Shutdown(),打电话Receive()直到它返回0(假设远程端点实际上不会向你发送任何东西,一旦远程端点收到你的所有数据就会发生这种情况).除非您这样做,否则您无法保证远程端点实际上已收到您发送的所有数据,即使使用延迟套接字也是如此.
我真的不明白他关于调用Receive()以确保远程端点实际上已经收到我发送的所有数据的说法.(套接字阻塞接收,直到发送缓冲区为空?)
我对提出的不同方法感到困惑.你能解释一下吗?
(1)但不知为何,例如为Socket.Connected属性分配1字节的数组,即使它调用Send与0长度?
我有两个简单的应用程序:
等待特定tcp端口以供客户端连接的服务器应用程序.然后听他说的话,发回一些反馈并断开那个客户端.
一个表单应用程序连接到服务器应用程序,然后说出一些内容,然后等待反馈并断开与服务器的连接,然后在表单中显示反馈.
虽然服务器应用程序似乎行为正常(我已经使用Telnet对其进行了测试,并且我看到反馈并且我看到反馈后直接发生了断开连接),但表单应用程序似乎并未发现与服务器的断开连接.(即使在服务器断开连接后,TcpClient.Connected似乎也保持正常)
我的问题是:为什么TcpClient.Connected保持正确,我怎么知道服务器是否/何时断开连接?
这是我的完整代码:
表格申请:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace Sender
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void sendButton_Click(object sender, EventArgs e)
{
TcpClient tcpClient = new TcpClient();
tcpClient.Connect(IPAddress.Parse("127.0.0.1"), 81);
responseLabel.Text = "waiting for response...";
responseLabel.Invalidate();
// write request
NetworkStream networkStream = tcpClient.GetStream();
byte[] buffer = (new ASCIIEncoding()).GetBytes("Hello World! ");
networkStream.Write(buffer, 0, buffer.Length);
networkStream.Flush();
// read response
Thread readThread = …Run Code Online (Sandbox Code Playgroud) int readCount;
byte[] buffer = new byte[128];
SocketError socketError;
TcpClient tcpClient = tcpListener.AcceptTcpClient();
tcpClient.Client.ReceiveTimeout = 500; // #1
// tcpClient.Client.Connected is **true** here.
readCount = tcpClient.Client.Receive(buffer, 0, buffer.Length, SocketFlags.None, out socketError); // reacCount > 0
// tcpClient.Client.Connected is **false** here.
Run Code Online (Sandbox Code Playgroud)
如果#1被替换为tcpClient.Client.Blocking = false; ,tcpClient.Client.Connected具有正确的值(true).
我已将Socket.ReceiveTime属性设置为100并调用Socket.Receive().Receive()返回大于零的整数值.没有例外.在我使用复制缓冲区完成工作后 - 我没有使用任何与Socket相关的方法 - ,Socket.Connected属性已更改为false.为什么?
我正在编写一个小型(C#)客户端应用程序,该应用程序使用TCP / IP连接将数据发送到远程服务器。我正在使用标准的.Net TcpClient对象,并且由于我要定期向服务器提交数据包,因此希望从客户端打开连接。但是,服务器可能会关闭连接,在这种情况下,我需要在发送下一个数据包之前重新连接。
使用Wireshark,当服务器终止连接时,我只能看到以下对话框:
server >>> FIN, ACK
ACK <<< client
我所没有看到的是我的客户拥有自己的FIN响应,以完成连接关闭。结果是我的客户端程序仅在发送下一个数据包后才发现连接已断开。
有什么方法可以设置TcpClient或它的基础Socket以完成断开连接,并提供一些反馈,以便我的客户端代码在发送下一个数据包之前知道重新连接?
为了回应以下评论而添加:我的发送代码非常简单-维护TcpClient和NetworkStream成员变量的对象具有一个成员函数,该成员函数包含(基本上)以下内容:
bool sent = false;
byte[] buffer = Encoding.UTF8.GetBytes(dataString);
while (!sent)
{
try
{
m_outStream.Write(buffer, 0, buffer.Length);
sent = true;
}
catch (Exception ex)
{
if (m_outStream != null) { m_outStream.Dispose(); }
m_client = new TcpClient(AddressFamily.InterNetwork);
m_client.Connect(ipAddress, ipPort);
m_outStream = m_client.GetStream();
}
}
Run Code Online (Sandbox Code Playgroud)
初始化了m_client和m_outStream以后,每次只需执行一次传递。然后,使用Wireshark,我可以看到服务器发送了带有标志的数据包,FIN, ACK客户端对此进行了响应ACK。
下次调用函数时,数据将通过发送出去PSH, ACK,服务器将以响应RST, ACK但不读取传入的数据。客户端不会引发异常。
然后,我第二次调用函数,并引发异常,导致重新启动连接。