zoukankan      html  css  js  c++  java
  • FireDAC 接占线导致另一个 hstmt DataSnap

    [FireDAC][Phys][ODBC][Microsoft][ODBC SQL Server Driver]连接占线导致另一个 hstmt

    同样的程序,在2台win10 正常,1台win10 报连接占线!

    SQL Native Client  安装客户端

    原因2:存储过程返回有2个结果集,在获取第2个结果集之前执行其他sql 也会引起连接占线

    原因3:存储过程返回的数据,cachUpdate=true,利用缓存巧妙的修改数据,出报表,未保存之前,执行别的sql也会引起连接占线,把返回的存储过程的数据集赋值给到FDmemtable里就好了,在FDmemtable里修改。报表从FDmemtable取数据。

    TFDStoredProc

    FetchOptions.Mode

    fmOnDemand

    fmAll

    2018.10.9 fixed 方法是

    页面的create事件里,所有的FDQuery,FDTable的FetchOptions->Mode = fmAll 就好了。

    FDQuery3->FetchOptions->Mode = fmAll;

     2018.12.19

    还有一个原因是

    存储过程调用execProc;但是存储过程有返回值,存储过程里有select a,b 返回结果集。

    修改存储过程为没有没有结果集,或者改为 OpenProc的调用方法即可。

    建立了DataSnap服务器,数据连接用FireDAC  FDConnection1。

    什么原因?FDConnection1在应用服务器的TDataModule放着,难度要用TRemoteDataModule?

    FDConnection1要在ServerMethods1窗体上,不能在TDataModule上放。ServerMethods1具有多线程多用户实例的功能。不同的连接普通的DataModule自然无此功能。

    一个连接触发事件顺序:DSTCPServerTransport1Connect>DSServer1Connect>DSServerClass1Instance-Create>TServerMethods1DSServerModuleCreate

    DSServer1Disconnect>DSTCPServerTransport1Disconnect>DSServerClass1Instance-Destroy

    从继承关系来看,TServerContainer1就是从DataModule继承而来,所以应用服务器工程再添加DataModule就多余没有意义了。应用服务器exe启动后触发一次TServerContainer1::DataModuleCreate事件,

    应用服务器退出的时候触发TServerContainer1::DataModuleDestroy事件一次。就说明他确实和DataModule一样的作用。所有客户端连接都共享着一个TServerContainer1控件。

    但是每次客户端连接都会触发:

    DSTCPServerTransport1Connect和DSServer1Connect事件;

    DSServerClass1控件的TServerContainer1::DSServerClass1CreateInstance和TServerContainer1::DSServerClass1DestroyInstance事件。

    ServerMethodsUnit1的TServerMethods1::DSServerModuleCreate和TServerMethods1::DSServerModuleDestroy。

    可见ServerMethodsUnit1完全是线程概念,每个用户一个实例,每次连接都创建销毁。

    ServerMethods1上的FDConnection1必须独立连接,不能再共享ServerContainer1或另外创建的DataModule上的connection了。

    ServerMethods1上的方法可以共用ServerMethods1上的FDConnection1连接没有问题。

    用FDConnection1连接Datasnap服务器

    FireDAC  连接Datasnap服务端。

    DriverID=DS
    Protocol=tcp/ip
    Server=127.0.0.1
    Port=211
    User_Name=dsusr
    Password=123
    

    http://docwiki.embarcadero.com/RADStudio/Berlin/en/Connect_to_DataSnap_Server_(FireDAC)

    http://docwiki.embarcadero.com/CodeExamples/Berlin/en/DataSnap.FireDAC_Sample

    http://docwiki.embarcadero.com/CodeExamples/Berlin/en/DataSnap.FireDAC_DBX_Sample

     http://www.cnblogs.com/hnxxcxg/p/5663372.html

    DSConnectEventObject->ChannelInfo->Id

     DSConnectEventObject->ChannelInfo->Id

    Event.Channel->ChannelInfo->Id

    这几个ID是同一个值。

    DSConnectEventObject->ConnectProperties[TDBXPropertyNames::UserName]

    delphi可以去到UserName,c++builder如何去到这个宏定义UserName?Data::Dbxcommon::TDBXPropertyNames::UserName也不行。这样可以了。

    DSConnectEventObject->ConnectProperties->operator[](TDBXPropertyNames_UserName);

     which is called after TDSAuthenticationManager.OnUserAuthenticate). 需要有认证功能才可以。

    继承关系图

     DSTCPServerTransport1Connect事件中Event.Connection可以获取客户端信息

    void __fastcall TServerContainer1::DSTCPServerTransport1Connect(TDSTCPConnectEventObject &Event)
    {
    Event.Channel->ChannelInfo->Id
    Event.Channel->ChannelInfo->ClientInfo.IpAddress
    Event.Channel->ChannelInfo->ClientInfo.ClientPort

    TIdTCPConnection*con; con=(TIdTCPConnection*)Event.Connection; con->Socket->Binding->PeerIP; con->Socket->Binding->PeerPort; con->Socket->Binding->IP; con->Socket->Binding->Port;

    }

    TServerMethods1-->TDSServerModule-->TDSServerModuleBase-->TProviderDataModule-->TDataModule-->TComponent-->TPersistent-->TObject

    TServerContainer1-->TDataModule-->TComponent-->TPersistent-->TObject

    TRemoteDataModule-->TProviderDataModule-->TDataModule-->TComponent-->TPersistent-->TObject

    TDSServerClass-->TDSCustomServerClass-->TDSServerComponent-->TComponent-->TPersistent-->TObject

    TDSServer-->TDSCustomServer-->TComponent-->TPersistent-->TObject

    TDSTCPServerTransport-->TDSServerTransport-->TDSServerComponent-->TComponent-->TPersistent-->TObject

    TDSHTTPService-->TCustomDSHTTPServerTransport-->TCustomDSRESTServerTransport-->TDSServerTransport-->TDSServerComponent-->TComponent-->TPersistent-->TObject

     

    DataSnap,如果客户端异常掉线或拔掉网线,那么在服务端会留下一个TCP连接,这个连接会变成死连接(经过测试,如 果windows的TCP保持连接禁用的话,三个小时该死连接还不消失)。如果大量客户端并发,出现的死TCP连接过多,服务器内存和端口将会增加,直到 占满服务器的端口和耗尽内存为止。如果这样的话,服务器无法健壮稳定的运行。

    大家可以另开线程来监控客户端连接,但是今天要给大家讲解的不是这个方法,而是使用TCP协议自带的心跳包功能解决这个问题。

    大家先了解一下 TCP keep-alive原理

    一个TCP keep-alive 包是一个简单的ACK,该ACK包内容为一个比当前连接sequence number 小于一的包。主机接受到这些ACKs会返

    回一个包含当前sequence number 的ACK包。
    Keep-alives一般被用来验证远端连接是否有效。如果该连接上没有其 他数据被传输,或者更高level 的 keep-alives被传送,keep-alives 在每个KeepAliveTime被发送。(默认是 7,200,000 milliseconds ,也就是2个小时)。

    如果没有收到 keep-alive 应答,keep-alive 将在每 KeepAliveInterval 秒重发一次。KeepAliveInterval 默认为1秒。如 Microsoft 网络功能中很多部分中采用的 NETBT 连接,更常见的是发送 NETBios keep-alives,所以,在 NetBios 连接中通常不发送TCP keep-alives。
    TCP保持连接默认被禁用,但是微软Sockets应用程序可以使用SetSockOpt函数去启用他们。

    如果客户端网络中断,服务器系统发送心跳包后,服务器会自动解除TCP连接。这一点,大家可以使用 netstat -p -tcp 命令查看

    DataSnap 的连接事件顺序图

  • 相关阅读:
    转发和重定向的区别
    关于Daydream VR的最直白的介绍
    Duplicate Protocol Definition of DTService Is Ignored
    automatically select architectures
    java
    初识反射
    java网络编程
    Map接口
    Set,List
    正则表达式
  • 原文地址:https://www.cnblogs.com/cb168/p/4624130.html
Copyright © 2011-2022 走看看