IdTCPClient与 IdTCPServer 间传输问题,请指教。

sqrkim 2009-05-09 10:45:03
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, DB, Grids, DBGrids, StdCtrls, ADODB, IdTCPServer,
IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient;

type
Tuser = record
s_id:array[0..50] of string;
s_name:array[0..50] of string;
s_age:array[0..50] of string;
s_text:array[0..50] of string;
dt_date:array[0..50] of TDateTime;
end;

TForm1 = class(TForm)
ADOConnection1: TADOConnection;
Button1: TButton;
DBGrid1: TDBGrid;
DataSource1: TDataSource;
Memo1: TMemo;
IdTCPClient1: TIdTCPClient;
IdTCPServer1: TIdTCPServer;
ADOQuery1: TADOQuery;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure IdTCPServer1Execute(AThread: TIdPeerThread);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
strm: TMemoryStream;
//user:Tuser;
implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var i:integer; user:Tuser;
begin
strm:= TMemoryStream.Create;

ADOQuery1.First;
while not ADOQuery1.Eof do
begin
for i:= 1 to ADOQuery1.RecordCount do
begin
user.s_id[i-1]:= ADOQuery1.FieldByName('i_id').AsString;
user.s_name[i-1]:= ADOQuery1.FieldByName('vc_name').AsString;
user.s_age[i-1]:= ADOQuery1.FieldByName('vc_age').AsString;
user.s_text[i-1]:= ADOQuery1.FieldByName('vc_text').AsString;
user.dt_date[i-1]:= ADOQuery1.FieldByName('dt_date').AsDateTime;
ADOQuery1.Next;
end;
end;

strm.WriteBuffer(user,sizeof(Tuser));

self.IdTCPClient1.Host:='127.0.0.1';
self.IdTCPClient1.Port:=9999;
try
self.IdTCPClient1.Connect(5000);
//self.IdTCPClient1.Writebuffer(strm,sizeof(strm));
self.IdTCPClient1.WriteStream(strm,true,False);
self.IdTCPClient1.Disconnect;
except
on e:exception do
memo1.Lines.Add(e.Message);
end;

strm.Free;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
with ADOQuery1 do
begin
Close;
SQL.Clear;
SQL.Add('select * from sy');
Open;
end;

self.IdTCPServer1.DefaultPort:=9999;
self.IdTCPServer1.Active:= true;
end;

procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
var
i:integer; user:TUser;
begin
strm:= TMemoryStream.Create;

with AThread.Connection do
begin
AThread.Connection.ReadStream(strm,-1,FALSE);// 跟踪:strm显示为strm(),证明数据没过来
strm.ReadBuffer(user,sizeof(TUser));
memo1.Lines.Add(user.s_id[1]); //没有看到user.s_id[1]的数据
end;
end;

end.

不知道具体应该怎么改,谢谢大家。
...全文
177 17 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
sqrkim 2009-05-09
  • 打赏
  • 举报
回复
我试验了 如果中间不用TMemoryStream的话 client端直接用self.IdTCPClient1.Writebuffer(user,sizeof(Tuser)); server端用AThread.Connection.ReadBuffer(user,sizeof(TUser)); 这样的话数据是可以读出来的。但是老是报AV的错误,实在是头疼
sqrkim 2009-05-09
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 unsigned 的回复:]
Server端ReadStream前先Read四个字节,比如使用ReadInteger之类的,然后再根据这四个字节ReadStream.接着又是Read四个字节,ReadStream...依此类推.
[/Quote]
那我是不是可以直接设置strm.Position:= 4;挪到第4个字节然后开始读,可是还是没效果。你说的用 readinteger 能再具体一些么?
或者会不会是我写的时候哪里出错了?没有写进去。
僵哥 2009-05-09
  • 打赏
  • 举报
回复
Server端ReadStream前先Read四个字节,比如使用ReadInteger之类的,然后再根据这四个字节ReadStream.接着又是Read四个字节,ReadStream...依此类推.
sqrkim 2009-05-09
  • 打赏
  • 举报
回复
没人帮忙?
ks_reny 2009-05-09
  • 打赏
  • 举报
回复
學習
sqrkim 2009-05-09
  • 打赏
  • 举报
回复
自己顶下
sqrkim 2009-05-09
  • 打赏
  • 举报
回复
哈哈 哦了 结贴。
SuperTitan001 2009-05-09
  • 打赏
  • 举报
