Borland Socket Server在通过Internet联接时,很有问题,有没有替代品?(300分)

  • 主题发起人 主题发起人 程云
  • 开始时间 开始时间
不知道大家的系统的中间件有多大!:P
这个问题很复杂阿!.呵呵!
:( 我们的系统现在没觉得慢啊!
 
如果服务器平台是WIN XP就没事, 如果平台是WIN NT或2000就有问题, 是否我的设
置有问题?
 
TWEBCONNECTION问题也多多的,SOCKET速度还快,TWEBCONNECTION呢,速度慢,而且还不能正确
传递参数。要用TClientDataSet.FetchParams是不能的了
 
会不会是防火墙墙的问题 ?
 
sofox:我发现你很厉害哦.
>>我用ASTA有段日子了,听我的,不要用ASTA,这东西很Buggy。原因在于它的Server端用Borland自带的ServerSocket
>>主要问题:
>> 1)效率低,由于是基于Message方式,所有socket读写都由MainThread完成,如果有大量Client连接,而且数据交换
>>频繁,那你就糗大了;
你有好主意而不用message吗?说出来大家听听.
>> 2)对Client的管理极度混乱,除非你能容忍你的服务器不知道有client断开连接;
不会吧,这么恐怖呀!幸好没有用过:)
>> 3)脆弱,特别时当你用线程来完成某些费时操作时,有一种100%让server挂掉的方法:发一个能引起server在Thread里面
>>发生Exception的请求(例如一个非法的SQL),然后立刻断开连接
这点我不同意.server挂掉是什么意思?我的服务器在调试的时候会发生异常但只是使引发服务
器异常的客户断开呀,不影响其他客户的异常是可以完全避免的,而且SocketServer会将异常传
到客户端的.
 
兄弟们,再别扯WebConnection了这家伙和SocketConnection用的是相同的代码哟.
我倒怀疑是Interface的问题.我的系统中我已经将它换掉了.
 
大家不要争,
Web Services是解决Internet下数据传输的最佳方式,要不他也不会发展到今天,
使用SOAP和IIS虽然不能解决目前遇到的问题,但在下一次开发过程中使用它是最好的
选择。虽然它也有一些问题,比如安全性等,但只要我们编程的时候小心点,注意点,
用户是不会知道的,只会知道我们开发的东西很稳定。

Web Services=SOAP+UDDI+WSDL+.........
 
建议使用ASTAIO,他的SERVER是使用我的一个乌克兰朋友写的IOCP来完成的,因此理论上来
说可以支持大约20,000个并发连接.
 
gz,这是一个很值得讨论的问题。
 
秋之叶,我也碰到了这样的问题,能否给我发一个,50分以上 zhangmingjiu@21cn.com
要有用的
 
scktsrvr.exe
本来就有bug
 
SConnect.pas也有bug
 
关于这个问题:

Hi Dan:
After 6 month I response your ask for my tips in this enviroments, more I have the fix. I get the fix today after 15 day in January to detect and 30 hs in the last two day searching the solution because the problem become more frequently in machine with high processor (Dell 2400 dual)

I need talk with you and I need if you can contact peope arround the broalnd world to test this fix.
My preliminary testing was successfully

Maybe Borland wants hire to me :).

Ok, go ahead!
The first problem I post to raid and is open number 139350 , this problem affect with have a lot of thread! your client application died and you remain objects in socket server. My fix this raid work fine

2nd and 3th I found doing sniffers and extreme logs. The point is server and client are in listen point at the same time, If you disconnect from socket the client returns!. This is the failure, well this failures is produce by:

