C/S系统,并发2500人的连接,给个建议....200分 ( 积分: 200 )

  • 主题发起人 主题发起人 huangwei8123
  • 开始时间 开始时间
H

huangwei8123

Unregistered / Unconfirmed
GUEST, unregistred user!
我想改进一个的系统,估计有3000人的并发连接,一个星期10万左右连接(客户说的,实际上我也不知道有么那么多)。
我想问下大家,用什么控件好呢?传送的数据倒不是很大,而且也不会一直连接。
 
3000的并发用户,可以考虑使用一些多层技术手段了,比如池,非连接状态对象。。。
 
我用的是D7,对网络编程没有接触过,看了下书,就用IdUDPClient,IdUDPServer这两个控件了,大家有什么建议?

to :HNXXCXG
池,非连接状态对象,对于我可能太复杂了....谢谢你。
 
indy 支持不到这么高的连接。200人就差不多要挂了
 
3000同时左右,完成端口是很好的选择
 
完成端口?我挺好多人说起过这个,能小小的解释下吗?原理是什么?
 
完成端口需要用到什么控件吗?
 
DELPHI中完成端口(IOCP)的简单分析(1)
--------------------------------------------------------------------------------

2006-11-03 17:01:25

用DELPHI开发网络代码已经有一段时间了!
我发现在网上用VC来实现完成端口(IOCP)的代码很多,但是使用DELPHI来实现的就比较少了。对IOCP讲的清楚的就更少了。在这里我把自己编写DELPHI下的IOCP写出来,希望对刚学完成端口的朋友有个帮助。
首先我们来了解一些在使用IOCP的时候需要使用的一些结构!
(1):单IO数据结构
LPVOID = Pointer;
LPPER_IO_OPERATION_DATA = ^ PER_IO_OPERATION_DATA ;
PER_IO_OPERATION_DATA = packed record
Overlapped: OVERLAPPED;
DataBuf: TWSABUF;
Buffer: array [0..1024] of CHAR;
BytesSEND: DWORD;
BytesRECV: DWORD;
end;
上面的结构中Overlapped: OVERLAPPED;和DataBuf: TWSABUF;是固定的结构类型。Buffer: array [0..1024] of CHAR;是用来保存接受数据的缓存。BytesSEND: DWORD;用来标志发送数据的长度。BytesRECV: DWORD;用来标志接受数据的长度。因为完成端口的工作者线程可以接受到来自客户端的数据,同时还可以接受到自己发送给客户端的数据,所以我们使用BytesSEND,BytesRECV变量来说是用来区分这次的数据是来自客户端的数据还是自己发送出去的数据。详细的使用方法,我会在下面详细说明。
(2):“单句柄数据结构”
LPPER_HANDLE_DATA = ^ PER_HANDLE_DATA;
PER_HANDLE_DATA = packed record
Socket: TSocket;
end;
下来我从编写一个完成端口的为例说明。
if WSAStartUp($202, wsData) <> 0 then
begin
WSACleanup();
end;
加载SOCKET。我使用的是2.2版为了后面方便加入心跳。
CompletionPort:=CreateIOCompletionPort(INVALID_HANDLE_VALUE,0,0,0);
创建一个完成端口。
GetSystemInfo(LocalSI);
for I:=0 to LocalSI.dwNumberOfProcessors * 2 -1 do
begin
hThread := CreateThread(nil, 0, @ServerWorkerThread, Pointer(CompletionPort),0, ThreadID);
if (hThread = 0) then
begin
Exit;
end;
CloseHandle(hThread);
end;
根据CPU的数量创建CPU*2数量的工作者线程。
Listensc:=WSASocket(AF_INET,SOCK_STREAM,0,Nil,0,WSA_FLAG_OVERLAPPED);
if Listensc=SOCKET_ERROR then
begin
closesocket(Listensc);
WSACleanup();
end;
sto.sin_family:=AF_INET;
sto.sin_port:=htons(5500);
sto.sin_addr.s_addr:=htonl(INADDR_ANY);
if bind(Listensc,sto,sizeof(sto))=SOCKET_ERROR then
begin
closesocket(Listensc);
end;
listen(Listensc,20);
创建一个套接字,将此套接字和一个端口绑定并监听此端口。
while (TRUE) do
begin
Acceptsc:= WSAAccept(Listensc, nil, nil, nil, 0);
当客户端有连接请求的时候,WSAAccept函数会新创建一个套接字Acceptsc。这个套接字就是和客户端通信的时候使用的套接字。
if (Acceptsc= SOCKET_ERROR) then
begin
closesocket(Listensc);
exit;
end;
判断Acceptsc套接字创建是否成功,如果不成功则退出。
PerHandleData := LPPER_HANDLE_DATA (GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA)));
if (PerHandleData = nil) then
begin
exit;
end;
PerHandleData.Socket := Acceptsc;
创建一个“单句柄数据结构”将Acceptsc套接字绑定。
if (CreateIoCompletionPort(Acceptsc, CompletionPort, DWORD(PerHandleData), 0) = 0) then
begin
exit;
end;
将套接字、完成端口和“单句柄数据结构”三者绑定在一起。
PerIoData := LPPER_IO_OPERATION_DATA(GlobalAlloc(GPTR, sizeof(PER_IO_OPERATION_DATA)));
if (PerIoData = nil) then
begin
exit;
end;
ZeroMemory(@PerIoData.Overlapped, sizeof(OVERLAPPED));
PerIoData.BytesSEND := 0;
PerIoData.BytesRECV := 0;
PerIoData.DataBuf.len := 1024;
PerIoData.DataBuf.buf := @PerIoData.Buffer;
Flags := 0;
创建一个“单IO数据结构”其中将PerIoData.BytesSEND 和PerIoData.BytesRECV 均设置成0。说明此“单IO数据结构”是用来接受的。
if (WSARecv(Acceptsc, @(PerIoData.DataBuf), 1, @RecvBytes, @Flags,@(PerIoData.Overlapped), nil) = SOCKET_ERROR) then
begin
if (WSAGetLastError() <> ERROR_IO_PENDING) then
begin
exit;
end
end;
用此“单IO数据结构”来接受Acceptsc套接字的数据。
end;
创建IOCP的工作已经完成,下一次我将写IOCP的工作者线程的处理方法,谢谢!
 
