关于ClientSocket的怪问题(50分)

  • 主题发起人 主题发起人 shangcm
  • 开始时间 开始时间
S

shangcm

Unregistered / Unconfirmed
GUEST, unregistred user!
我作了一个C/S程序:client向server发送一个字符串(自定义命令),server收到后根据
client的要求,向client发送所需的文件。这个过程已经在各位富翁的帮助下完成。

为了让程序可移植性增强,client的ClientSocket的属性是从配置文件(ini文件)中
读取的,具体就是说server的IP地址和端口。

现在我遇到了一个奇怪的问题:
当我修改ini文件中关于IP的信息后,重新运行client时,该client还是连接修改前的server。
这个现象一直存在。除非重启或不运行该client程序一段时间才会使用新的IP!
(close和active:=false方法我都试过了,问题依旧)

我现在怀疑是否断开连接和建立连接一样需要一段时间?
(1)如果这样,我将client关闭后,该连接信息保存在什么地方?
(2)我该怎样解决这个讨厌的问题,即如何立即结束连接?

以上问题谁遇到过?
请大家帮帮忙,先谢了!
 
兄弟姐妹们,看在“大富翁”的情面上,拉兄弟一把吧!
 
真的这么难?
还是没人理我?
我好可怜!
 
shangcm兄弟,我也一样,问题也没什么人回答。真不知道是不懂呢,还是不愿意???
我的问题大家也帮忙看看!!!
http://www.delphibbs.com/delphibbs/dispq.asp?LID=480123
 
是不是分数太低了?如果有必要,我可以增加分数!
 
大家在百忙中抽出一点时间,帮帮我吧!
 
好象不可能哟,可否说详细一些,关于你的代码?
想知道你打开INI的方式
 
这是ini文件的内容:
[server]
address=211.65.0.168
cmdport=8089
fileport=8088
[local]
path=d:/asst/
run=asst.exe
ini=asst.ini
[files]
count=2
file1=asst.exe
file2=asst.ini

这是客户端程序:
unit main;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ShellAPI, StdCtrls, IniFiles, Buttons, RXCtrls, RxGrdCpt, ScktComp;

type
TMainForm = class(TForm)
SpeedButton1: TSpeedButton;
SpeedButton2: TSpeedButton;
RxLabel1: TRxLabel;
RxLabel2: TRxLabel;
RxLabel3: TRxLabel;
RxGradientCaption1: TRxGradientCaption;
RxLabel4: TRxLabel;
RxLabel5: TRxLabel;
ClientSocket1: TClientSocket;
ClientSocket2: TClientSocket;
procedure FormActivate(Sender: TObject);
procedure SpeedButton1Click(Sender: TObject);
procedure SpeedButton2Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
procedure ClientSocket2Read(Sender: TObject; Socket: TCustomWinSocket);
private
{ Private declarations }
public
{ Public declarations }
end;

var
MainForm: TMainForm;
ServerAddress,cmdPort,filePort,File1,File2,LocalPath,RunName,IniName:string;
FileSize,RecvSize:Integer;

implementation

{$R *.DFM}

function CanRun:Boolean;
begin
//是否可以运行
if FileExists(LocalPath+RunName) and FileExists(LocalPath+IniName) then
Result:=True
else Result:=False;
end;

procedure GetInfo;
var
InfoFile:TIniFile;
begin
//获取配置信息
InfoFile:=TIniFile.Create(ExtractFilePath(Application.ExeName)+'/checker.ini');
with InfoFile do
begin
ServerAddress:=ReadString('server','address','211.65.0.168');
cmdPort:=ReadString('server','cmdport','8089');
filePort:=ReadString('server','fileport','8088');
LocalPath:=ReadString('local','path','d:/asst/');
RunName:=ReadString('local','run','asst.exe');
IniName:=ReadString('local','ini','asst.ini');
File1:=ReadString('files','file1','asst.exe');
File2:=ReadString('files','file2','asst.ini');
Free;
end;
end;

