ClientSocket收发记录型问题?(在线等!!!) (200分)

  • 主题发起人 主题发起人 insert2003
  • 开始时间 开始时间
I

insert2003

Unregistered / Unconfirmed
GUEST, unregistred user!
服务端用VC写好的,完全正确,无需我处理!

const
d_MaxDetailNum = 100;

flagLogin = $80;
flagQueryInfo = $82;
flagChangePassword = $83;
flagQueryAmount = $85;
flagQueryDetail = $86;
flagCharge = $89;

d_LogName_Len = 20;
d_LogPassword_Len = 10;
d_CardNo_Len = 20;
d_Phone_Len = 7;
d_Name_Len = 30;
d_IDCardNo_Len = 18;
d_Address_Len = 40;
d_LinkTel_Len = 30;
d_Date_Len = 8;
d_Time_Len = 19;
d_DealNo_Len = 14;

d_Error_Ok = $00; //
d_Error_CommError = $01; // 通信错误
d_Error_InvalidName = $02; // 登录名错误
d_Error_PasswordError = $03; // 密码错误
d_Error_AcccountFreeze = $04; // 帐户冻结
d_Error_InvalidPhone = $05; // 非法电话
d_Error_SystemError = $06; // 系统
d_Error_NoData = $07; // 没有数据
d_Error_OtherError = $ff; // 其它错误

type
structClientPackHead = Record // 数据包
uPackLength :Longint;
uFlag :Longint;
cRequire :char;
cAnswer :char;
cCRC :array[0..5] of char ;
end;

structClientLogin = packed Record //登录数据
cLogNamm :array[0..d_LogName_Len] of char;
cLogPassword :array[0..d_LogPassword_Len] of char;

end;

structClientChangePassword = Record //修改密码
cOldPassword :array[0..d_LogPassword_Len] of char;
cNewPassword :array[0..d_LogPassword_Len] of char;
end;

structClientQueryInfo = Record // 查询机主资料
cPhone :array[0..d_Phone_Len] of char;
cCardNo :array[0..d_CardNo_Len] of char;
end;

structClientQueryInfoAnswer = Record // 查询机主资料应答
cPhone :array[0..d_Phone_Len] of char;
cCardNo :array[0..d_CardNo_Len] of char;
cName :array[0..d_Name_Len] of char;
cIDCardNo :array[0..d_IDCardNo_Len] of char;
cAddress :array[0..d_Address_Len] of char;
cLinkTel :array[0..d_LinkTel_Len] of char;
end;

structClientCharge = Record // 充值
cPhone :array[0..d_Phone_Len] of char;
cCardNo :array[0..d_CardNo_Len] of char;
uAmount :Integer;
end;

structClientQueryAmount = Record // 查询充值金额
cStartDate :array[0..d_Date_Len] of char;
cEndDate :array[0..d_Date_Len] of char;
cPhone :array[0..d_Phone_Len] of char;
cCardNo :array[0..d_CardNo_Len] of char;
end;

structClientQueryAmountAnswer = Record // 查询充值金额返回
uNum :Integer ;
uAmount :Integer;
end;

structClientQueryDetail = Record // 查询充值明细
cStartDate :array[0..d_Date_Len] of char;
cEndDate :array[0..d_Date_Len] of char;
cPhone :array[0..d_Phone_Len] of char;
cCardNo :array[0..d_CardNo_Len] of char;
end;

structClientChargeDetail = Record // 询充值金额返回
cPhone :array[0..d_Phone_Len] of char;
cCardNo :array[0..d_CardNo_Len] of char;
uAmount :Integer;
cTime :array[0..d_Time_Len] of char;
cDealNo :array[0..d_DealNo_Len] of char;
end;

structClientQueryDetailAnswer = Record // 查询充值明细返回
uDetailNum :Integer;
ChargeDetail :array[0..d_MaxDetailNum-1] of structClientChargeDetail;
end;