DELPHI中完成端口(IOCP)的简单分析(2)
--------------------------------------------------------------------------------

2006-11-03 17:02:49

今天我写一下关于DELPHI编写完成端口(IOCP)的工作者线程中的东西。希望各位能提出批评意见。
上次我写了关于常见IOCP的代码,对于IOCP来说,接受到客户端发送过来和自己发送出去的数据都是从工作者线程中得到。代码和解释如下:
function ServerWorkerThread(CompletionPortID:Pointer):Integer;stdcall;
begin
CompletionPort:=THANDLE(CompletionPortID);
//得到创建线程是传递过来的IOCP
while(TRUE) do
begin
//工作者线程会停止到GetQueuedCompletionStatus函数处,直到接受到数据为止
if (GetQueuedCompletionStatus(CompletionPort, BytesTransferred,DWORD(PerHandleData), POverlapped(PerIoData), INFINITE) = False) then
begin
//当客户端连接断开或者客户端调用closesocket函数的时候,函数GetQueuedCompletionStatus会返回错误。如果我们加入心跳后,在这里就可以来判断套接字是否依然在连接。
if PerHandleData<>nil then
begin
closesocket(PerHandleData.Socket);
GlobalFree(DWORD(PerHandleData));
end;
if PerIoData<>nil then
begin
GlobalFree(DWORD(PerIoData));
end;
continue;
end;
if (BytesTransferred = 0) then
begin
//当客户端调用shutdown函数来从容断开的时候,我们可以在这里进行处理。
if PerHandleData<>nil then
begin
TempSc:=PerHandleData.Socket;
shutdown(PerHandleData.Socket,1);
closesocket(PerHandleData.Socket);
GlobalFree(DWORD(PerHandleData));
end;
if PerIoData<>nil then
begin
GlobalFree(DWORD(PerIoData));
end;
continue;
end;
//在上一篇中我们说到IOCP可以接受来自客户端的数据和自己发送出去的数据,两种数据的区别在于我们定义的结构成员BytesRECV和BytesSEND的值。所以下面我们来判断数据的来自方向。因为我们发送出去数据的时候我们设置了结构成员BytesSEND。所以如果BytesRECV=0同时BytesSEND=0那么此数据就是我们接受到的客户端数据。(这种区分方法不是唯一的,个人可以有自己的定义方法。只要可以区分开数据来源就可以。)
if (PerIoData.BytesRECV = 0) and (PerIoData.BytesSEND = 0) then
begin
PerIoData.BytesRECV := BytesTransferred;
PerIoData.BytesSEND := 0;
end
else
begin
PerIoData.BytesSEND := BytesTransferred;
PerIoData.BytesRECV := 0;
end;
//当是接受来自客户端的数据是,我们进行数据的处理。
if (PerIoData.BytesRECV > PerIoData.BytesSEND) then
begin
PerIoData.DataBuf.buf := PerIoData.Buffer + PerIoData.BytesSEND;
PerIoData.DataBuf.len := PerIoData.BytesRECV - PerIoData.BytesSEND;
//这时变量PerIoData.Buffer就是接受到的客户端数据。数据的长度是PerIoData.DataBuf.len 你可以对数据进行相关的处理了。
//.......

