套接字错误后,存储的prodecude不能正常工作

时间:2016-12-12 08:23:09

标签: c# sql-server sockets stored-procedures tcplistener

我正在使用在Windows服务,.NET Framework 4.6.1,Entity Framework 6.1.3和C#上运行的TCPListener开发Socket服务器。作为数据库我正在使用SQL Server Enterprise 2012 SP 2。

我的套接字客户端上出现套接字超时后,我的数据库出现问题。每次我在客户端获得套接字超时(或任何其他问题)时,我的数据库都会出现奇怪的行为。

我有一个套接字服务器,它使用数据库存储过程来更新表:

public TcpListenerServer(int serverPort)
{
    port = serverPort;
    connectionString =
        ConfigurationManager.ConnectionStrings["DbContext"].ConnectionString;

    tcpListenerServer = null;
    codesReceived = new CodesReceived();
    lockCodesUpdate = new System.Object();
    locked = false;
}

public void InitTCPServer()
{
    // Create server.
    IPEndPoint ipAddress = new IPEndPoint(IPAddress.Any, port);
    tcpListenerServer = new TcpListener(ipAddress);

    // Create cancellation token.
    tokenSource = new CancellationTokenSource();
    token = tokenSource.Token;

    // Start the service
    tcpListenerServer.Start(5);

    // Begin an asynchronous connection attemp
    tcpListenerServer.
        BeginAcceptTcpClient(new AsyncCallback(DoAcceptTcpClientCallback),
                             tcpListenerServer);
}

public void Stop()
{
    if (tcpListenerServer != null)
        tcpListenerServer.Stop();
}

private void DoAcceptTcpClientCallback(IAsyncResult ar)
{
    TcpClient client = null;

    try
    {
        // Get the listener that handles the client request.
        TcpListener listener = (TcpListener)ar.AsyncState;

        // End the operation
        client = listener.EndAcceptTcpClient(ar);

        // Handle the data received
        Task.Run(() => { HandleCodeReceived(client, token); }, token);

        // Begin a new asynchronous connection attemp
        tcpListenerServer.
            BeginAcceptTcpClient(new AsyncCallback(DoAcceptTcpClientCallback),
                                 tcpListenerServer);
    }
    catch (SocketException ex)
    {
        log.ErrorFormat("DoAcceptTcpClientCallback socket error: {0}, Message {1}", ex.ErrorCode, ex.Message);
        Stop();
    }
    catch (ObjectDisposedException)
    {
        return;
    }
}

private void HandleCodeReceived(TcpClient client, CancellationToken token)
{
    // client could be null or not be connected when it reach this method?
    if ((client != null) && (client.Connected))
    {
        try
        {
            // Read input message.
            NetworkStream netStream = client.GetStream();

            StreamReader reader = new StreamReader(netStream);
            string messageReceived = null;

            // The while do this: read ALL the lines sent.
            while ((messageReceived = reader.ReadLine()) != null)
            {
                // If we have a valid message
                if ((!string.IsNullOrWhiteSpace(messageReceived)) &&
                    (IsValid(messageReceived)))
                {
                    // Parse message received from client.
                    ClientMessage message =
                        new ClientMessage(messageReceived);

                    // First check if code is valid.
                    if ((string.IsNullOrWhiteSpace(message.Code)) ||
                        (message.Code.Equals("0")))
                    {
                        SendBackMessage(false, client);
                    }
                    else
                    {
                        ProcessCodeReceived(client, message);
                    }
                }
                else
                    SendBackMessage(false, client);
            }
        }
        catch (Exception ex)
        {
            log.Error(ex.Message);

            SendBackMessage(false, client);
        }
    }
}

private bool IsValid(string messageReceived)
{
    string[] cadenas = messageReceived.Split(":".ToCharArray());

    return ((cadenas != null) && (cadenas.Length == 8));
}