回复
这个就要你自己处理了,如果有大的就定义大点,呵呵
sqrkim 2009-05-09
  • 打赏
  • 举报
回复
那如果长度不够100 或者超出100了呢?程序会做何处理?
SuperTitan001 2009-05-09
  • 打赏
  • 举报
回复
固定长度100,这样sizeof(user)就有了准确的值了
sqrkim 2009-05-09
  • 打赏
  • 举报
回复
啊 明白了 原来是这样。谢谢SuperTitan001,最后一个问题s_name:array[0..50] of string[100]中 string[100]的意思是说 s_name的最大字符长度为100么?
SuperTitan001 2009-05-09
  • 打赏
  • 举报
回复
刚刚试了试
客户端:

procedure TForm1.BitBtn1Click(Sender: TObject);
var
i:integer;
user:Tuser;
begin
IdTCPClient1.Host:='127.0.0.1';
IdTCPClient1.Port:=9999;
try
self.IdTCPClient1.Connect(5000);
for i:= 0 to 50 do
begin
user.s_id[i]:= inttostr(i);
user.s_name[i]:= 'name'+inttostr(i);
user.s_age[i]:= 'age'+inttostr(i);
user.s_text[i]:= 'text'+inttostr(i);

end;
IdTCPClient1.WriteBuffer(user,sizeof(user),true);
except
on e:exception do
memo1.Lines.Add(e.Message);
end;
IdTCPClient1.Disconnect;
end;

服务端:

procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
var
user:Tuser;
i:integer;
begin
AThread.Connection.ReadBuffer(user,sizeof(user));
for i:=0 to 50 do
memo1.Lines.Add(user.s_name[i]);
end;


关键是服务端要知道数据包的大小
SuperTitan001 2009-05-09
  • 打赏
  • 举报
回复
type
Tuser = record
s_id:array[0..50] of string;
s_name:array[0..50] of string;
s_age:array[0..50] of string;
s_text:array[0..50] of string;
end;

改成
Tuser = record
s_id:array[0..50] of string[100];
s_name:array[0..50] of string[100];
s_age:array[0..50] of string[100];
s_text:array[0..50] of string[100];

中间就不要用什么MemoryStream了
发送就是IdTCPClient1.WriteBuffer(user,sizeof(user),true);

接收用AThread.Connection.ReadBuffer(user,sizeof(user));

我试过是可以的
sqrkim 2009-05-09
  • 打赏
  • 举报
回复
还有个问题 我在跟踪的时候发现cmd:= Readln();//接收到client端传来的流长度 为0, 是不是strm.WriteBuffer(user,sizeof(Tuser));根本就没有写入进去啊?
sqrkim 2009-05-09
  • 打赏
  • 举报
回复
谢谢unsigned 和 supertitan001 的帮助和指点。我理解后编译如下代码,不知是否正确 还请指点。

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, DB, Grids, DBGrids, StdCtrls, ADODB, IdTCPServer,
IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient;

type
Tuser = record
s_id:array[0..50] of string;
s_name:array[0..50] of string;
s_age:array[0..50] of string;
s_text:array[0..50] of string;
//dt_date:array[0..50] of TDateTime;
end;

TForm1 = class(TForm)
ADOConnection1: TADOConnection;
Button1: TButton;
DBGrid1: TDBGrid;
DataSource1: TDataSource;
Memo1: TMemo;
IdTCPClient1: TIdTCPClient;
IdTCPServer1: TIdTCPServer;
ADOQuery1: TADOQuery;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure IdTCPServer1Execute(AThread: TIdPeerThread);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
strm: TMemoryStream;
//user:Tuser;
implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var i:integer; user:Tuser; cmd:string;
begin
ADOQuery1.First;

//赋值
while not ADOQuery1.Eof do
begin
for i:= 1 to ADOQuery1.RecordCount do
begin
user.s_id[i-1]:= ADOQuery1.FieldByName('i_id').AsString;
user.s_name[i-1]:= ADOQuery1.FieldByName('vc_name').AsString;
user.s_age[i-1]:= ADOQuery1.FieldByName('vc_age').AsString;
user.s_text[i-1]:= ADOQuery1.FieldByName('vc_text').AsString;
//user.dt_date[i-1]:= ADOQuery1.FieldByName('dt_date').AsDateTime;
ADOQuery1.Next;
end;
end;
strm:= TMemoryStream.Create;
strm.WriteBuffer(user,sizeof(Tuser));