//当我们将数据处理完毕以后,应该将此套接字设置为结束状态,同时初始化和它绑定在一起的数据结构。
ZeroMemory(@(PerIoData.Overlapped), sizeof(OVERLAPPED));
PerIoData.BytesRECV := 0;
Flags := 0;
ZeroMemory(@(PerIoData.Overlapped), sizeof(OVERLAPPED));
PerIoData.DataBuf.len := DATA_BUFSIZE;
ZeroMemory(@PerIoData.Buffer,sizeof(@PerIoData.Buffer));
PerIoData.DataBuf.buf := @PerIoData.Buffer;
if (WSARecv(PerHandleData.Socket, @(PerIoData.DataBuf), 1, @RecvBytes, @Flags,@(PerIoData.Overlapped), nil) = SOCKET_ERROR) then
begin
if (WSAGetLastError() <> ERROR_IO_PENDING) then
begin
if PerHandleData<>nil then
begin
TempSc:=PerHandleData.Socket;
closesocket(PerHandleData.Socket);
GlobalFree(DWORD(PerHandleData));
end;
if PerIoData<>nil then
begin
GlobalFree(DWORD(PerIoData));
end;
continue;
end;
end;
end
//当我们判断出来接受的数据是我们发送出去的数据的时候,在这里我们清空我们申请的内存空间
else
begin
GlobalFree(DWORD(PerIoData));
end;
end;
end;
到此,工作者线程已经处理完成。接受数据已经没有问题了。下一篇中我将会写出,如何时候IOCP来发送数据代码。今天的代码中应该对PerIoData.BytesRECV > PerIoData.BytesSEND单另解说一下。其实如果按照上面的例子去编写工作者线程,会觉得编写出来的代码会很不稳定,接受到的数据总是有错位的现象。原因是TCP协议中有数据分片的概念,这个以后我会将我处理这个的代码分享给大家。
 
谢谢 无欲则刚。
正在学习中....

我在我的问题简单些吧
其实很简单,
有4个服务器,2个10M独享,2个100M独享。
1.客户端的程序,在启动的时候要判断那个服务器快,然后连接上那个服务器,
2.然后向那个服务器发送一个命令,服务器程序根据这个命令查询数据库,然后把查询的结构通过某种加密技术返回给客户端,然后就可以断开连接了。在客户端的程序运行的过程中,还可能发送其他类型的查询命令。(因为客户要求客户端是不用安装的,所以没有考虑是用查询控件)
关键麻烦在于,可能并发连接的数量比较多,有上千,以后还会增加,所以希望是用的技术可以支持。

呵呵,功能就是以上要求的....大家看看用什么方式开发????
 
JSP群:27533401把我这几年收集的JSP视频教程和大家分享
我是个自学JSP的,有很多时候遇到问题不能解决,中间求过很多人,有的人很热心,有的人很冷淡,不管如何

我都要谢谢他们,现在我渐渐的学习JSP有2~3年了,回首发现以前没人教真的很难........

现在不能说我的技术很好,但是我愿意帮助新手解决些问题,只要我会,希望大家都来互相帮助,谁都有遇到

困难的时候...

特地开了个群,我把我这几年收集的视频教程都贡献出来了,欢迎大家互相帮助的学好JAVA

:群号:27533401
我们的总部设在http://bbs.8isp.cn/?u=233
 
看你的数据传输量,不大的话,使用D6的ServerSocket都可以了,如果大的话,一定要用楼上说的IOCP
 
to markhorse:
数据传送我是这样想的,客户端到服务器肯定很小,就一条命令,但是服务器到客户端有一点点大,大约是1000--2000首歌的歌词、地址、名字。这样的话,ServerSocket可以吗?那么客户端用什么控件好呢?
 
http://fxh7622.blog.51cto.com/blog/63841/7667
上面这个博客里有详细说明完成端口的做法。
 
好的,这就过去看看...
 
呵呵,这这不就是“无欲则刚”转贴过来的吗....不过那里还有一些其他的东西,现在可能用不到,以后会有用的...
 
一段比较简单的代码
unit IOCPServerSocket;

interface

uses
SysUtils, Classes, SyncObjs, Windows, Sockets, WinSock;

type
EIOCPError = Exception;
TCustomIOCPServer = class;

TIOCPClientSocketThread = class(TThread)
private
FIOCPServer: TCustomIOCPServer;
FClientSocket: TCustomIpClient;
protected
procedure Execute; override;
public
constructor Create(AIOCPServer: TCustomIOCPServer);
destructor Destroy; override;
end;

TIOCPServerSocketThread = class(TThread)
private
FIOCPServer: TCustomIOCPServer;
FSocket: TCustomTcpServer;
protected

procedure Execute; override;
public
constructor Create(AIOCPServer: TCustomIOCPServer);
destructor Destroy; override;
end;

TIOCPThreadStatusType =
(iocpActual, iocpCurrent, iocpClient);
TIOCPThreadStatusRec = packed record
CurThread: integer;
ActThread: integer;
ClientThread: integer;
end;

TErrorEvent = procedure(AE: Exception) of object;
TUpdateEvent = procedure(IOCPThreadStatus: TIOCPThreadStatusRec)
of object;
TProcessEvent = procedure(ASock: TCustomIpClient) of object;

TCustomIOCPServer = class(TComponent)
private
FServerSocketThread: TIOCPServerSocketThread;
FErrorException: EIOCPError;
FIOCPHandle: THandle;
FLocalHost: TSocketHost;
FLocalPort: TSocketPort;
FThreadPool: TList;
FThreadStatus: TIOCPThreadStatusRec;
FMaxThreadsInPool: integer;
FMinThreadsInPool: integer;
FTerminateEvent: TSimpleEvent;
FSvcTerminateEvent: TSimpleEvent;
FCriticalSection: TCriticalSection;
FIdleTimeOut: integer;
FOnErrorEvent: TErrorEvent;
FOnUpdateEvent: TUpdateEvent;
FOnProcessEvent: TProcessEvent;
function GetActive: Boolean;
procedure SetActive(const Value: Boolean);
procedure SetLocalHost(const Value: TSocketHost);
procedure SetLocalPort(const Value: TSocketPort);

procedure IncThreadStatus(AType: TIOCPThreadStatusType);
procedure DecThreadStatus(AType: TIOCPThreadStatusType);
procedure SetMaxThreadsInPool(const Value: integer);
procedure SetMinThreadsInPool(const Value: integer);
procedure SetIdleTimeOut(const Value: integer);

procedure SyncErros;
protected
procedure EnsureClosed;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;

procedure WaitForTerminate;

procedure Open; virtual;
procedure Close; virtual;
procedure SyncUpdate;

property Active: Boolean
read GetActive write SetActive;
property IdleTimeOut: integer
read FIdleTimeOut write SetIdleTimeOut;
property LocalHost: TSocketHost
read FLocalHost write SetLocalHost;
property LocalPort: TSocketPort
read FLocalPort write SetLocalPort;
property MaxThreadsInPool: integer
read FMaxThreadsInPool write SetMaxThreadsInPool;
property MinThreadsInPool: integer
read FMinThreadsInPool write SetMinThreadsInPool;

property OnUpdate: TUpdateEvent
read FOnUpdateEvent write FOnUpdateEvent;
property OnProcess: TProcessEvent
read FOnProcessEvent write FOnProcessEvent;
property OnError: TErrorEvent
read FOnErrorEvent write FOnErrorEvent;
end;

TIOCPServer = class(TCustomIOCPServer)
published
property Active;
property IdleTimeOut;
property LocalHost;
property LocalPort;
property MaxThreadsInPool;
property MinThreadsInPool;

property OnUpdate;
property OnProcess;
property OnError;
end;

implementation

const
TERMINATE_THREAD = $7fffffff;

resourcestring
ERRIOCPCreation =
'Could not initialize IOCP connection';


{ TIOCPClientSocketThread }

constructor TIOCPClientSocketThread.Create(AIOCPServer: TCustomIOCPServer);
begin
inherited Create(False);
FreeOnTerminate := True;
FIOCPServer := AIOCPServer;
end;

destructor TIOCPClientSocketThread.Destroy;
begin
inherited Destroy;
end;

procedure TIOCPClientSocketThread.Execute;
var
Transfered: dword;
AClientSocket: TSocket;
OverlappedPtr: POverlapped;
Thread: TThread;
i: integer;

begin
with FIOCPServer do
begin
while not Terminated do
begin
if not GetQueuedCompletionStatus(FIOCPHandle, Transfered,
Cardinal(AClientSocket), OverlappedPtr, FIdleTimeOut + 500) then
begin
if GetLastError = WAIT_TIMEOUT then
begin
FCriticalSection.Enter;
try
if (FThreadStatus.CurThread > FMinThreadsInPool) then
Terminate;
finally
FCriticalSection.Leave;
end;
end else
begin
if (AClientSocket = TERMINATE_THREAD) then
begin

Terminate;
Break;
end;
IncThreadStatus(iocpActual);
DecThreadStatus(iocpClient);
Synchronize(SyncUpdate);
FCriticalSection.Enter;
try
if (FThreadStatus.CurThread < FMaxThreadsInPool) then
begin
if (FThreadStatus.ActThread = FThreadStatus.CurThread) then
begin
Thread := TIOCPClientSocketThread.Create(FIOCPServer);
FThreadPool.Add(Thread);
IncThreadStatus(iocpCurrent);
Synchronize(SyncUpdate);
end;
end;
finally
FCriticalSection.Leave;
end;
FClientSocket := TCustomIpClient.Create(nil);
with FClientSocket do
try
try
FServerSocketThread.FSocket.Accept(FClientSocket);
if Assigned(FOnProcessEvent) then
FOnProcessEvent(FClientSocket);
except
on E:Exception do
begin
FCriticalSection.Enter;
try

