用socket控件传送图象的问题.(85分)

  • 主题发起人 主题发起人 plwei
  • 开始时间 开始时间
P

plwei

Unregistered / Unconfirmed
GUEST, unregistred user!
我要用socket控件传送图象。
在server端用sendstream(mystream);//mystream:Tmemorystream;
那么在client端怎样接收流mystream呢?
如果说流为上百k可以做到吗?
 
用tcp可以:-)
 
procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
var
buf:array[1..10000] of char;
len:integer;
jpe:TJPEGimage;
begin
len:=socket.ReceiveLength ;//为4261个字节
socket.ReceiveBuf(buf,len);
mystream.Write(buf,len);
jpe:=TJpEGimage.Create ;
mystream.Position:=0;
mystream.Size;//在此变为4262个字节
jpe.LoadFromStream(mystream);//在此系统提示JPEG error #52
image1.Canvas.Draw(0,0,jpe);
jpe.Free;
end;
在server端我用socket.sendstream(stream)发送一个4261大小的文件;client
端用上述代码实现.不知错误是何原因,应如何改正?
如果图象很大的话应该怎么传送?
 
mystream 没有定义,

另外定义了以后,还要Create


 
mystream.Position:=0;
mystream.Write(buf,len);
mystream.setsize(len);
ok!!!
 
cytown:
一点也不OK, 还是老毛病。
 
呵呵, 是server端send的问题了, 检查一下吧.
 
一次传送不能>2KB,好象说过不止一次了.
 
你的client是block模式吗?
如果是的话, 不能用socket.receivebuf接收, 必须用TWinSocketStream来接受.
 
你应该根据发过来的数据流的大小来接收.
W.H.的说法也是你的一个错误
 
我刚成功的实现了这个功能:
客户端主要程序:
var m:TMemoryStream;
p:Pointer; b,i,j,k:integer; s:string;
begin
m := TMemoryStream.Create;
image1.Picture.Bitmap.SaveToStream( m );//假设有一图象控件

GetMem( p, m.size );
m.Position := 0;
m.Read( p^, m.size );

ClientSocket.Socket.SendBuf( p^, m.size );

FreeMem( p );
m.Free;
end;
服务器端的OnClientRead中:
var p:pointer; m:TMemoryStream;
begin
GetMem( p, Size );
Socket.ReceiveBuf( p^, Size );
m := TMemoryStream.Create;
m.Write( p^, Size );
m.Position := 0;
image1.Picture.Bitmap.LoadFromStream(m);//假设有一图象控件
FreeMem(p);
m.Free;
end;
说明一下:Size为LongInt型全局变量用来记录图象尺寸,客户断必须先用
SendText将这个数据传过来服务器端先用Socket的ReceiveText判断这个数据才能有效执行.
如假包换哟!!!!!!
 
如果文件大的话可以用程序切开来试一试,用Text方式比较简单不容易出错呀
 
Aloney大虾说的办法需要每次先传文件大小,这样好象比较烦啊,有没有什么别的办法啊???
 
用TServerSocket和TClientSocket的sendstream方法好象一次最大只能发送
8k的数据,如果大于8k就会出错。Aloney的方法我在D4上试过,如果图片小的
话没问题,大于8K的话就什么也收不到。

我采用拼接的方法实现了任意大小文件的传送(还是有些限制的,下面我将要说
明),以下程序在D4上调试通过:

Client端:(发方)
private
{ Private declarations }
stream : TMemoryStream;
size,count : integer; //定义全局变量

procedure TForm1.Button2Click(Sender: TObject);
begin
stream := TMemoryStream.Create; //流初始化
if OpenDialog1.Execute then
begin
stream.LoadFromFile(OpenDialog1.FileName);
size := stream.Size;
count := 0; //记录位置
ClientSocket1.Socket.SendText(inttostr(size)); //发送文件大小
end;
end;

procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
var
rcvtxt : string;
buf : array [1..8192] of char;
left : integer; //剩余的字节数
begin
rcvtxt := Socket.ReceiveText;
left := size - count; //剩余的字节数
if AnsiPos('go',rcvtxt)=1 then //收方响应了则发送一块
begin
if sizeof(buf)<left then
begin
stream.Read(buf,sizeof(buf));
Socket.SendBuf(buf,sizeof(buf));
count := count + sizeof(buf);
end
else
begin
stream.Read(buf,left);
Socket.SendBuf(buf,left);
end;
end;
end;



Server端:(收方)
private
{ Private declarations }
Tof : file;
size,count :integer;

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
buf : array [1..8192] of char;
rcvtxt : string;
left,len : integer;
begin
len := Socket.ReceiveLength;
if len<10 then //若数据长度少于10位则认为是文件长度
begin
rcvtxt := Socket.ReceiveText;
size := strtoint(rcvtxt);
count := 0;
if SaveDialog1.Execute then
begin
AssignFile(ToF, SaveDialog1.FileName);
Rewrite(ToF, 1);
end;
Socket.SendText('go'); //创立文件后发送一个响应
end
else
begin
left := size - count; //计算剩余字节数
if sizeof(buf)<left then //满一块的则写一块,发送响应
begin
Socket.ReceiveBuf(buf,sizeof(buf));
BlockWrite(Tof,buf,sizeof(buf));
count := count + sizeof(buf);
Socket.SendText('go');
end
else //不满一块则只写剩余的,不用响应
begin
Socket.ReceiveBuf(buf,left);
BlockWrite(Tof,buf,left);
CloseFile(Tof);
end;
end;
end;

由于我的控制条件是用接收的数据长度来判断是否是文件流,对于长度小于10
bytes或长度模8192小于10的文件并不适用,但只要改变一下这个条件则可以
应用于大多数情况了
 
if sizeof(buf)<left then
begin
stream.Read(buf,sizeof(buf));
Socket.SendBuf(buf,sizeof(buf));
count := count + sizeof(buf);
end
else
begin
stream.Read(buf,left);
Socket.SendBuf(buf,left);
end;
end;
end;

Server端:(收方)
private
{ Private declarations }
Tof : file;
size,count :integer; //变量
procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
buf : array [1..8192] of char; //buffer
rcvtxt : string;
left,len : integer;
begin
len := Socket.ReceiveLength;
if len<10 then //小于10则认为是文件长度
begin
rcvtxt := Socket.ReceiveText;
size := strtoint(rcvtxt);
count := 0;
if SaveDialog1.Execute then
begin
AssignFile(ToF, SaveDialog1.FileName);
Rewrite(ToF, 1);
end;
Socket.SendText('go');
end
else //否则认为是数据
begin
left := size - count;
if sizeof(buf)<left then //满一块则写一块并发送响应'go'
begin
Socket.ReceiveBuf(buf,sizeof(buf));
BlockWrite(Tof,buf,sizeof(buf));
count := count + sizeof(buf);
Socket.SendText('go');
end
else
begin //不满一块则说明是最后一块了,不用发响应
Socket.ReceiveBuf(buf,left);
BlockWrite(Tof,buf,left);
CloseFile(Tof);
end;
end;
end;

这个程序的通用性还不够强,但只须稍加改动就可以适应大多数情况了
 
怎么贴不完啊,sigh
 
不好意思,上次因为网络故障,没有发完
我后来又进行了多次实验,发现buffer设
为2K可能是最保险的方法,8K可能速度快
一些,但在有些环境下会出错。
程序如下:

Client端:(发方)

private
stream : TMemoryStream; //定义内存流,其实用
文件流也可以
size,count : integer; //文件大小
end;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
begin
ClientSocket1.Address := Edit1.Text;
ClientSocket1.Active := True;
end;

procedure TForm1.ClientSocket1Connect(Sender: TObject;
Socket: TCustomWinSocket);
begin
StatusBar1.SimpleText := 'Connected to '+Socket.RemoteAddress;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
stream := TMemoryStream.Create;
if OpenDialog1.Execute then
begin
stream.LoadFromFile(OpenDialog1.FileName);
size := stream.Size; //获得文件大小
count := 0;
ClientSocket1.Socket.SendText(inttostr(size)); //先发送大小
end;
end;

procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
var
rcvtxt : string;
buf : array [1..2048] of char;
left : integer;
begin
rcvtxt := Socket.ReceiveText;
left := size - count; //未读字节数
if AnsiPos('go',rcvtxt)=1 then
begin
if sizeof(buf)<left then //若满一块则读一块
begin
stream.Read(buf,sizeof(buf));
Socket.SendBuf(buf,sizeof(buf));
count := count + sizeof(buf);
end
else //不满则发剩余的
begin
stream.Read(buf,left);
Socket.SendBuf(buf,left);
end;
end;
end;


Server端(收方)


private
Tof : file;
size,count :integer;
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.CutFirst(denstr: string;scrstr: string);
var
len :integer;
begin
len := length(scrstr);
denstr := copy(scrstr,2,(len-1));
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
ServerSocket1.Active := True;
StatusBar1.SimpleText := 'Listening...';
end;

procedure TForm1.ServerSocket1Accept(Sender: TObject;
Socket: TCustomWinSocket);
begin
StatusBar1.SimpleText := 'Connected from '+ Socket.RemoteAddress;
end;

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
buf : array [1..2048] of char;
rcvtxt : string;
left,len : integer;
begin
len := Socket.ReceiveLength;
if len<10 then //若长度小于10则认为是文件长度
begin
rcvtxt := Socket.ReceiveText;
size := strtoint(rcvtxt);
count := 0;
if SaveDialog1.Execute then
begin
AssignFile(ToF, SaveDialog1.FileName);
Rewrite(ToF, 1);
end;
Socket.SendText('go');
end
else
begin
left := size - count; //未写的字节数
if sizeof(buf)<left then //满一块则写一块
begin
Socket.ReceiveBuf(buf,sizeof(buf));
BlockWrite(Tof,buf,sizeof(buf));
count := count + sizeof(buf);
Socket.SendText('go');
end
else //否则写剩余字节数
begin
Socket.ReceiveBuf(buf,left);
BlockWrite(Tof,buf,left);
CloseFile(Tof);
end;
end;
end;


这个程序在长度的判断上通用性还不够强,但只需
稍加改动就可以实用了
 
if sizeof(buf)<left then //若满一块则读一块
begin
stream.Read(buf,sizeof(buf));
Socket.SendBuf(buf,sizeof(buf));
count := count + sizeof(buf);
end
else //不满则发剩余的
begin
stream.Read(buf,left);
Socket.SendBuf(buf,left);
end;
end;
end;


Server端(收方)


private
Tof : file;
size,count :integer;
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.CutFirst(denstr: string;scrstr: string);
var
len :integer;
begin
len := length(scrstr);
denstr := copy(scrstr,2,(len-1));
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
ServerSocket1.Active := True;
StatusBar1.SimpleText := 'Listening...';
end;

procedure TForm1.ServerSocket1Accept(Sender: TObject;
Socket: TCustomWinSocket);
begin
StatusBar1.SimpleText := 'Connected from '+ Socket.RemoteAddress;
end;

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
buf : array [1..2048] of char;
rcvtxt : string;
left,len : integer;
begin
len := Socket.ReceiveLength;
if len<10 then //若长度小于10则认为是文件长度
begin
rcvtxt := Socket.ReceiveText;
size := strtoint(rcvtxt);
count := 0;
if SaveDialog1.Execute then
begin
AssignFile(ToF, SaveDialog1.FileName);
Rewrite(ToF, 1);
end;
Socket.SendText('go');
end
else
begin
left := size - count; //未写的字节数
if sizeof(buf)<left then //满一块则写一块
begin
Socket.ReceiveBuf(buf,sizeof(buf));
BlockWrite(Tof,buf,sizeof(buf));
count := count + sizeof(buf);
Socket.SendText('go');
end
else //否则写剩余字节数
begin
Socket.ReceiveBuf(buf,left);
BlockWrite(Tof,buf,left);
CloseFile(Tof);
end;
end;
end;


这个程序在长度的判断上通用性还不够强,但只需
稍加改动就可以实用了
 
看harry老兄贴的好辛苦啊,
sigh,看了这日子挣钱越来越难了
 
后退
顶部