繁体   English   中英

IIS 异步控制器操作中的互斥体实现?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM