是高手的进来快进来看看!菜鸟求救!!!(50分)

  • 主题发起人 主题发起人 yinzt
  • 开始时间 开始时间
Y

yinzt

Unregistered / Unconfirmed
GUEST, unregistred user!
偶正在在利用delphi的clientsocket和serversocket控件进行编程,实现两台机器通讯.采用c/s模式,ServerSocket一次只能接收8K的数据.
当接收超过8K,或者临近8K的数据,就会出现丢包现象.有没有什么可行的解决办法?
 
俺也是菜鸟,只能帮你顶了[:D]
 
你看看允许发送的最大包是多大吧,太大了建议你分包发送哦!
 
打数据弄成流的形式 再按大小截成段来传送 用个循环就能搞定了
 
具体怎么弄?能说得再详细一点吗?
 
要发的包长度是不固定的.
 
这个样子,用Tfilestream打开文件,再定义buffer,array[0..1023] of byte ,
分次发送,最好定义一个结构,如下
type
Data = record
TotalLen : integer; //总长度
CurPos : integer; //已传长度
CurData : array[0..1023] ;//数据
end;
小弟菜人一个,第一次回贴哈
 
给个刚开始学clientsocket/serversocket的程序参考下,希望有用。
unit Unit1;

interface

uses
Windows, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, ScktComp, Jpeg, ExtDlgs;

type
TForm1 = class(TForm)
ClientSocket1: TClientSocket;
ServerSocket1: TServerSocket;
Label1: TLabel;
Panel1: TPanel;
Button1: TButton;
Panel2: TPanel;
Image1: TImage;
Image2: TImage;
procedure FormShow(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
procedure ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
procedure Image1DblClick(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
PicStrm : TmemoryStream;
ReceiveStrm : TmemoryStream;
LeftSize : Integer;
procedure SendPic;
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

Const
SendSize = 8192;
RecSize = 8192;

implementation

{$R *.dfm}

procedure TForm1.SendPic;
var
SendChar : Array[0..SendSize-1] of Char;
begin
if LeftSize > SendSize then
begin
PicStrm.Read(SendChar,SendSize);
ClientSocket1.Socket.SendBuf(SendChar,SendSize);
LeftSize := LeftSize - SendSize;
end
else
begin
PicStrm.Read(SendChar,LeftSize);
ClientSocket1.Socket.SendBuf(SendChar,LeftSize);
end;
end;

procedure TForm1.FormShow(Sender: TObject);
begin
PicStrm := TMemoryStream.Create;
ReceiveStrm := TMemoryStream.Create;
ServerSocket1.Open;
ClientSocket1.Open;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
if Image1.Picture.Graphic = Nil then exit;
Button1.Cursor := crHourGlass;
Image1.Picture.Graphic.SaveToStream(PicStrm);
LeftSize := PicStrm.Size;
PicStrm.Position := 0;
SendPic;
end;

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
RecLen : Integer;
RecChar : Array[0..RecSize-1] of Char;
Jpg : TJpegImage;
Bmp : TBitmap;
begin
RecLen := Socket.ReceiveLength;
Socket.ReceiveBuf(RecChar,RecLen);
ReceiveStrm.Write(RecChar,RecLen);
if RecLen < RecSize then
begin
Try
Image2.Picture.Graphic := nil;
Jpg := TJpegImage.Create;
ReceiveStrm.Position := 0;
Jpg.LoadFromStream(ReceiveStrm);
Image2.Picture.Graphic := Jpg;
except
end;

if Image2.Picture.Graphic = nil then
Try
Bmp := TBitmap.Create;
ReceiveStrm.Position := 0;
Bmp.LoadFromStream(ReceiveStrm);
Image2.Picture.Graphic := Bmp;
Except
end;

ReceiveStrm.Clear;
Socket.SendText('Over');
end
else
Socket.SendText('Wait');
end;

procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
begin
if Socket.ReceiveText = 'Wait' then
SendPic
else
begin
PicStrm.Clear;
Button1.Cursor := crDefault;
end;
end;

procedure TForm1.Image1DblClick(Sender: TObject);
begin
With TOpenPictureDialog.Create(nil) do
try
if Execute then
Image1.Picture.LoadFromFile(FileName);
Finally
Free;
end;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
action := caFree;
end;

end.
 
系统默认的缓冲区长度只有8192个字节,一个包小于8192个字节是,可以一次发完或一次收完,但还要看你的处理速度,如果连续发送两个5000个字节的包,则第二次发不完,你要再发一次。接收也是一样的道理,当有几个字节到达时,系统便可以读取,但还有很多数据没到,你想一次读完时不行的。因此应该这么做:
发送的时候,你应该根据Send函数返回值,看看发了几个字节,发完没有,如果没发完,继续将剩下的发完,接收的时候也是一样的道理。
缓冲长度是可以设置的,以下代码可以设置缓冲长度为1M。
long v = 1024*1024;
setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&v, sizeof(bs));
setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&v, sizeof(bs));
 
超过默认的缓冲了
解决办法:
将需要发送的部分分开发送
 
结了,好像目前都没有较好的解决方案[:(][V]
 
后退
顶部