IdTCPClient1.Host:='127.0.0.1';
IdTCPClient1.Port:=9999;
try
self.IdTCPClient1.Connect(5000);
IdTCPClient1.WriteLn(IntToStr(strm.Size)); //向服务器发送流的大小,此时跳到服务器端
cmd:= IdTCPClient1.ReadLn; //接受服务器端的命令字符,在这里我暂时设置为空
IdTCPClient1.OpenWriteBuffer; //准备发送缓冲
IdTCPClient1.WriteStream(strm,true,true,strm.Size);
IdTCPClient1.CloseWriteBuffer; //结束发送缓冲

IdTCPClient1.Disconnect;
except
on e:exception do
memo1.Lines.Add(e.Message);
end;

strm.Free;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
with ADOQuery1 do
begin
Close;
SQL.Clear;
SQL.Add('select * from sy');
Open;
end;

self.IdTCPServer1.DefaultPort:=9999;
self.IdTCPServer1.Active:= true;
end;

procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
var
i:integer; user:TUser; cmd:string;
begin
strm:= TMemoryStream.Create;

with AThread.Connection do
begin
cmd:= Readln();//接收到client端传来的流长度
strm.Size:= StrToInt(cmd);//设置要接收的流的大小
WriteLn('BEGIN');//返回client端开始传输数据,此时跳转到client端

ReadStream(strm,-1,True); //这里报错 AV错误

strm.ReadBuffer(user,sizeof(TUser));
memo1.Lines.Add(user.s_id[1]);
end;
end;

end.
SuperTitan001 2009-05-09
  • 打赏
  • 举报
回复
你在传送string的时候,服务器端无法知道你传送的总字节数是多少。
楼上说的是一个办法。
另外可以将string改为固定长度,比如string[200]。另外Tdatetime也是传不了的,也用字符串传送吧
僵哥 2009-05-09
  • 打赏
  • 举报
回复
当然不是.
WriteStream(Stream,true,true (*注意这个参数,它实际了先发送四个字节作为后续Stream的实际长度,就形成了一个简单的网络协议*))

因此,你只需要在接收端先接收4个字节作为长度,然后再根据这个长度来接收后续数据即可.

个人建议楼主加深点网络编程方面的基础知识,先了解什么是TCP流协议.
访问真八字排盘系统介绍: 1、八字排盘 八字排盘是将年月日时按照天干地支的形式进行排列,一个时单位代表了一个柱。八字由年柱、月柱、日柱和时柱共四个柱组成,也被称为四柱八字。八字学中基于中国阴阳五行、天干地支与刑冲克害、以及民盲派的神煞论等方式,进一步预测爱情顺遂、工作高低、姻缘好坏、财富高低、学业成就、身体健康等事的学问。 八字排盘由以下元素组合:年月日时四柱、大运干支、胎元 、流年干支、十神、地势、神煞等。生辰八字不只是把干支历计算出来,而还要遵守月令、节令的强弱,时辰的阴阳变化进行校正。排盘分析,就是根据出生者的性别、天干地支的阴阳五行关系、进一步推算出来的一套方法论,给预测者做人生吉凶的参考数据,在未来事业、财运、婚姻、家庭等问题时,能做出风险较低的决策。 八字排盘怎么看 八字排盘由年、月、日、时四柱组成,每柱包含一个天干和一个地支,共八个字。年柱代表出生的年份,月柱代表出生的月份,日柱代表出生的日期,时柱则代表出生的时辰。每个柱的干支组合都会对个人的命运产生影响。天干地支旁边标注的正财、偏财、偏印、正印、比肩、劫财、食神、伤官、正官、七杀等,称为十神。 2、八字排盘软件介绍 我们是腾讯云市场金牌合作伙伴,广州正规软件开发公司,开发的八字排盘系统数据最全面精准,我们八字排盘采用最精确的排盘程序,而且运用“真太阳时”,进行更精确的时划分。大家都知道我们使用的北京时,是统一规定的标准时。而八字排盘需要相对于太阳方位的天文时,即平太阳时。我们国家地大物博,北京时19时,哈尔滨已经夜幕降临,而新疆却还是太阳高挂,这时哈尔滨的天文时可能在20:00以后,而新疆的天文时可能在16时以前。北京时是东经120度经线的平太阳时,如果您出生地的经度与北京时所处的经度差异较大,或者处于单数时点的前后,比如6点差一刻,8点,10点15分等

1,594

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 网络通信/分布式开发
社区管理员
  • 网络通信/分布式开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