问题:
设计一个高效且非常快速的命名管道客户端服务器框架.
现状:
我已经有经过验证的生产测试框架.它很快,但是每个管道连接使用一个线程,如果有很多客户端,线程数可能会很快变高.我已经使用了可以根据需要扩展的智能线程池(事实上的任务池).
我已经使用OVERLAPED模式管道,但后来我使用WaitForSingleObject或WaitForMultipleObjects阻塞,这就是为什么我需要在服务器端每个连接一个线程
期望的解决方案:
客户端很好,但在服务器端,我想只为每个客户端请求使用一个线程,而不是每个连接.因此,不是在客户端的整个生命周期中使用一个线程(连接/断开连接),而是每个任务使用一个线程.所以只有当客户端请求数据而不再需要时.
我在MSDN上看到了一个使用OVERLAPED结构数组的示例,然后使用WaitForMultipleObjects等待它们全部.我发现这是一个糟糕的设计.我在这里看到两个问题.首先,你必须维护一个可以变得非常大的数组,删除将是昂贵的.其次,你有很多事件,每个阵列成员一个.
我也看到了完成端口,比如CreateIoCompletionPort和GetQueuedCompletionStatus,但是我看不出它们是如何更好的.
我想要的是ReadFileEx和WriteFileEx所做的事情,它们在操作完成时调用回调例程.这是一种真正的异步编程风格.但问题是ConnectNamedPipe不支持它,而且我看到线程需要处于警报状态,你需要调用一些*Ex函数来实现它.
那么这样的问题如何最好地解决了?
以下是MSDN的工作方式:http://msdn.microsoft.com/en-us/library/windows/desktop/aa365603(v = vs.85).aspx
我用这种方法看到的问题是,如果WaitForMultipleObjects的限制是64个句柄,我怎么看不到你可以同时连接100个客户端.当然,我可以在每次请求后断开管道,但想法是在TCP服务器中建立永久客户端连接,并在每个客户端具有唯一ID和客户端特定数据的整个生命周期中跟踪客户端.
理想的伪代码应该是这样的:
repeat
// wait for the connection or for one client to send data
Result = ConnectNamedPipe or ReadFile or Disconnect;
case Result of
CONNECTED: CreateNewClient; // we create a new client
DATA: AssignWorkerThread; // here we process client request in a thread
DISCONNECT: CleanupAndDeleteClient // release the client object …Run Code Online (Sandbox Code Playgroud) 我已经看了,找不到任何好的东西.
所以问题是,是否有任何良好的Web框架可以轻松地为大多数高端手机开发GUI?我的意思是这个
所以基本上我正在寻找像jQuery或ExtJS这样的手机开发.
编辑:
如果可以在Delphi中使用它将是一个很大的优势
编辑2:
如果不清楚,我正在寻找一个可以在浏览器中运行的网络基础解决方案.所以目标是HTML输出而不是本机代码.
我有一个问题,我不知道如何解决.
我有一个Indy10 HTTP服务器.我在许多应用程序中使用过Indy9和Indy10 HTTP服务器,从未遇到任何问题.但现在我使用带有ExtJS javascript RAI框架的Indy10 HTTP服务器.
问题是当我提交包含非ansi字符的数据时.例如,当我在1250代码页(斯洛文尼亚语,克罗地亚语......)中提交字母"č"时,我在Indy的"未解决的参数" - >"%C4%8D"中得到以下内容.这是utf-8编码中"č"字母的正确十六进制表示.我的所有页面都是utf-8,我从未向Indy提交表单数据时遇到任何问题.我调试了代码,发现我实际上得到了一个像这样的字节序列:[37,67,52,37,56,68].这是字符串"%C4%8D"的字节表示.但是当然Indy无法正确编码为UTF-16.举个例子.实际表格字段:
FirstName=?rt
Run Code Online (Sandbox Code Playgroud)
提交后出现如下:
FirstName=%C4%8Drt
Run Code Online (Sandbox Code Playgroud)
我不知道如何解决这个问题.我查看了ExtJS论坛,但这个主题没有任何内容.有人对这类问题一无所知吗?
编辑:
如果我对params ad JSON进行编码,则它们会正确到达.我也尝试对params进行URL解码,但结果不正确.也许我错过了什么.我会再看看这个.是的,似乎ExtJS URL编码参数
编辑2:
好的,我发现了更多.我比较了帖子数据的实际内容.它是这样的:
Delphi 2006 (Indy10): FirstName=%C4%8D
Delphi 2010 (Indy10): FirstName=%C4%8D
Run Code Online (Sandbox Code Playgroud)
在这两种情况下,未解析的参数都是相同的.我打开了ParseParams,在BDS2006中它们被正确解析,但在2010年它们没有.这是使用delphi进行的Indy10.这个版本有错误还是我做错了什么?
编辑3:
我下载了最新的夜间版本Indy10.仍然是同一个问题.
编辑4:
我不得不接受自己的答案.
我正在尝试构建一个非常简单的驱动程序.它的唯一目的是注册"PsSetCreateProcessNotifyRoutine"和从内核收到的回调,通知我的Win32应用程序关于哪些proccesses启动和停止.
我只知道如何用"DriverEntry"和"DriverUnload"构建这样一个简单的驱动程序,并用DDK编译它.但我不知道如何实际沟通.我知道可以用IOCTL完成.但除此之外,我在黑暗中.我找不到在Delphi中如何做到这一点的简单例子.我只知道可以做到.
所以我正在寻找的是一些简单易懂的教程,如何做到这一点或事件更好的例子delphi程序与acompaniying驱动程序代码.也许甚至还有其他沟通方式.
任何帮助都会得到满足.
我有一个队列,我可以在其中排队不同的线程,所以我可以保证两件事:
第二点很重要.否则,一个简单的关键部分就足够了.我有不同的请求组,只有在一个组内才能满足这些要求.来自不同组的请求可以并发运行.
它看起来像这样:
FTaskQueue.Enqueu('MyGroup');
try
Do Something (running in context of some thread)
finally
FTaskQueue.Dequeu('MyGroup');
end;
Run Code Online (Sandbox Code Playgroud)
编辑:我删除了实际的实现,因为它隐藏了我想要解决的问题
我需要这个,因为我有一个基于Indy的Web服务器接受http请求.首先,我找到了请求的相应会话.然后为该会话执行请求(代码).我可以获得同一会话的多个请求(读取我可以获得新请求,而第一个仍处理)并且它们必须以正确的到达顺序逐个执行.所以我寻找一个可以在这种情况下使用的通用同步队列,以便请求可以排队.我无法控制线程,每个请求可以在不同的线程中执行.
这种问题的最佳(使用)方法是什么?问题是Enqueue和Dequeue必须是原子操作,以便保存正确的顺序.我目前的实施有很大的瓶颈,但它确实有效.
编辑:Bellow是原子Enqueue/Dequeue操作的问题
你正常地做这样的事情:
procedure Enqueue;
begin
EnterCriticalSection(FCritSec);
try
DoEnqueue;
finally
LeaveCriticalSection(FCritSec);
end;
BlockTheCurrentThread; // here the thread blocks itself
end;
procedure Dequeue;
begin
EnterCriticalSection(FCritSec);
try
DoDequeue;
UnblockTheNextThread; // here the thread unblocks another thread
finally
LeaveCriticalSection(FCritSec);
end;
end;
Run Code Online (Sandbox Code Playgroud)
现在问题在于这不是原子的.如果队列中已有一个线程而另一个线程调用Enqueue,则可能会发生第二个线程将离开临界区并尝试阻塞自身.现在线程调度程序将恢复第一个线程,它将尝试取消阻塞下一个(第二个)线程.但是第二个线程还没有被阻止,所以没有任何反应.现在第二个线程继续并阻塞自身,但这不正确,因为它不会被解除阻塞.如果阻塞在临界区内,那么临界区永远不会离开,我们就会陷入僵局.
可能是一个微不足道的问题,但我希望得到最好的解决方案.
问题:
我有两个或更多工作人员将密钥插入一个或多个表.当两个或多个工作人员试图同时将同一个密钥插入其中一个密钥表时,就会出现问题.典型的问题.
关键表是简单的对.第一列是自动递增整数,第二列是varchar键.
这种并发问题的最佳解决方案是什么?我认为这是一个常见的问题.一种可靠的方法是处理抛出的异常,但不知何故我不相信这是解决这个问题的最佳方法.
我使用的数据库是Firebird 2.5
编辑:
一些额外的信息,以使事情清楚.
典型的这种表是用户表.例如:
1 2056 2 1044 3 1896 4 5966 ...
每个工作人员检查用户"xxxx"是否存在,如果不存在则插入.
编辑2:
仅供参考,如果有人会走相同的路线.IB/FB返回错误代码对(我正在使用InterBase Express组件).检查重复值违规是这样的:
except
on E: EIBInterBaseError do
begin
if (E.SQLCode = -803) and (E.IBErrorCode = 335544349) then
begin
FKeysConnection.IBT.Rollback;
EnteredKeys := False;
end;
end;
end;
Run Code Online (Sandbox Code Playgroud) 尝试在 64 位应用程序中使用 Indy 和 OpenSSL。该应用程序已从 32 位移植。从https://indy.fulgan.com/SSL下载的 OpenSSL 库一切正常
但我找不到 64 位的。目前 fulgan 的存储库似乎是空的。任何人都有这方面的信息。我无法让它与标准 OpenSSL 二进制文件一起使用。
我不确定印地在这方面是否有任何变化。
我不明白为什么一个简单的请求和响应需要 400 毫秒才能完成。它只需要不到 1 毫秒即可在本地主机上完成(环回)。当我从虚拟机向主开发计算机发出请求时,需要 400 毫秒才能完成。最多需要 40 毫秒。这是 HTTP 请求的最大消耗量,因此 TCP 应该更快。这是客户端和服务器的代码。我就是看不出我在哪里浪费了时间。如果您需要更多信息,我可以介绍一下。
该代码与 Indy 9 和 10 兼容,这就是 IFDEF-s 的原因。而且连接已经建立,没有连接部分,仅数据发送和响应需要 400 毫秒。
function TIMCClient.ExecuteConnectedRequest(const Request: IMessageData): IMessageData;
var
DataLength: Int64;
FullDataSize: Int64;
IDAsBytes: TIdBytes;
IDAsString: ustring;
begin
Result := AcquireIMCData;
FAnswerValid := False;
with FTCPClient{$IFNDEF Indy9}.IOHandler{$ENDIF} do
begin
Request.Data.Storage.Seek(0, soFromBeginning);
DataLength := Length(Request.ID) * SizeOf(uchar);
FullDataSize := DataLength + Request.Data.Storage.Size + 2 * SizeOf(Int64);
SetLength(IDAsBytes, DataLength);
Move(Request.ID[1], IDAsBytes[0], DataLength);
// write data
{$IFDEF Indy9}WriteInteger{$ELSE}Write{$ENDIF}(FullDataSize);
{$IFDEF Indy9}WriteInteger{$ELSE}Write{$ENDIF}(DataLength);
{$IFDEF Indy9}WriteBuffer{$ELSE}Write{$ENDIF}(IDAsBytes{$IFDEF Indy9}[0]{$ENDIF}, …Run Code Online (Sandbox Code Playgroud) delphi ×8
indy10 ×2
64-bit ×1
asynchronous ×1
concurrency ×1
driver ×1
extjs ×1
firebird ×1
indy ×1
ioctl ×1
javascript ×1
mobile ×1
named-pipes ×1
openssl ×1
performance ×1
queue ×1
sql ×1
ssl ×1
submit ×1
synchronous ×1
tcp ×1
wdk ×1
winapi ×1
windows ×1