[英]Mutex implementation within IIS async controller action?
我编写了一个 Web 服务,它是一个托管在 IIS 中的 Asp.Net MVC 应用程序。 来自 Web 服务的数据不是从数据库中检索的,而是从通过 TCP 访问的另一台服务器检索的。 我们将其称为数据服务器。 Web 服务可以连接到多个数据服务器。
为便于讨论,用户通过指定用户名和密码进行身份验证,然后使用适当的数据服务器创建带有套接字的“会话”。 假设一切正常 - 我们保持 Socket 处于活动状态并向用户传递标识他们所属会话的令牌。
对于每个套接字,我需要防止流量相互中断。 我认为最好的方法是以序列化的方式在 Socket 上运行网络流量。 我通过使用锁实现了这一点。 我在此数据服务器上执行查询的代码如下。 我遇到的问题是,有时我会遇到两个冲突的查询,一个可能会挂起。 我看到一个查询进来,但看起来它卡在了锁上。 IIS 异步调用的锁定机制是否安全? 是否有我可以插入的工具来确保这实际上是错误? 我一直在寻找一段时间,但找不到针对此特定场景的指导。
private async Task<string> query(string request, AbstractPermission context = null, bool bUpdateDateTime = true)
{
try
{
string reply = "";
isErrorMsg = false;
//this lock prevents the keep alive thread from coming in here while we're on the socket
lock (socketLock)
{
sendDone.Reset();
receiveDone.Reset();
// Send test data to the remote device.
Send(Socket, request);
sendDone.WaitOne();
// Receive the response from the remote device.
Receive(Socket);
receiveDone.WaitOne();
reply = QueryResponse;
} //done reading - let's unlock
if (bUpdateDateTime)
{
this.LastUsed = DateTime.Now;
}
return QueryResponse;
}
catch (Exception e)
{
throw e;
}
}
private void Send(Socket client, String data)
{
byte[] byteData = Encoding.ASCII.GetBytes(data);
client.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), client);
}
private void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = client.EndSend(ar);
// Signal that all bytes have been sent.
sendDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void Receive(Socket client)
{
try
{
// Create the state object.
StateObject state = new StateObject();
state.workSocket = client;
state.PostInitialRead = false;
// Begin receiving the data from the remote device.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, SocketFlags.None,
new AsyncCallback(ReceiveCallback), state);
}
catch (Exception e)
{
LogError(e);
}
}
private void ReceiveCallback(IAsyncResult ar)
{
try
{
// Retrieve the state object and the client socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
bool PostInitialRead = state.PostInitialRead;
// Read data from the remote device.
int bytesRead = client.EndReceive(ar);
//
//
var thisBatch = Encoding.ASCII.GetString(state.buffer, 0, bytesRead);
var endIdx = thisBatch.IndexOf('\x04');
if (!PostInitialRead)
{
if (bytesRead == 0)
throw new ApplicationException("Timeout waiting for response");
if (endIdx != -1)
{
thisBatch = thisBatch.Substring(0, endIdx);
}
if (state.buffer[0] != 0)
{
thisBatch = thisBatch.Substring(1, state.buffer[0]);
isErrorMsg = true;
}
else if (state.buffer[1] != 0)
{
thisBatch = thisBatch.Substring(2);
isErrorMsg = true;
}
else
{
thisBatch = thisBatch.Substring(2);
}
state.sb.Append(thisBatch);
state.PostInitialRead = true;
}
else
{
state.ms.Write(state.buffer, 0, endIdx!=-1?endIdx:bytesRead);
}
if (endIdx != -1)
{
// Got everything
state.sb.Append(Encoding.ASCII.GetString(state.ms.ToArray()));
QueryResponse = state.sb.ToString();
receiveDone.Set();
return;
}
else
{
// Get the rest of the data.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
1:在 IIS 中托管这样的东西是完全荒谬的吗?
不。看,dotnetcore 和现代开发使用基于 WebSockets 的 SignalR 来处理类似的事情 - 它托管在 IIS 中,所以它并不完全荒谬。
2:我们不能真正回答那个。 IO 部分是微不足道的 - IIS 可以处理这个。 但是没有关于数据服务器的详细信息 - 不知道。 您通常希望尽可能避免锁定,但这并不意味着完全。 MRSV (multiple Reader, Single Writer),写时复制等可以帮助最小化写,但最后你需要一些锁定。 调试这个并不有趣,但这就是人们所做的得到大笔报酬的事情。
一般应用程序通过将锁定卸载到后端的数据库来避免所有这些 - 许多人花费大量时间优化数据锁定。 如果您不能这样做(请记住,我们根本不知道您的数据服务器在内部做什么)- 欢迎使用硬编程。
调试的最佳机会是尝试找到一个重现案例,然后 - 当它被卡住时 - 附加一个调试器。 像这样的东西很难调试 - 但同样,这就像常规编程的最高级别(忽略某些硬件和非常特殊的任务)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.