procedure TMainForm.FormActivate(Sender: TObject);
begin
//获取配置信息
FileSize:=0;
RecvSize:=0;
GetInfo;
with ClientSocket1 do
begin
Address:=ServerAddress;
Port:=StrToInt(filePort);
Open;
end;
with ClientSocket2 do
begin
Address:=ServerAddress;
Port:=StrToInt(cmdPort);
Open;
end;
SpeedButton2.Enabled:=CanRun;
end;

procedure TMainForm.SpeedButton1Click(Sender: TObject);
begin
//更新上机助手
if FileExists(LocalPath+RunName) then DeleteFile(LocalPath+RunName);
ClientSocket2.Socket.SendText('/download -'+File1);
end;

procedure TMainForm.SpeedButton2Click(Sender: TObject);
begin
//运行上机助手
Winexec(PChar(LocalPath+RunName),SW_SHOW);
Close;
end;

procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if ClientSocket1.Active then ClientSocket1.Close;
if ClientSocket2.Active then ClientSocket2.Close;
end;

procedure TMainForm.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
var
Buffer:pointer;
nRetr:integer;
fs:TFileStream;
const
BufferSize=8760;
begin
GetMem(Buffer,BufferSize);
nRetr:=Socket.ReceiveBuf(Buffer^,BufferSize);
if not FileExists(LocalPath+File1) then
begin
fs :=TFileStream.Create(LocalPath+File1,fmCreate or fmShareDenyNone);
fs.Seek(0,soFromBeginning);
end else
begin
fs :=TFileStream.Create(LocalPath+File1,fmOpenWrite or fmShareDenyNone);
fs.Seek(0,soFromEnd);
end;
fs.WriteBuffer(Buffer^,nRetr);
fs.Destroy;
FreeMem(Buffer);
RecvSize:=RecvSize+nRetr;
if RecvSize=FileSize then SpeedButton2.Click;
end;

procedure TMainForm.ClientSocket2Read(Sender: TObject;
Socket: TCustomWinSocket);
var
SizeMsg:string;
begin
SizeMsg:=UpperCase(Trim(Socket.ReceiveText));
if Pos('FILESIZE=',SizeMsg)=1 then
FileSize:=StrToInt(Copy(SizeMsg,10,Length(SizeMsg)-9));
end;

end.
 
请大家看看!
 
大家都没遇到过吗?
帮帮忙吧!
 
我没有写测试程序,我看了一下TClientSocket的原码 可能和这里有关
procedure TClientSocket.DoActivate(Value: Boolean);
begin
if (Value <> FClientSocket.Connected) and not (csDesigning in ComponentState) then
begin
if FClientSocket.Connected then
FClientSocket.Disconnect(FClientSocket.FSocket)
else FClientSocket.Open(FHost, FAddress, FService, FPort, ClientType = ctBlocking);
end;
end;
也就是说 如果FClientSocket(这是TClientSocket内部的套接字连接类)还存在连接
TClientSocket只是断开(是否真正断掉要等候服务断返回一个确认,祥见TCP的三次握手
),所以你这时重新设置属性连接没有用
你可以试着这样解决,使用动态创建的方法创建TClinetSocket,用完后断开释放需要的
时候重新创建
 
我赞同Tintin的观点,最好采用动态的方法创建TClientSocket,
用完后断开释放,需要时重新创建。
不过,Socket建立连接是通过三次握手协议达成,而断开连接只是二次握手。
另外,你还应该要注意接收数据时的函数重入问题。
 
也许是INI文件在作怪!
因为INI文件属于初始化文件,一旦被加载会在系统中登记并保留一段时间。
原来在编写局域网通信程序时曾经碰到过被修改的INI文件不能马上生效。
建议使用一般的文本文件,例如:
a.txt

serveraddress=xxx.xxx.xxx.xxx
...

在程序初始化时用TStringList将其读入并自己解析字符串。
 
多谢 hdzj2000 !
的确是ini文件在作怪!用 hdzj2000 的方法可以解决!谢谢!

xiaoyebing 和 Tintin 的说法也有道理,我一直怀疑是这个问题,
但我用你们的方法总是与服务器连接不上,可能是我的问题。
有时间再继续讨论。

至于分嘛,你们看这样分行不行?
hdzj2000 40
xiaoyebing 5
Tintin 5

再次感谢各位!谢谢!
 
多人接受答案了。
 
后退
顶部