winsock1.1发送接收的问题!!请各位大虾救小第一把!!(100分)

  • 主题发起人 the_best_of_bes
  • 开始时间
T

the_best_of_bes

Unregistered / Unconfirmed
GUEST, unregistred user!
我正在作一个发送接收文件的程序,用winsock1.1的函数,以下是问题,如果谁有例子就更好了。
问题:1:server端接收数组buf为8192,client端发送数组buf为8192。在client端每次发送数据大小为8192。如果某一文件为12192,send先发开始信息‘start’通知server接受方创建文件用于接收。第一次发8192,然后再发剩下的4000,接下来发送结束信息‘end’。问题是接收方在每次接收时数据的大小有时会小于8192,并且在接收最后的数据时我的信息‘end’和剩下的信息被一次接收了,这样我就收不到我的结束信息‘end’了(但发送时是分2次发的)。我试过把发送最后不足8192的数据用#0填够,单在接收写入文件时确多了好多空行(好像时空格),写入文件时用Tfilestream 流。
2:socket的缓冲区大小是不是就是我定义的接收,发送数组buf的大小?
3:在windows 下是用非阻塞的好还是用阻塞的好?我感觉非阻塞的好用但听人说对数据的丢失不好控制。
 
1.你用的是TCP协议吧?TCP协议就是这样的,它会自动帮你组包(可能是拆分,也有可能是合并)。你最后一次发送的数据包太小了,系统把'end'组合成一个包发送出去了(虽然你是分两次发送的)。解决的办法有很多种,要视具体情况而定,如果你固定每次发送的数据包大小是8192,那么接收端每次收完8192个字节就算完成一次接收,少收了就继续接收,多收了就算下个数据包的。最后一个数据包长度不够的字节就补0。
2.你可以自定义缓冲区大小,但它跟你收发数据包的buf的大小是两回事。
3.如果你的连接不是很多,用阻塞模式控制起来比较方便,但非阻塞的效率比较高。
 
to:ego
我是用的Tcp,能不能麻烦你讲的细一点,如果有例子就更好了。我是第一次作数据传输。
谢谢!!!!
 
是这样的,
TCP在发送数据的时候自作聪明的等待下一个发送的数据,如果相同发送的IP和端口,它就会把2次数据加起来一次性发送出去。
所以你在使用的时候,发送一次数据以后等待对方的返回信息,等到返回信息以后在发的二次数据,就可以了。
 
小弟实在是笨,能不能给个例子
 
这是发送端的代码。
var
wsData:TWSADATA;
sck:TSOCKET;
flag:Boolean;
host:phostent;
prot:Integer;
tto:SOCKADDR_IN;
Shutdown:String;
CliAddrIn:TSockAddrIn;
zgc:integer;
Test:Integer;
Item:TListItem;
begin
Test:=0;
prot:=926;
if WSAStartUp($101, wsData) <> 0 then
begin
//Application.MessageBox('初始化WINSOCK错误');
WSACleanup();
end;
//while Test<1000do
//begin
Item:=RzListView1.Items.Insert(0);
sck:=socket(AF_INET,SOCK_STREAM,0);
if sck=SOCKET_ERROR then
begin
Item.Caption:=FormatDateTime('hh:nn:ss',Now());
Item.SubItems.Add('不正常');
//Application.MessageBox('SOCKET错误');
closesocket(sck);
WSACleanup();
end
else
begin
//host:=gethostbyname('vefc');
CliAddrIn.sin_addr.s_addr:=inet_addr('200.200.200.19');
CliAddrIn.sin_family:=AF_INET;
CliAddrIn.sin_port:=htons(926);
if (connect(sck,CliAddrIn,sizeof(CliAddrIn))<>SOCKET_ERROR) then
begin
Shutdown:='85623910';
//Applciation.
send(sck,Shutdown[1],length(Shutdown),0);
Item.Caption:=FormatDateTime('hh:nn:ss',Now());
Item.SubItems.Add('正常');
//Application.MessageBox('asdf','asdf',MB_OK);
//shutdown(sck,0);
end
else
begin
Item.Caption:=FormatDateTime('hh:nn:ss',Now());
Item.SubItems.Add('不正常');
end;
end;
if sck<>-1 then
begin
closesocket(sck);
end;
Inc(Test);
sleep(100);
//Label1.Caption:=IntToStr(Test);
//end;
//Application.MessageBox('10000完成','asdf',MB_OK);
end;
 
接受端接受后,利用SEND发送过来就可以了。这边利用Rev接受就可以了。接受的套接字和发送的相同。
 
你的回答好象和我的问题不太一样。接收端在接收发送端的数据时可能2次才收完,而且我发的是一个大的文件。还有我把不够8192剩下的数据填为0时在接收端写入文件的是空格(应该是空阿!),请指教!!!
 
可以不用'start'和'end'做标志。
发送方在要传文件时发起连接,发送结束后断开连接。
接收方收到数据只管保存,得知对方关闭连接时文件就已经传完了。
 
但我要在‘start’处写入其它信息,始接收端作出相应的处理
 
把所有附加信息放在开头,而用关闭连接来结束。
 
那为大虾能不能救救我不然就没时间了!!!
 
要自己定一個數據包協義,如:
type
TDataHeader = Record
ID : WORD;
nLen : Integer;
...
end;
如果數據包小於nLen就要一直Recv
 
结贴了
谢谢各位的帮助,我找到答案了:
1:发定长的数据,接收方要每次接收时要接够定长的数据再做处理。
2:发变长数据,要在数据前面加入信息的长度,接收方每次截取数据的长度进行接收。
 
多人接受答案了。
 
顶部