C# 套接字关闭:我应该在什么时候使用SocketShutdown
我认为停机顺序如下(如上所述): (备注部分)内容如下: 使用面向连接的C# 套接字关闭:我应该在什么时候使用SocketShutdown,c#,.net,sockets,berkeley-sockets,C#,.net,Sockets,Berkeley Sockets,我认为停机顺序如下(如上所述): (备注部分)内容如下: 使用面向连接的套接字时,在关闭套接字之前,请始终调用关闭方法。这样可以确保在关闭连接的套接字之前,所有数据都在该套接字上发送和接收 这似乎意味着,如果我使用Shutdown(SocketShutdown.Both),任何尚未收到的数据都可能会被消耗。要测试这一点: 我不断地向客户机发送数据(在单独的线程中通过send) 客户端执行了Shutdown(SocketShutdown.Both) 服务器上的BeginReceive回调执行,
套接字
时,在关闭套接字
之前,请始终调用关闭
方法。这样可以确保在关闭连接的套接字之前,所有数据都在该套接字上发送和接收
这似乎意味着,如果我使用Shutdown(SocketShutdown.Both)
,任何尚未收到的数据都可能会被消耗。要测试这一点:
- 我不断地向客户机发送数据(在单独的线程中通过
)send
- 客户端执行了
Shutdown(SocketShutdown.Both)
- 服务器上的
回调执行,但是,BeginReceive
引发异常:远程主机强制关闭了现有连接。这意味着我无法接收EndReceive
返回值并依次调用0
Shutdown
private TcpListener SocketListener { get; set; }
private Socket ConnectedClient { get; set; }
private bool serverShutdownRequested;
private object shutdownLock = new object();
private struct SocketState
{
public Socket socket;
public byte[] bytes;
}
private void ProcessIncoming(IAsyncResult ar)
{
var state = (SocketState)ar.AsyncState;
// Exception thrown here when client executes Shutdown:
var dataRead = state.socket.EndReceive(ar);
if (dataRead > 0)
{
state.socket.BeginReceive(state.bytes, 0, state.bytes.Length, SocketFlags.None, ProcessIncoming, state);
}
else
{
lock (shutdownLock)
{
serverShutdownRequested = true;
state.socket.Shutdown(SocketShutdown.Both);
state.socket.Close();
state.socket.Dispose();
}
}
}
private void Spam()
{
int i = 0;
while (true)
{
lock (shutdownLock)
{
if (!serverShutdownRequested)
{
try { ConnectedClient.Send(Encoding.Default.GetBytes(i.ToString())); }
catch { break; }
++i;
}
else { break; }
}
}
}
private void Listen()
{
while (true)
{
ConnectedClient = SocketListener.AcceptSocket();
var data = new SocketState();
data.bytes = new byte[1024];
data.socket = ConnectedClient;
ConnectedClient.BeginReceive(data.bytes, 0, data.bytes.Length, SocketFlags.None, ProcessIncoming, data);
serverShutdownRequested = false;
new Thread(Spam).Start();
}
}
public ServerForm()
{
InitializeComponent();
var hostEntry = Dns.GetHostEntry("localhost");
var endPoint = new IPEndPoint(hostEntry.AddressList[0], 11000);
SocketListener = new TcpListener(endPoint);
SocketListener.Start();
new Thread(Listen).Start();
}
- 客户端连接到服务器
- 客户端执行
Shutdown(SocketShutdown.Both)
- 服务器接收关机确认并发送一些数据作为响应。服务器还执行
关闭
- 客户端从服务器接收数据,但不允许下一个
:不允许发送或接收数据的请求,因为套接字已在该方向上通过上次关闭调用关闭BeginReceive
EndReceive
到Close
套接字返回一个0
值。这是否意味着我应该使用Shutdown(SocketShutdown.Send)
?如果是这样,什么时候应该使用Shutdown(SocketShutdown.Both)
第一个实验的代码:
private TcpListener SocketListener { get; set; }
private Socket ConnectedClient { get; set; }
private bool serverShutdownRequested;
private object shutdownLock = new object();
private struct SocketState
{
public Socket socket;
public byte[] bytes;
}
private void ProcessIncoming(IAsyncResult ar)
{
var state = (SocketState)ar.AsyncState;
// Exception thrown here when client executes Shutdown:
var dataRead = state.socket.EndReceive(ar);
if (dataRead > 0)
{
state.socket.BeginReceive(state.bytes, 0, state.bytes.Length, SocketFlags.None, ProcessIncoming, state);
}
else
{
lock (shutdownLock)
{
serverShutdownRequested = true;
state.socket.Shutdown(SocketShutdown.Both);
state.socket.Close();
state.socket.Dispose();
}
}
}
private void Spam()
{
int i = 0;
while (true)
{
lock (shutdownLock)
{
if (!serverShutdownRequested)
{
try { ConnectedClient.Send(Encoding.Default.GetBytes(i.ToString())); }
catch { break; }
++i;
}
else { break; }
}
}
}
private void Listen()
{
while (true)
{
ConnectedClient = SocketListener.AcceptSocket();
var data = new SocketState();
data.bytes = new byte[1024];
data.socket = ConnectedClient;
ConnectedClient.BeginReceive(data.bytes, 0, data.bytes.Length, SocketFlags.None, ProcessIncoming, data);
serverShutdownRequested = false;
new Thread(Spam).Start();
}
}
public ServerForm()
{
InitializeComponent();
var hostEntry = Dns.GetHostEntry("localhost");
var endPoint = new IPEndPoint(hostEntry.AddressList[0], 11000);
SocketListener = new TcpListener(endPoint);
SocketListener.Start();
new Thread(Listen).Start();
}
Shutdown(SocketShutdown.Both)
应在您不想接收或发送时使用。您可能想突然关闭连接,或者您知道另一方已使用SocketShutdown.Receive关闭了连接。例如,您有一个时间服务器,它将当前时间发送给连接它的客户机,服务器发送时间并调用Shutdown(SocketShutdown.Received)
,因为它不希望从客户机获得更多数据。客户端在收到时间数据时应该调用Shutdown(SocketShutdown.Both),因为它不会发送或接收任何进一步的数据 Shutdown(SocketShutdown.Both)禁用当前套接字上的发送和接收操作。调用Shutdown(SocketShutdown.Both)实际上是客户机与服务器的断开连接。您可以通过检查服务器端的SocketState对象中的socket Connected属性看到这一点:它将为false
这是因为关闭操作是不可逆的,所以在停止套接字上的发送和接收之后,没有必要保持连接,因为它是隔离的
一旦调用shutdown函数来禁用send、receive或两者,就没有方法为现有套接字连接重新启用send或receive
()
关于你的问题:
- 我不断地向客户端发送数据(通过单独的线程发送)
- 客户端执行了关机(SocketShutdown.Both)-->这会断开客户端的连接
- 服务器上的BeginReceive回调执行时,EndReceive抛出
异常:远程主机强制关闭了现有连接。这意味着
我无法接收0返回值,从而调用Shutdown
EndReceive引发异常,因为客户端套接字不再连接
要优雅地终止套接字,请执行以下操作:
客户端套接字调用Shutdown(SocketShutdown.Send)),但应继续接收
在服务器上,EndReceive返回读取的0字节(客户端表示没有来自其端的更多数据)
服务器
A) 发送其最后的数据
B) 调用Shutdown(SocketShutdown.Send))
C) 在套接字上调用Close,可以选择超时以允许从客户端读取数据
客户
A) 从服务器读取剩余数据,然后接收0字节(服务器发出信号,表示没有来自其端的更多数据)
B) 在套接字上关闭调用
()Send
在关机序列期间也返回0
。如果我更新服务器以考虑这一点,在Spam
方法中设置我的标志之前,EndReceive
仍会引发异常。我怀疑这一切都是因为CLOSE\u WAIT
socket状态不知何故被跳过。您是否找到了答案?是的,但当用户在10秒后尝试重复该操作时,您会收到错误“发送或接收数据的请求失败,因为socket已关闭”我对C语言中的套接字实现非常失望#