Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 使用Indy的全局、线程安全的Cookie manager_Multithreading_Delphi_Delphi 2010_Indy - Fatal编程技术网

Multithreading 使用Indy的全局、线程安全的Cookie manager

Multithreading 使用Indy的全局、线程安全的Cookie manager,multithreading,delphi,delphi-2010,indy,Multithreading,Delphi,Delphi 2010,Indy,我的Delphi 2010应用程序使用多线程上传内容,上传的数据发布到需要登录的PHP/web应用程序,因此我需要使用共享/全局cookie管理器(我使用的是Indy10修订版4743),因为TIdCookieManager不是线程安全的:( 此外,服务器端会话id每5分钟自动重新生成一次,因此我必须保持全局和本地cookie管理器同步 我的代码如下所示: TUploadThread = class(TThread) // ... var GlobalCookieManager : TI

我的Delphi 2010应用程序使用多线程上传内容,上传的数据发布到需要登录的PHP/web应用程序,因此我需要使用共享/全局cookie管理器(我使用的是Indy10修订版4743),因为TIdCookieManager不是线程安全的:(

此外,服务器端会话id每5分钟自动重新生成一次,因此我必须保持全局和本地cookie管理器同步

我的代码如下所示:

TUploadThread = class(TThread)
// ...

var
   GlobalCookieManager : TIdCookieManager;

procedure TUploadThread.Upload(FileName : String);
var
   IdHTTP           : TIdHTTP;
   TheSSL           : TIdSSLIOHandlerSocketOpenSSL;
   TheCompressor    : TIdCompressorZLib;
   TheCookieManager : TIdCookieManager;
   AStream          : TIdMultipartFormDataStream;
begin
     ACookieManager := TIdCookieManager.Create(IdHTTP);

     // Automatically sync cookies between local & global Cookie managers
     @TheCookieManager.OnNewCookie := pPointer(Cardinal(pPointer( procedure(ASender : TObject; ACookie : TIdCookie; var VAccept : Boolean)
     begin
          OmniLock.Acquire;
          try
             GlobalCookieManager.CookieCollection.AddCookie(ACookie, TIdHTTP(TIdCookieManager(ASender).Owner).URL{IdHTTP.URL});
          finally
                  OmniLock.Release;
          end;    // try/finally

          VAccept := True;
     end )^ ) + $0C)^;
     // ======================================== //


     IdHTTP         := TIdHTTP.Create(nil);
     with IdHTTP do
     begin
          HTTPOptions     := [hoForceEncodeParams, hoNoParseMetaHTTPEquiv];
          AllowCookies    := True;
          HandleRedirects := True;
          ProtocolVersion := pv1_1;

          IOHandler       := TheSSL;
          Compressor      := TheCompressor;
          CookieManager   := TheCookieManager;
     end;    // with

     OmniLock.Acquire;
     try
        // Load login info/cookies
        TheCookieManager.CookieCollection.AddCookies(GlobalCookieManager.CookieCollection);
     finally
            OmniLock.Release;
     end;    // try/finally

     AStream         := TIdMultipartFormDataStream.Create;

     with Stream.AddFile('file_name', FileName, 'application/octet-stream') do
     begin
          HeaderCharset  := 'utf-8';
          HeaderEncoding := '8';
     end;    // with

     IdHTTP.Post('https://www.domain.com/post.php', AStream);
     AStream.Free;
end;
procedure TUploadThread.Upload(FileName : String); 
var 
  IdHTTP           : TIdHTTP; 
  TheSSL           : TIdSSLIOHandlerSocketOpenSSL; 
  TheCompressor    : TIdCompressorZLib; 
  TheCookieManager : TIdCookieManager; 
  TheStream        : TIdMultipartFormDataStream; 
begin 
  IdHTTP := TIdHTTP.Create(nil); 
  try
    ...
    TheCookieManager := TIdCookieManager.Create(IdHTTP); 
    TheCookieManager.OnNewCookie := NewCookie;

    with IdHTTP do 
    begin 
      HTTPOptions     := [hoForceEncodeParams, hoNoParseMetaHTTPEquiv]; 
      AllowCookies    := True; 
      HandleRedirects := True; 
      ProtocolVersion := pv1_1; 

      IOHandler       := TheSSL; 
      Compressor      := TheCompressor; 
      CookieManager   := TheCookieManager; 
    end;    // with 

    OmniLock.Acquire; 
    try 
      // Load login info/cookies 
      TheCookieManager.CookieCollection.AddCookies(GlobalCookieManager.CookieCollection); 
    finally 
      OmniLock.Release; 
    end;

    TheStream := TIdMultipartFormDataStream.Create; 
    try
      with TheStream.AddFile('file_name', FileName, 'application/octet-stream') do 
      begin 
        HeaderCharset  := 'utf-8'; 
        HeaderEncoding := '8'; 
      end;

      IdHTTP.Post('https://www.domain.com/post.php', TheStream); 
    finally
      TheStream.Free; 
    end;
  finally
    IdHTTP.Free;
  end;
end; 
但它不起作用!我在调用AddCookies()时遇到此异常

Project MyEXE.exe引发异常类EAccessViolation,并显示消息 '地址00000000处的访问冲突。读取地址00000000'

我还尝试使用assign(),即

但我仍然得到同样的例外,通常在这里:

 TIdCookieManager.GenerateClientCookies()

有人知道如何解决这个问题吗?

如果让我猜的话,我会说你的问题就在这里的某个地方:

 // Automatically sync cookies between local & global Cookie managers
 @TheCookieManager.OnNewCookie := pPointer(Cardinal(pPointer( procedure(ASender : TObject; ACookie : TIdCookie; var VAccept : Boolean)
 begin
      OmniLock.Acquire;
      try
         GlobalCookieManager.CookieCollection.AddCookie(ACookie, TIdHTTP(TIdCookieManager(ASender).Owner).URL{IdHTTP.URL});
      finally
              OmniLock.Release;
      end;    // try/finally

      VAccept := True;
 end )^ ) + $0C)^;
我不确定
$0C
这个神奇的数字是用来做什么的,但我敢打赌所有这些类型转换都在那里,因为你花了很长时间让编译器接受它。它会给你输入错误,说你不能将一个东西分配给另一个


这些类型错误的存在是有原因的!如果你在类型系统中胡乱操作,很可能会出现问题。尝试将该匿名方法转换为TUploadThread上的普通方法,并以这种方式分配它,看看它是否工作得更好。

不要对
OnNewCookie
事件使用匿名过程。使用普通方法类方法:

procedure TUploadThread.NewCookie(ASender: TObject; ACookie : TIdCookie; var VAccept : Boolean);
var
  LCookie: TIdCookie;
begin
  LCookie := TIdCookieClass(ACookie.ClassType).Create;
  LCookie.Assign(ACookie);
  OmniLock.Acquire; 
  try 
    GlobalCookieManager.CookieCollection.AddCookie(LCookie, TIdHTTP(TIdCookieManager(ASender).Owner).URL); 
  finally 
    OmniLock.Release; 
  end;
  VAccept := True;
end;
或:

然后像这样使用它:

TUploadThread = class(TThread)
// ...

var
   GlobalCookieManager : TIdCookieManager;

procedure TUploadThread.Upload(FileName : String);
var
   IdHTTP           : TIdHTTP;
   TheSSL           : TIdSSLIOHandlerSocketOpenSSL;
   TheCompressor    : TIdCompressorZLib;
   TheCookieManager : TIdCookieManager;
   AStream          : TIdMultipartFormDataStream;
begin
     ACookieManager := TIdCookieManager.Create(IdHTTP);

     // Automatically sync cookies between local & global Cookie managers
     @TheCookieManager.OnNewCookie := pPointer(Cardinal(pPointer( procedure(ASender : TObject; ACookie : TIdCookie; var VAccept : Boolean)
     begin
          OmniLock.Acquire;
          try
             GlobalCookieManager.CookieCollection.AddCookie(ACookie, TIdHTTP(TIdCookieManager(ASender).Owner).URL{IdHTTP.URL});
          finally
                  OmniLock.Release;
          end;    // try/finally

          VAccept := True;
     end )^ ) + $0C)^;
     // ======================================== //


     IdHTTP         := TIdHTTP.Create(nil);
     with IdHTTP do
     begin
          HTTPOptions     := [hoForceEncodeParams, hoNoParseMetaHTTPEquiv];
          AllowCookies    := True;
          HandleRedirects := True;
          ProtocolVersion := pv1_1;

          IOHandler       := TheSSL;
          Compressor      := TheCompressor;
          CookieManager   := TheCookieManager;
     end;    // with

     OmniLock.Acquire;
     try
        // Load login info/cookies
        TheCookieManager.CookieCollection.AddCookies(GlobalCookieManager.CookieCollection);
     finally
            OmniLock.Release;
     end;    // try/finally

     AStream         := TIdMultipartFormDataStream.Create;

     with Stream.AddFile('file_name', FileName, 'application/octet-stream') do
     begin
          HeaderCharset  := 'utf-8';
          HeaderEncoding := '8';
     end;    // with

     IdHTTP.Post('https://www.domain.com/post.php', AStream);
     AStream.Free;
end;
procedure TUploadThread.Upload(FileName : String); 
var 
  IdHTTP           : TIdHTTP; 
  TheSSL           : TIdSSLIOHandlerSocketOpenSSL; 
  TheCompressor    : TIdCompressorZLib; 
  TheCookieManager : TIdCookieManager; 
  TheStream        : TIdMultipartFormDataStream; 
begin 
  IdHTTP := TIdHTTP.Create(nil); 
  try
    ...
    TheCookieManager := TIdCookieManager.Create(IdHTTP); 
    TheCookieManager.OnNewCookie := NewCookie;

    with IdHTTP do 
    begin 
      HTTPOptions     := [hoForceEncodeParams, hoNoParseMetaHTTPEquiv]; 
      AllowCookies    := True; 
      HandleRedirects := True; 
      ProtocolVersion := pv1_1; 

      IOHandler       := TheSSL; 
      Compressor      := TheCompressor; 
      CookieManager   := TheCookieManager; 
    end;    // with 

    OmniLock.Acquire; 
    try 
      // Load login info/cookies 
      TheCookieManager.CookieCollection.AddCookies(GlobalCookieManager.CookieCollection); 
    finally 
      OmniLock.Release; 
    end;

    TheStream := TIdMultipartFormDataStream.Create; 
    try
      with TheStream.AddFile('file_name', FileName, 'application/octet-stream') do 
      begin 
        HeaderCharset  := 'utf-8'; 
        HeaderEncoding := '8'; 
      end;

      IdHTTP.Post('https://www.domain.com/post.php', TheStream); 
    finally
      TheStream.Free; 
    end;
  finally
    IdHTTP.Free;
  end;
end; 

对评论作出答复:


谢谢你们,我改成了一种普通的方法,但我仍然在学习 AddCookies()中的异常,最后一个发生在读取 在此过程中,FRWLock.BeginWrite TIdCookies.LockCookieList(AAccessType:TIdCookieAccess): 潮汐学家

如果您的错误是读取地址00000000时发生的访问冲突,这有一个非常特殊的含义。这意味着您试图对为零的对象执行某些操作


当你得到它时,转到调试器。如果错误发生在你所说的那一行,那么几乎可以肯定,
Self
FRWLock
此时是nil。检查这两个变量,找出哪一个还没有被构造,这将为你指明解决方案。

你到底在用OnNewCookie赋值做什么?当我看到围绕匿名方法的多层指针强制转换,以类似
end)^)+$0C)^的结尾
,我有点紧张。我同意这不是最好的代码,但正如我在代码中所写的,OnNewCookie可以保持本地和全局Cookie管理器同步(据我所知,问题不在于OnNewCookie事件),我同意@MasonWheeler。
OnNewCookie
事件需要对象实例的非静态方法,而不是匿名过程
TIdCookieManager
将向事件处理程序传递一个隐藏的
Self
指针,但您的匿名参数没有考虑到这一点,因此其余的事件参数将被弄乱。谢谢大家,我已转换为普通方法,但在AddCookies()中仍会出现异常,最后一个发生在读取
FRWLock.BeginWrite的行中TIdCookies.LockCookieList(AAccessType:TIdCookieAccess):TIdCookieList在哪里实例化和释放
GlobalCokieManager
对象?由于它在全球范围内使用,您应该在单元的
初始化
终结
块中执行此操作。谢谢Mason,请参阅Thank you Remy,但我仍然有相同的问题…请参阅
AddCookie()
获得传递给它的cookie的所有权。因此,最终将有多个
TIdCookieManager
对象引用相同的物理cookie对象。这会导致饼干被扔掉。我看到了两种可能的解决方案:使用
OnNewCookie
调用
AddCookie()
而不是直接调用
ACookie
,或者调用
AddServerCookie(ACookie.ServerCookie)
而不是
AddCookie()
,最有可能的是
globalcokiemanager
对象在使用之前没有被实例化。