private void ProcessCodeReceived(TcpClient client, ClientMessage message)
{
    DateTime begin = DateTime.UtcNow;

    log.DebugFormat("ReadCode: {0} - Start", message.Code);

    StoredProcedureErrors result;
    result = ReadCode(message.Code, message.Nivel);

    if (result != StoredProcedureErrors.NoError)
        log.ErrorFormat(ReadCodeErrorMsg, result, message.Code);
    else
        codesReceived.Reset();

    DateTime end = DateTime.UtcNow;

    log.DebugFormat("ReadCode: {0} - End: {1} - {2}", message.Code, (end - begin).TotalMilliseconds, result);

    SendBackMessage(result == StoredProcedureErrors.NoError, client);
}

private void SendBackMessage(bool isCorrect, TcpClient client)
{
    if (isCorrect)
        client.GetStream().Write(ASCIIEncoding.UTF8.GetBytes(CorrectMsg + Environment.NewLine), 0, 4);
    else
        client.GetStream().Write(ASCIIEncoding.UTF8.GetBytes(IncorrectMsg + Environment.NewLine), 0, 4);
}

private StoredProcedureErrors ReadCode(
    string code,
    byte aggregationlevel)
{
    StoredProcedureErrors result =
        StoredProcedures.ReadCode(
            connectionString,
            code,
            aggregationlevel,
            UserName,
            Source,
            true);

    return result;
}

运行存储过程的代码是:

public static StoredProcedureErrors ReadCode(
    string connectionString,
    string code,
    byte codeLevel,
    string param1,
    string param2,
    bool isAuto)
{
    GenericRepository<Code> repository = null;
    LDbContext dbContext = new LDbContext(connectionString);

    repository = new GenericRepository<Code>(dbContext);

    string procName = "ReadCode";

    List<SqlParameter> parameters = null;
    SqlParameter helperCodeParam = null;

    SqlParameter codeParam = new SqlParameter();
    codeParam.ParameterName = "@code";
    codeParam.SqlDbType = System.Data.SqlDbType.NVarChar;
    codeParam.Size = 20;
    codeParam.Direction = System.Data.ParameterDirection.Input;
    codeParam.Value = code;

    [ ... ]

    parameters = new List<SqlParameter>();
    parameters.Add(codeParam);
    parameters.Add(aggregationLevelParam);
    parameters.Add(param1Param);
    parameters.Add(param2Param);
    parameters.Add(isAutoParam);

    if (helperCodeParam != null)
        parameters.Add(helperCodeParam);

    parameters.Add(returnValueParam);

    repository.Execute(procName, parameters);

    return (StoredProcedureErrors)Convert.ToInt32(returnValueParam.Value);
}

repository.Execute方法是:

public void Execute(
    string storedProcedureName,
    IEnumerable<SqlParameter> parameters)
{
    SqlConnection connection = null;

    try
    {
        connection =
            dbContext.Database.Connection as SqlConnection;
        connection.Open();

        SqlCommand cmd = new SqlCommand();

        cmd.CommandText = storedProcedureName;
        cmd.CommandType = CommandType.StoredProcedure;

        if (parameters != null)
            cmd.Parameters.AddRange(parameters.ToArray());

        cmd.Connection = connection;

        cmd.ExecuteNonQuery();
    }
    finally
    {
        if (connection != null)
            connection.Close();
    }
}

我的问题非常奇怪:ReadCode只更新表上的一行(该表用于非常密集地添加新行并更新其他行)。我确定在存储过程结束时更新了正确的行,因为我检查了@@ERROR@@ROWCOUNT。并围绕TRY - CATCH块中的更新语句(请查看我的DB administrator question有关此问题的信息)。

但它没有更新。如果我在SQL Server Management Studio上执行选择,则它不会更新。

我的第一个问题是:

  1. 使用静态方法运行存储过程是个好主意吗?
  2. 我怎么知道发生了什么?
  3. 默认情况下EF是否使用交易?我认为由于套接字错误而导致存储过程没有结束,SqlCommand.ExecuteNonQuery会进行回滚。
  4. 99.9%的时间它完美运行,但在客户端遇到套接字错误后,它开始在数据库上做一些奇怪的事情。

    更新
    在客户端,每次我得到一个SocketException我关闭套接字并创建一个新套接字。这样做之后,我再也不会遇到数据库错误了。

    我不认为这是问题的解决方案,但我不确定问题出在哪里。

0 个答案:

没有答案