FErrorException := e;
finally
FCriticalSection.Leave;
end;
Synchronize(SyncErros);
end;
end;
finally
DecThreadStatus(iocpActual);
Close;
Synchronize(SyncUpdate);
FreeAndNil(FClientSocket);
end;
end;
end;
end;
FCriticalSection.Enter;
try
i := FThreadPool.IndexOf(Self);
if i >= 0 then
FThreadPool.Delete(i);
DecThreadStatus(iocpCurrent);
Synchronize(SyncUpdate);
if FThreadStatus.CurThread = 0 then
FTerminateEvent.SetEvent;
finally
FCriticalSection.Leave;
end;
end;

end;

{ TIOCPServerSocketThread }

constructor TIOCPServerSocketThread.Create(AIOCPServer: TCustomIOCPServer);
begin
inherited Create(False);
FreeOnTerminate := True;
FIOCPServer := AIOCPServer;
FSocket := TCustomTcpServer.Create(nil);
FSocket.BlockMode := bmBlocking;
end;

destructor TIOCPServerSocketThread.Destroy;
begin
FSocket.Free;
inherited Destroy;

end;

procedure TIOCPServerSocketThread.Execute;
var
ASocket: TSocket;
AClientSocket: TCustomIpClient;
i: integer;
begin
with FSocket do
begin
LocalHost := FIOCPServer.LocalHost;
LocalPort := FIOCPServer.LocalPort;
Open;
repeat
if WaitForData(5000) then
begin
AClientSocket := TCustomIpClient.Create(nil);
try
Accept(AClientSocket);
ASocket := AClientSocket.Handle;
finally
AClientSocket.Free;
end;
if ASocket <> INVALID_SOCKET then
begin
FIOCPServer.IncThreadStatus(iocpCurrent);
PostQueuedCompletionStatus(FIOCPServer.FIOCPHandle, 0,
Cardinal(ASocket), nil);
end;
end;
until Terminated;
Close;
FIOCPServer.FCriticalSection.Enter;
try
for i := (FIOCPServer.FThreadPool.Count-1) downto 0 do
PostQueuedCompletionStatus(FIOCPServer.FIOCPHandle, 0,
Cardinal(TERMINATE_THREAD), nil);
finally
FIOCPServer.FCriticalSection.Leave;
end;
WaitForSingleObject(FIOCPServer.FTerminateEvent.Handle, INFINITE);
end;

end;

{ TCustomIOCPServer }

procedure TCustomIOCPServer.Close;
begin
try
FServerSocketThread.FSocket.Close;
FServerSocketThread.Terminate;
FServerSocketThread.WaitFor;
finally
CloseHandle(FIOCPHandle);
FSvcTerminateEvent.SetEvent;
end;
end;

constructor TCustomIOCPServer.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FIOCPHandle := 0;
FMinThreadsInPool := 4;
FMaxThreadsInPool := 10;
FCriticalSection := TCriticalSection.Create;
FTerminateEvent := TSimpleEvent.Create;
FSvcTerminateEvent:= TSimpleEvent.Create;
FThreadPool := TList.Create;
end;

procedure TCustomIOCPServer.DecThreadStatus(AType: TIOCPThreadStatusType);
begin
case AType of
iocpActual: InterlockedDecrement(FThreadStatus.ActThread);
iocpCurrent: InterlockedDecrement(FThreadStatus.CurThread);
iocpClient: InterlockedDecrement(FThreadStatus.ClientThread);
end;
end;

destructor TCustomIOCPServer.Destroy;
begin
FThreadPool.Free;
FSvcTerminateEvent.Free;
FTerminateEvent.Free;
FCriticalSection.Free;
inherited Destroy;

end;

procedure TCustomIOCPServer.EnsureClosed;
begin
if Active then
Close;
end;

