怎样控制Socket连续发时不要一次收?(200分)

  • 主题发起人 主题发起人 HunterHua
  • 开始时间 开始时间
H

HunterHua

Unregistered / Unconfirmed
GUEST, unregistred user!
我在非阻塞方式下,ClientSocket连续向ServerSocket发数据(调用SendBuf),每个包
数据都不大,ServerSocket端在OnClientRead事件中用
ReceiveBuf(Buffer,Socket.ReceiveLength)接收,我发现我分几次发的包服务端帮我
用一次收包收完(自动将几次发包合并成一次收包,只激发了一次OnClientRead),
我想问一下,我能否控制客户端每发一次,服务端就激发一次收包,
不要合并后一起收包?
 
禁用NAGLE算法
 
如果在局网上可以用命名管道,他的消息模式有边界保护,可以达到你的要求,
或者用UDP,稍做点确认机制,一般是没有问题的
 
无忌,如何用命名管道?
 
这是服务器
unit PipnamedThread;

interface

uses
Classes,Windows,Sysutils,stdctrls;

const
MSGBUF=1024;
FILBUF=4096;
PIPE='//./Pipe/';

type
TPipType=(dtSendFile,dtClose,dtSendMsg,dtOpen);
TPipnamedThread = class(TThread)
private
{ Private declarations }
FMemo:TMemo;
FPip:THandle;
Fhandle:THandle;
Fdelaytime:integer;
Fname:string;
szName:PChar;
Msg:string;
procedure ErrMsg(Msg:string);
procedure LogMsg;
protected
procedure Execute; override;
public
property name:string read Fname;
property delaytime:integer write Fdelaytime;
constructor CreatePip(handle:THandle;name:string;Memo:TMemo);
destructor Destroy;override;
end;

{ TPipServer = class(TThread)
private

protected

public

end; }

implementation

{ Important: Methods and properties of objects in VCL can only be used in a
method called using Synchronize, for example,

Synchronize(UpdateCaption);

and UpdateCaption could look like,

procedure TPipnamedThread.UpdateCaption;
begin
Form1.Caption := 'Updated in a thread';
end; }

{ TPipnamedThread }
procedure TPipnamedThread.LogMsg;
begin
FMemo.Lines.Add(Msg);
end;

procedure TPipnamedThread.ErrMsg(Msg:string);
begin
MessageBox(Fhandle,PChar(Msg),'错误',MB_ICONERROR);
end;

constructor TPipnamedThread.CreatePip(handle:THandle;name:string;Memo:TMemo);
begin
inherited Create(true);
Freeonterminate:=true;
szName:=PChar(PIPE+name);
Fname:=StrPas(szName);
Fhandle:=handle;
FMemo:=Memo;
Fdelaytime:=1000;
end;

procedure TPipnamedThread.Execute;
var
Buffer:PChar;
byteread:DWORD;
pasStr:string;
begin
FPip:=CreateNamedPipe(PChar(Fname),PIPE_ACCESS_DUPLEX,PIPE_TYPE_MESSAGE and
PIPE_READMODE_BYTE,1,0,0,1000,nil);

if FPip=INVALID_HANDLE_VALUE then
begin
ErrMsg(Format('创建命名管道错误,错误代码是:%d',
[GetLastError()]));
exit;
end;

Msg:='创建命名管道成功!';
Synchronize(LogMsg);
if ConnectNamedPipe(FPip,nil)=false then
begin
ErrMsg(Format('连接命名管道失败,错误代码是:%d',
[GetLastError()]));
exit;
end;

GetMem(Buffer,MSGBUF);
try
while (FPip<>INVALID_HANDLE_VALUE) and (not Terminated) do
begin
FillChar(Buffer^,MSGBUF,0);
if ReadFile(FPip,Buffer^,FILBUF,byteread,nil)<>false then
begin
pasStr:=copy(Buffer,1,MSGBUF);
Msg:='收到消息为:'+pasStr;
Synchronize(LogMsg);
end;
end;
if DisconnectNamedPipe(FPip)=false then
begin
ErrMsg(Format('断开命名管道失败,错误代码是:%d',
[GetLastError()]));
end;
finally
FreeMem(Buffer);
end;
end;

destructor TPipnamedThread.Destroy;
begin
CloseHandle(FPip);
Msg:='关闭命名管道成功!';
Synchronize(LogMsg);
inherited destroy;
end;

end.

procedure TForm1.Button2Click(Sender: TObject);
var
szName:PChar;
err:string;
begin
GetMem(szName,80);
wsprintf(szName,PChar(Format('//%s/Pipe/%s',[Edit2.text,edit1.text])));
if WaitNamedPipe(szName,NMPWAIT_WAIT_FOREVER)=false then
begin
err:=Format('等待命名管道失败,错误代码是:%d',[GetLastError()]);
MessageBox(handle,pchar(err),'错误',MB_ICONERROR);
exit;
end;

AHandle:=CreateFile(szName,
GENERIC_READ or GENERIC_WRITE,0,
nil,OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if AHandle=INVALID_HANDLE_VALUE then
begin
err:=Format('连接命名管道失败,错误代码是:%d',[GetLastError()]);
MessageBox(handle,pchar(err),'错误',MB_ICONERROR);
exit;
end;
FreeMem(szName);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
szWrited:PChar;
writed:DWORD;
err:string;
begin
if (AHandle=INVALID_HANDLE_VALUE) then
exit;
GetMem(szWrited,256);
FillChar(szWrited^,256,0);
StrCopy(szWrited,PChar(Memo1.text));
if WriteFile(AHandle,szWrited^,256,writed,nil)=false then
begin
err:=Format('发送数据出错,错误代码是:%d',[GetLastError()]);
MessageBox(Handle,PChar(err),'错误',MB_ICONERROR);
exit;
end;
FreeMem(szWrited);

end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
closehandle(AHandle);
end;

procedure TForm1.Memo1Enter(Sender: TObject);
begin
Memo1.BorderStyle:=bsSingle;
end;

procedure TForm1.Memo1Exit(Sender: TObject);
begin
Memo1.BorderStyle:=bsNone;
end;

end.
后面的是客护短
 
谢谢无忌, 能否详细点介绍禁用NAGLE算法?
如用命名管道,假如客户端是Unix机,那就用不了。
 
不是接收端合并为一个,而是发送端合并为一个
这个办法比较麻烦,一般来说,是要自己用某种机制重新拆开
比如,数据是字符串的话,可以用一个特殊字符隔开,比如#0,
如果是二进制数据,那么可能要在发送的数据块前面先加上长度
 
Pipi:不是接收端合并为一个,而是发送端合并为一个
为什么?什么情况下会合并?


 
发送端在短时间内接到多个小包,会合并为一个大包,一次发送
 
PiPi: 假如我在服务端收包事件中设断点,我不在短时间内发,都会合并收。
究竟能否发一个包收一个包?假如不能,能否解释一下其中道理。
 
进来的朋友请踢一脚
 
你虽然是收到了一个大包
但是你可以按照你们的规约格式把他分成若干个小包
 
还有一个办法,把所有的数据COPY到一个大的BUFFER里,再进行分割。
 
> 假如我在服务端收包事件中设断点,我不在短时间内发,都会合并收。
如果是debug的断点,那是没用的
 
查 setsockopt 的 TCP_NODELAY 不知道有没有用处,我从来没试过,因为我写的程序都是
自己还要分开的
 
我没有试过,我上面说的禁用NAGLE算法就是用这个参数
Pipe,你有QQ没?
我的是775033
 
no qq , no email
 
那有什么联系方式没?
 
有,我天天晚上都在大富翁
 
后退
顶部