structClientPack = packed Record // 数据包
PackHead :structClientPackHead; //包头
case Integer of
1 :(Login :structClientLogin;); // 登录数据
2 :(ChangePassword :structClientChangePassword;); // 修改密码
3 :(QueryInfo :structClientQueryInfo;); // 查询机主资料
4 :(QueryInfoAnswer :structClientQueryInfoAnswer;); // 查询机主资料应答
5 :(Charge :structClientCharge;); // 充值
6 :(QueryAmount :structClientQueryAmount;); // 查询充值金额
7 :(QueryDetail :structClientQueryDetail;); // 查询充值金额返回
8 :(QueryDetailAnswer :structClientQueryDetailAnswer;); // 查询充值明细返回
end;

问题一:这样赋值得是否正确:
strpcopy(loginclinet.Login.cLogNamm,trim(edit1.Text));
strpcopy(loginclinet.Login.cLogPassword,trim(edit2.Text));
loginclinet.PackHead.uPackLength :=sizeof(structClientPack);
loginclinet.PackHead.uFlag := flagLogin;
loginclinet.PackHead.cRequire :='';
loginclinet.PackHead.cAnswer :='';

问题二:这样发送怎么不行:
var
loginclinet : structClientPack;

clientsocket1.Socket.SendBuf(loginclinet,sizeof(structClientPack));

问题三:怎么接收服务端发过来的数据,服务端定义了现客户端一至的记录类型。
是否用此socket.ReceiveBuf()接收,请问此socket.ReceiveBuf()里面的参数应该怎么写!
 
最前面定义了一此常量,中间是定义了一些记录型,最后定义了主记录型变量。
 
这是个可变结构,DELPHI不知道他的大小,根据具体发送的内容,用头的大小加上相应结构体的大小
 
to:weiwei81123
可否举个例子???
 
比如你要登陆,填好PackHead与Login后,这样发送:
clientsocket1.Socket.SendBuf(loginclinet,sizeof(structClientPackHead)+sizeof(structClientLogin));
 
多谢weiwei81123,
再问一个问题,(是不是有点过份:P)
也是socket保持连接的问题:
有一个专门登录服务器的登录窗口,登录成功后,关闭此窗口,就断开连接了,
请问,怎样在我关闭此窗口的情况下保持连接。
此登录窗口是子窗口。
 
如果你的子窗体是工程自动建立的,那么你将关闭连接的代码写在OnDestroy而不是OnClose或???Click就行了,窗体没有销毁,在主窗体中你可以用frmLogin.xxx的方式访问的。
如果你的子窗体是动态创建的,那么得另开一个单元,将Socket连接及处理部分放到这个新单元了,让子窗体与主窗体都引用它。
 
只要登陆窗口没有被销毁并且你的代码没有关闭连接就会保持连接
关闭窗口并不等于销毁了该窗口,在OnClose中可以设置,默认操作是隐藏
动态创建的窗口在你将它Free掉之前也没有被销毁,不一定要另开一个单元
 
问题一:这样赋值得是否正确:
move(string(trim(edit1.Text))[1],loginclinet.Login.cLogNamm,length(trim(edit1.Text)));
move(string(trim(edit2.Text))[1],loginclinet.Login.cLogPassword,length(trim(edit2.Text)));
loginclinet.PackHead.uPackLength :=sizeof(structClientPack);
loginclinet.PackHead.uFlag := flagLogin;
loginclinet.PackHead.cRequire :='';
loginclinet.PackHead.cAnswer :='';

问题二:这样发送怎么不行:
var
loginclinet : structClientPack;
clientsocket1.Socket.SendBuf(loginclinet,sizeof(structClientPack));
应该是可以的啊,因为你的记录都是定长的,用数组表示字符串,可以的!

