Socket通信的问题 200分(200分)

  • 主题发起人 主题发起人 cyhan
  • 开始时间 开始时间
C

cyhan

Unregistered / Unconfirmed
GUEST, unregistred user!
我编了个网吧管理程序,是通过一台主机(NT)来控制几台机器(Win98),
主机端用ServerSocket,客户端用ClientSocket,用的是非阻塞式方式通
信,在调试时一直没什么事,但在线路拥挤的网吧上运行,却常常出现一两
台机器无法控制的现象,一直查不出什么原因,经这几天研究一把,发现是
TCP的通信机制引起的,主机或者客户端发送的命令不会马上送出,而是粘
连几个命令发出,这样造成传送出去的命令无法设别,请问哪位大侠指点一
下,如何实现一旦把命令送出后就真正的送出,即如何强迫Tcp把缓冲区清
空送出数据?
 
使用setsockopt函数,有TCP_NODELAY选择项
 
谢谢,但我调试这个函数,却总是返回错误信息,程序如下:

procedure TForm1.ServerSocket1Accept(Sender: TObject;
Socket: TCustomWinSocket);
Var
p1,p2,x,y:Integer;
begin
p1:=1;
p2:=Sizeof(p1);
x:=Setsockopt(TSocket(Socket),IPPROTO_TCP,TCP_NODELAY,PChar(@p1),p2);
y:=WSAGetLastError;
end;
x返回 -1,y返回 WSAENOTSOCK,请问如何正确使用这函数?
 
关注.
用带外数据(BOP)。
 
TSocket(Socket)不对吧,
应该是Socket.SocketHandle。
 
谢谢温柔一刀,已可以正确调用这个函数了,但是问题还是一样,还会产生信包粘
连的情况,而且比不用该函数更为严重。
 
"经这几天研究一把,发现是TCP的通信机制引起的"
怎么研究的?为什么得出这样的结论?

我觉得首先应该检查程序,"在调试时一直没什么事"
可不一定就真的没事。
 
在局域网的条件下,应该没有那么严重吧?
从CSMA/CD和TCP的工作方式看来,不应该出现你说的情况

尝试将缓冲区开得只有一个命令包大小试试?
 
这么麻烦? 每发出一个命令后等待client回应命令执行结果再发下一个命令不就可以了?
 
自己做一个命令结束标志
 
谢谢各位的帮助,我已解决好这问题。
 
请问怎么解决的?

我一般只用Sockets控件传Strings,然后在接受方解码然后映射成相应的指令,所以你所说的
命令粘连无法识别问题在我的方式下可以用编码解决,例如使用自定界码.
 
问:
我编了个网吧管理程序,是通过一台主机(NT)来控制几台机器(Win98),
主机端用ServerSocket,客户端用ClientSocket,用的是非阻塞式方式通
信,在调试时一直没什么事,但在线路拥挤的网吧上运行,却常常出现一两
台机器无法控制的现象,一直查不出什么原因,经这几天研究一把,发现是
TCP的通信机制引起的,主机或者客户端发送的命令不会马上送出,而是粘
连几个命令发出,这样造成传送出去的命令无法设别,请问哪位大侠指点一
下,如何实现一旦把命令送出后就真正的送出,即如何强迫Tcp把缓冲区清
空送出数据?

你好,cyhan:
这阶段我正好用tclientsocket和tserversocket的ctnonblocking方式实现文件从
client->server的传输,但是也发现这个问题,因为我设计成client端每发一个包,
server端都要给一个响应是否成功,跟你的问题很类似,请问一下你的粘包问题怎么
解决,能不能也帮我解决一下,多谢!

const _bbs='send_file_test11'
每个包结构为16位包标识(固定为_bbs)+4位(如下)+包数据(长度不定)

client端发的包(其中vctosave,vdsaveinfo,vcfirstbuf,vclastbuf为必发的包)
vctosave:请求server端上传文件(无包数据)
vcsaveinfo:发送文件信息-》vcsaveinfo+包数据(文件名称|文件时间|文件大小)
vcfirstbuf:
头一个包-》包数据长度:如果文件大小<datalen,为文件大小,
如果文件大小>=datalen,为datalen长的文件流(datalen大小可配置)
vccommonbuf:中间的包-》包数据为datalen长的文件流
vclastbuf:最后的包-》包数据长度为剩余文件流大小

server端发的包
vsready:已准备好
vssaveinfook:存文件信息成功
vsfirstbufok:存第一个包成功
vscommonbufok:存中间包成功
vssaveok:上传文件成功

问题在于:
1。client端发送一个包后,怎么才能判断server端是否响应超时
2。client端发送一个包后,按造delphi的onread的原理,可能会激发
server端的多个onread事件,我怎么写server端的读数据的过程?

我的程序大概如下:

unit client;
tform1.button1onclick(...)
begin
client1.open;
end;
tform1.client1connect(...)
begin
socket.sendbuf(_bbs+vcsave,20);
end;
tform1.client1tread(...)
var
getbuf,sendbuf:array [1..datalen+20] of char;
len,sendsize:integer;
begin
len:=socket.receivebuf(getbuf,datalen+20);
sendsize:=0;
if len>=20 then
begin
处理包(存文件流,处理出响应包sendbuf,sendsize);
end;
if sendsize>0 then socket.sendbuf(sendbuf,sendsize);
end;

unit server;
tform1.server1read(...)
var
getbuf,sendbuf:array [1..datalen+20] of char;
len,sendsize:integer;
begin
len:=socket.receivebuf(getbuf,datalen+20);
sendsize:=0;
if (len>=20)and(copy(getbuf,1,20)=_bbs) then
//问题就出在这里,如果client端发了一个包,server端激发了三个onread
事件,这是不是判断len>=20不是行不通了,因为其实包还没收完整,要等待
三个onread事件后才能处理,但是却怎么知道还没后续onread事件,我知道
是可以通过加包头和包尾解决,但是应该如何编码,如果包内容里也包括该
标识又该如何解决,还有如果网络数据如果很慢(如只有5byte),这时本身
的_bbs可能就不能在一个onread事件中读完,又该如何判断?
begin
处理包(处理出sendbuf,sendsize);
end;
if sendsize>0 then socket.sendbuf(sendbuf,sendsize);
end;
 
后退
顶部