function TCustomIOCPServer.GetActive: Boolean;
begin
Result := (FIOCPHandle <> 0);

end;

procedure TCustomIOCPServer.IncThreadStatus(AType: TIOCPThreadStatusType);
begin
case AType of
iocpActual: InterlockedIncrement(FThreadStatus.ActThread);
iocpCurrent: InterlockedIncrement(FThreadStatus.CurThread);
iocpClient: InterlockedIncrement(FThreadStatus.ClientThread);
end;
end;

procedure TCustomIOCPServer.Open;
var
AClientThread: TIOCPClientSocketThread;
ASystemInfo: TSystemInfo;
i: integer;
begin
if not (csLoading in ComponentState) and
not (csDesigning in ComponentState) then
begin
EnsureClosed;
GetSystemInfo(ASystemInfo);
FIOCPHandle := CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0,
ASystemInfo.dwNumberOfProcessors);
if (FIOCPHandle = 0) then

raise EIOCPError.Create(ERRIOCPCreation);
try
for i := 0 to FMinThreadsInPool-1 do
begin
AClientThread := TIOCPClientSocketThread.Create(Self);
FThreadPool.Add(AClientThread);
IncThreadStatus(iocpCurrent);
end;
FServerSocketThread := TIOCPServerSocketThread.Create(Self);
except
EnsureClosed;
raise;
end;
end;

end;

procedure TCustomIOCPServer.SetActive(const Value: Boolean);
begin
if (Value <> Active) and
(not (csLoading in ComponentState) and
not (csDesigning in ComponentState)) then
begin
if Value then Open else Close;
end;

end;

procedure TCustomIOCPServer.SetIdleTimeOut(const Value: integer);
begin
EnsureClosed;
FIdleTimeOut := Value;
end;

procedure TCustomIOCPServer.SetLocalHost(const Value: TSocketHost);
begin
FLocalHost := Value;
end;


procedure TCustomIOCPServer.SetLocalPort(const Value: TSocketPort);
begin
FLocalPort := Value;
end;

procedure TCustomIOCPServer.SetMaxThreadsInPool(const Value: integer);
begin
EnsureClosed;
FMaxThreadsInPool := Value;
end;

procedure TCustomIOCPServer.SetMinThreadsInPool(const Value: integer);

begin
EnsureClosed;
FMinThreadsInPool := Value;
end;

procedure TCustomIOCPServer.SyncErros;
begin
if Assigned(FOnErrorEvent) then
FOnErrorEvent(FErrorException);
end;

procedure TCustomIOCPServer.SyncUpdate;
begin
if Assigned(FOnUpdateEvent) then
FOnUpdateEvent(FThreadStatus);

end;

procedure TCustomIOCPServer.WaitForTerminate;
begin
FSvcTerminateEvent.WaitFor(INFINITE)
end;

end.
 
我在我的问题简单些吧
其实很简单,
有4个服务器,2个10M独享,2个100M独享。
1.客户端的程序,在启动的时候要判断那个服务器快,然后连接上那个服务器,
2.然后向那个服务器发送一个命令,服务器程序根据这个命令查询数据库,然后把查询的结构通过某种加密技术返回给客户端,然后就可以断开连接了。在客户端的程序运行的过程中,还可能发送其他类型的查询命令。(因为客户要求客户端是不用安装的,所以没有考虑是用查询控件)
关键麻烦在于,可能并发连接的数量比较多,有上千,以后还会增加,所以希望是用的技术可以支持。

呵呵,功能就是以上要求的....大家看看用什么方式开发????

数据传送我是这样想的,客户端到服务器肯定很小,就一条命令,但是服务器到客户端有一点点大,大约是1000--2000首歌的歌词、地址、名字。这样的话,ServerSocket可以吗?那么客户端用什么控件好呢?

应该不需要用到完成端口那么高深的东西吧...
 
还有就是服务端可能要做一个平衡负载,要怎么写呢???
 
后退
顶部