Second problem I think but I'm not sure is in function TCustomWinSocket.ReceiveBuf(var Buf; Count: Integer): Integer;
i'm not sure because I haven't time to try don't use this fix. My point was, using this fix work, so keep there!
The new code is see {##Add}:

function TCustomWinSocket.ReceiveBuf(var Buf; Count: Integer): Integer;
var
ErrorCode, iCount: Integer; {##Add}
begin
Lock;
try
Result := 0;
if (Count = -1) and FConnected then
ioctlsocket(FSocket, FIONREAD, Longint(Result))
else begin
if not FConnected then Exit;
if ioctlsocket(FSocket, FIONREAD, iCount) = 0 then {##ADD}
begin
if iCount < Count then {##ADD}
Count := icount; {##ADD}
end;

Result := recv(FSocket, Buf, Count, 0);
if Result = SOCKET_ERROR then
begin
ErrorCode := WSAGetLastError;
if ErrorCode <> WSAEWOULDBLOCK then
begin
Error(Self, eeReceive, ErrorCode);
Disconnect(FSocket);
if ErrorCode <> 0 then
raise ESocketError.CreateResFmt(@sWindowsSocketError,
[SysErrorMessage(ErrorCode), ErrorCode, 'recv']);
end;
end;
end;
finally
Unlock;
end;
end;

Thrird Problem THE PROBLEM! I think this the point !:....
function TSocketTransport.Receive(WaitForInput: Boolean; Context: Integer): IDataBlock;
this function read when it want , but this function woukd be reading when WINSOCK want! the problem is wait for the event
the new code is : (see {##ADD}




function TSocketTransport.Receive(WaitForInput: Boolean; Context: Integer): IDataBlock;
var
RetLen, Sig, StreamLen: Integer;
P: Pointer;
FDSet: TFDSet;
TimeVal: PTimeVal;
RetVal: Integer;
bFirst: boolean; {## ADD}
begin
Result := nil;
TimeVal := nil;
FD_ZERO(FDSet);
FD_SET(FSocket.SocketHandle, FDSet);
if not WaitForInput then
begin
New(TimeVal);
TimeVal.tv_sec := 0;
TimeVal.tv_usec := 1;
end;
RetVal := select(0, @FDSet, nil, nil, TimeVal);
if Assigned(TimeVal) then
FreeMem(TimeVal);
if RetVal = SOCKET_ERROR then
raise ESocketConnectionError.Create(SysErrorMessage(WSAGetLastError));
if (RetVal = 0) then Exit;
RetLen := FSocket.ReceiveBuf(Sig, SizeOf(Sig));
if RetLen <> SizeOf(Sig) then
raise ESocketConnectionError.CreateRes(@SSocketReadError);
CheckSignature(Sig);
RetLen := FSocket.ReceiveBuf(StreamLen, SizeOf(StreamLen));
if RetLen = 0 then
raise ESocketConnectionError.CreateRes(@SSocketReadError);
if RetLen <> SizeOf(StreamLen) then
raise ESocketConnectionError.CreateRes(@SSocketReadError);
Result := TDataBlock.Create as IDataBlock;
Result.Size := StreamLen;
Result.Signature := Sig;
P := Result.Memory;
Inc(Integer(P), Result.BytesReserved);

{this next line is for safety , because I detect one case where the code can't not read the first time, 60000 is tentative, maybe
INFINITE is correct}
if (StreamLen > 0) then WaitForSingleObject(FEvent, 60000);{##Add}
bFirst := True; {##ADD} {this line maybe I can don't use , but I keep it because the same case in first time}
while StreamLen > 0 do
begin
RetLen := FSocket.ReceiveBuf(P^, StreamLen);
if RetLen = 0 then
begin {##Add}
if not bFirst then {##ADD} {this is because If you retry you get the correct data!!}
raise ESocketConnectionError.CreateRes(@SSocketReadError);

bFirst := False; {##ADD}
end;

if RetLen > 0 then
begin
Dec(StreamLen, RetLen);
Inc(Integer(P), RetLen);
end;

{##ADD} {This is the CODE this the more important part of the fix}
if StreamLen > 0 then {Only when you need mare than one recv, i fyou put this code before reveivebuf you are an step delayed
and the connection don't close or has many time to read , because WSAResetEvent(FEvent) in caller
function!}
begin
if (WaitForSingleObject(FEvent, 90000) = WAIT_OBJECT_0) then {I wait for read, maybe you can change 90000 with INFINITE}
begin
WSAResetEvent(FEvent);{I reset the event, very important because Wait don't work}
end
else
begin
raise ESocketConnectionError.Create('Read Error Single Object Timeout');
end;
end;
{##END ADD}
end;
if StreamLen <> 0 then
raise ESocketConnectionError.CreateRes(@SInvalidDataPacket);
InterceptIncoming(Result);
end;


Manuel Parma
mparma@usa.net
 
总之:
scktsrvr.exe要慎用
 
const
FD_MAX_EVENTS = 10;

FD_READ_BIT = 0;
FD_WRITE_BIT = 1;
FD_OOB_BIT = 2;
FD_ACCEPT_BIT = 3;
FD_CONNECT_BIT = 4;
FD_CLOSE_BIT = 5;
FD_QOS_BIT = 6;
FD_GROUP_QOS_BIT = 7;
FD_ROUTING_INTERFACE_CHANGE_BIT = 8;
FD_ADDRESS_LIST_CHANGE_BIT = 9;

type
_WSANETWORKEVENTS = record
lNetworkEvents: Integer;
iErrorCodes: array [0..FD_MAX_EVENTS - 1] of Integer;
end;
PWSANetworkEvents = ^TWSANetworkEvents;
TWSANetworkEvents = _WSANETWORKEVENTS;

function WSAEnumNetworkEvents(s: TSocket; hEventObject: THandle;
lpNetworkEvents: PWSANetworkEvents): Integer; stdcall; external 'ws2_32.dll';


procedure TSocketDispatcherThread.ClientExecute;

function IsClose(socket, event: THandle): Boolean;
var
Network: TWSANetworkEvents;
begin
FillChar(Network, SizeOf(Network), 0);
Result := WSAEnumNetworkEvents(socket, event, @Network) = SOCKET_ERROR;
if not Result then
Result := ((Network.lNetworkEvents and FD_CLOSE) = FD_CLOSE);
end;

var
Data: IDataBlock;
msg: TMsg;
Obj: ISendDataBlock;
Event: THandle;
WaitTime: DWord;
begin

...
case MsgWaitForMultipleObjects(1, Event, False, WaitTime, QS_ALLEVENTS) of
WAIT_OBJECT_0:
begin
{ 如果客户端断开,也会触发,然后用IsClose判断一下,是否Client主动断开连接 }
{ 当前IsClose依赖Event的状态,所以,需要放在WSAResetEvent的前面 }
if IsClose(ClientSocket.SocketHandle, Event) then
begin
FTransport.Connected := False;
break;
end;
{ *************** }
WSAResetEvent(Event);
*******************************************
Data := FTransport.Receive(False, 0); 在客户端断开连接时,这里总是出错。
*******************************************
if Assigned(Data) then
begin
FLastActivity := Now;
FInterpreter.InterpretData(Data);
Data := nil;
FLastActivity := Now;
end;
end;

MsgWaitFor中,进行侦听Event事件,Event事件是由TSocketTransport中关联了一个Socket的FD_READ和FD_CLOSE,
当客户端主动断开,MsgWaitFor也会返回,但如果读数据的话,肯定是出错的,一般来说,在FTransport.Receive
会出现,因为数据读错,所以一般来说LAN中是不会出错,因为一旦出错,Receive出抛出异常,就会断开当前线程,
但在Internet上的客户端偶没正式测试过。你试试看吧。

当然,如果可以,你可以再改点东西,如设置TSocketTransport.Socket中的Read Timeout, write Timeout时间,
这样可以确保一点。
 
其实这类系统用webservices是最适合的,Internet上就得用基于http协议和httpserver的方式.而java更适合作这类系统的中间层服务器平台,有成熟的appserver和解决方案.
我现在做的系统就是这样的,client是用delphi写的.只可惜因我们公司和我们客户的原因,可能没法用上与系统对应的硬件平台(服务器,网络...)等,可能难以取得理想的效果.

 
scktsrvr.exe还有一个问题:当SQLSERVER2000服务启动后,就不能运行此程序,没有任何反应或错误消息。只能先运行scktsrvr.exe,再启动SQLSERVER2000。
在5台服务器上有2台出现此现象,原因不明。
 
学习,收藏!
 
用DWBDataSet 0.63 试试
http://www.dekit.net/DWB/Default.asp
 
后退
顶部