问题三:怎么接收服务端发过来的数据,服务端定义了现客户端一至的记录类型。
是否用此socket.ReceiveBuf()接收,请问此socket.ReceiveBuf()里面的参数应该怎么写!
若你用tserversocket,只要事件即可,
若你用WinSocket,在接受事件中用
recv(YouSocketHandle,RecBuf, RecCount, 0);即可。

 
为什么我发送过去的数值与在服务端接收的数值不一样呢?

ChargeClient.PackHead.uPackLength := sizeof(structClientPackHead) + sizeof(structClientCharge);
ChargeClient.PackHead.uFlag := flagPack;
ChargeClient.PackHead.cRequire := flagCharge;
ChargeClient.PackHead.cAnswer := 5;
//上面为包头信息(正确的)

strpcopy(ChargeClient.Charge.cPhone,cPhonec);
strpcopy(ChargeClient.Charge.cCardNo,cCardc);
ChargeClient.Charge.uAmount := iAmunt;
//上面为电话号码、卡号(正确的)、金额(服务端接收的值与我发过去的值不一致,每次都是一个固定值,不是0就是1394637056)。

form2.ClientSocket1.Socket.SendBuf(ChargeClient,sizeof(structClientPackHead) + sizeof(structClientCharge));
//发送

iAmunt定义为integer
服务端(VC写)定义为:uint,

问题:Delphi的integer与VC的uint应该是一至的吧?
为什么我发过去的包与接收的值不一致呢?但前面的电话号与卡号为何又是正确的呢?难道是类型问题?还是其它呢?请高手指点!!!
 
Delphi的integer与VC的int是一致的!
Delphi的dword与VC的uint是一致的!
 
自动对齐导致的问题
所有Record都用packed就好了
或使用{$A-}
 
为什么我发过去的包与接收的值不一致呢?但前面的电话号与卡号为何又是正确的呢?难道是类型问题?还是其它呢?请高手指点!!!
-----------------
这个问题简单,主要是字节对其问题,VC程序员一般都是以 1 字节对其的,你只需这样作即可porject->option->complier->code generation中把optionmizition关闭,然后record field alidment 改为 1 即可

若你不想更动这些选项,只需再程序里把record 改为 packed record即可
 
多谢各位的解答,通过你们的提示,我全部加了 packed ,并把充值包的integer 改为longword类型,但是,结果令人烦闷,还是一样,不对,我发送20过去,变成11514624了。

我把这些记录类型都定义在一unit(pass)文件中,然后引用该unit(pass)文件,与此应该无关吧,想不出是什么原因,只能。。。。。
还有,ChargeClient.Charge.uAmount := iAmunt;的 iAmount 的值我是通过
strtoint(trim(edit1.text)) 得来的,这样行不行啊???
 
多个窗口都要用到TCP连接,就在这些窗口中都引用一个新单元,该单元中引用TCPClient,在第一个窗口动态建立,然后在每个窗口就可以用,窗口销毁也没关系!!
我已经用TIdTcpClient实现!
 
多谢各位,问题已解决。
保持连接的问题:我是把clientSocket 置于主窗口上!
后面发送值的问题:把所有的 packed 全部去掉就没问题了!
等等再结贴!
 
讨论一下,有无可能做一个程序,
装在别人的机上,然后通过该程序将当前用户操作员的内容截取下来,
可否通过Windows的内核等什么API之类的来实现啊!
截取屏幕是可以的,但要的是当前操作窗口的内容取出来,这可不可能呢?
 
保持连接的问题:我是把clientSocket 置于主窗口上!
======================================================
不妥!!
虽然说这样做可以,但是,每次启动你都要把主窗口建立并隐藏,先显示登陆窗口,如果登陆失败或用户只显示登陆窗口而暂时不登陆等等,程序也将耗费大量资源,这是很糟糕的编程思维!
 
是啊,我的主窗口代码都不知道写了多长了,开始因为上面催得紧,就放到主窗口来了,
等会改过来吧,谢谢~~~
 

Similar threads

I
回复
0
查看
564
import
I
S
回复
0
查看
1K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
后退
顶部