急!急!急!求助一个有关Winsows Socket的问题(200分)

  • 主题发起人 主题发起人 大米
  • 开始时间 开始时间

大米

Unregistered / Unconfirmed
GUEST, unregistred user!
我在Delphi3.0编的程序里用WinSock实现数据库中数据的发送和接收
程序在95之间运行正常,可如果一台95,一台NT之间收发的时候发现
用NT发送,95接收没问题,反过来却总是报错
跟踪调试后发现在接收相同的数据时;
95下Recv(socket,buffer,size,0)返回值正常,等于size
NT下Recv(socket,buffer,size,0)却总是小于size
这是什麽原因?
请问各位大虾有什麽办法让NT下也能正常接收?
 
用Delphi 4试试
而且最好在NT下重新编译一次
 
我做过,95和Nt下的接收应该是一样的。是不是你的程序没有加入
同步控制,或是一次发送数据超出4096字节?能否mail你的程序
给我,只要收发部分。chen_ke@263.net
 
为什么不用Socket.ReceiveBuf了?
 
// NT5beta2下面的全拼输入法和IE5.0beta2 简直就是害人虫!!
// 我辛辛苦苦输入了半个小时, 全被他们俩给消遣了!!!
// 强烈抗议!! 希望大家引以为戒,以后想发表长篇大论,
// 切记先用编辑器输入,然后粘贴, :(!!!!!!!!!!
 
这个并没有任何错误发生,只是因为您还没有正确理解TCP/IP网络传输层传送数据的原理

TCP/IP的传输层提供的可靠的传输协议TCP,是面向字节流的,并不时面向消息报文的,
发送接收的过程中会有协商, 按照一定的缓冲区分块发送。所以,您并不能指望只要您
提供了buffer, 会对方整个接收到。

例如:
send(socket, buffer, 8192, 0);
系统可能分成若干个1,2K的数据包依次发送,
这样一来,接收的程序
recv(socket, buffer, 8192, 0);
就不能够一次把8192个字节全部接收到,因为这里接收方
并不知道发送方的8192的边界,只知道字节流。

您需要多次调用recv来接收需要的长度,其实,发送方
也是一样,并不能保证一次就把您所要求的数据全部发送完
毕,因为发送方的缓冲区也是有限的,也需要您根据send
的返回值,多次调用来保证全部发送完成。

而这里的buffer 的 size 只属于更高层的约定(既是所谓的应用层协议啦!)
如果发送方面只perfect_send(socket, buffer, 123, 0); 但是接受方期待的却是
能够perfect_recv(socket, buffer, 4096, 0); 那么就会发生“死锁"!

提供解决办法如下:(C(++) version)
if you want pascal version, please convert yourself, or mail me, let me
convert for you, :)
int SafeSend(int sockfd, const void* lpBuf, unsigned int nBufLen, int nFlags)
{
int iSendOffSet=0;
int iSendLen;
while (iSendOffSet<nBufLen)
{
if ( (iSendLen=send(sockfd, (const char*)lpBuf+iSendOffSet, nBufLen-iSendOffSet, nFlags))>0)
iSendOffSet+=iSendLen;
else
return iSendLen; // It's an error code
}

assert(iSendOffSet == nBufLen);
return iSendOffSet; // Must be nBufLen now.
}

int ReceiveBuf(int sockfd, void* Buf, unsigned int nBufLen, int nFlags)
{
int iReceiveOffSet=0;
int iReceiveLen;
while (iReceiveOffSet<nBufLen)
{
if ( (iReceiveLen=recv(sockfd, (char *)Buf+iReceiveOffSet, nBufLen-iReceiveOffSet, nFlags))>0)
iReceiveOffSet+=iReceiveLen;
else
return iReceiveLen; // It's an error code
}

assert(iReceiveLen == nBufLen);
return iReceiveOffSet; // Must be nBufLen now.
}

 
我发送数据时每次都超过4096个字节
请问这会带来什麽问题吗?
 
我是第一次来这里,因为这几天抓破头皮也没想出来办法
所以就到处贴文章求助,没想到这里有这麽多热心的朋友
好让我感动!!!
Thanks a lot!
^_^
 
window的Socket默认缓冲区是4096,如果一次发送超过4096字节,可能导致
数据丢失或异常出现。通常的解决方法是把数据分块发送,而且每块不超过
4096字节,并加以同步控制。如:A 发送方;B 接收方
开始:A发一个字节通知B开始收发。(可省略)
发送(循环):A发送4000字节到B-----------B确认后通知A继续发送(可发送一个字节表示)-|
|--------------------------------------------------------------------|
结束:A发一个字节通知B结束,双方断开Socket连接。
 
对不起,看来我没有说详细
我是用Paradox数据库,Delphi3.0开发C/S程序。程序既可以用在服务器端,也可以用在客户端。程序启动时创建一个ListenSocket监听网上的信息。客户端发送数据
时先创建一个子线程,在这个子线程里创建一个ClientSocket用来和服务器端相连
以传送数据,服务器收到请求后在后台创建一个子线程,在这个子线程里创建一个
ServerSocket负责和ClientSocket相连。至于线程同步,阻塞模式,数据库加锁
都考虑到了。
数据库每条记录包括一些文字信息和12个压缩图,现在一般最多只前5个压缩图有
数据,每个大概4-5k,文字信息最多1108个字节
发送的时候先发文字信息,再一个个地发压缩图,当然还带有这些信息的字节数。
接收的时候也是对应着先接收文字信息,在一个个地接收压缩图。
接收的时候在Recv之前有一个函数判断ClientSocket中可接收的字节数。
比如说接收文字信息部分时,先判断ClientSocket中可接收的字节数是否>=1108
如果是就开始Recv,否则就等待直到超出规定的时间


程序在NT下运行时,我发现如果记录里只有一个压缩图就接收得很好
当压缩图大于一个时,接收开始那段文字信息时还正常,可一到接收
第一个压缩图时,函数判断出ClientSocket中可接收的字节数大于
Size1(Size1是第一个压缩图的字节数),但Recv(ClinetSocket,
Buffer1,Size1,0)却总是小于Size1

**在95下不管有几个压缩图都能正常接收**

 
判断ClientSocket中可接收字节数的代码:

function SocketDataLength(hSocket:TSocket):Integer;
begin
ioctlsocket(hSocket, FIONREAD, Longint(Result))
end;

function CheckSocketData(hSocket:TSocket;Count:Integer):Integer;
Var Error:Integer;
Begin
Result:=0;
Error:=0;
While SocketDataLength(hSocket)<Count Do
Begin
Sleep(100);
Inc(Error);
If Error>100 Then
Begin
Result:=-1;
Break;
End;
End;
If SocketDataLength(hSocket)>Count Then
Result:=1;
end;

每次接收时的代码:
If CheckSocketData(hClientSocket,size)>=0 Then
begin
if (Recv(hThreadSocket,buffer,size,0)<>size) then
begin
报错处理
end;
end;
 
Sorry
上一篇中的(Recv(hThreadSocket,buffer,size,0)<>size)
应该是(Recv(hClientSocket,buffer,size,0)<>size)
 
function CheckSocketData(hSocket:TSocket;Count:Integer):Integer;
Var Error:Integer;
Begin
Result:=0;
Error:=0;
While SocketDataLength(hSocket)<Count Do
Begin
Sleep(100);
Inc(Error);
If Error>100 Then
Begin
Result:=-1;
Break;
End;
End;
If SocketDataLength(hSocket)>Count Then
Result:=1;
end;
 
奇怪,怎麽每次Paste上的东东总是有些出入
函数CheckSocketData中的循环是这样的:
while SocketDataLength(hSocket)<Count do
begin
Sleep(100);
Inc(Error);
if Error>100 then
begin
Result:=-1;
Break;
end;
end;
 
我要晕了,怎麽显示出来的循环总不是我写的,老是缺一些
 
不要写大于和小于号 .
 
那样有可能会被认成html控制符的.
如果一定要用它, 请写"<" 在HTML中会变成<小于号
大于号用">"
 
函数CheckSocketData中的循环是这样的:
while SocketDataLength(hSocket)小于count do
begin
Sleep(100);
Inc(Error);
if Error大于100 then
begin
Result:=-1;
Break;
end;
end;
 
压缩图每个不超过4k吗?是放送成功一个后,接收方要求你再发第二个,
还是没有确认就发送方不停的发,接收方不停的收呢?
接收方可试试以下代码:
var size1:integer;
if CheckSocketData(hClientSocket,size)>=0 Then
begin
size1:=0;
while size1<size then
begin
size1:=size1+Recv(hClientSocket,buffer+size1,size-size1,0);
Sleep(100);
Inc(Error);
if Error大于100 then
begin
报错处理
Break;
end;
end;
end;
 
您的程序不应该依赖任何假设的系统缓冲区的长度, 还是使用
自己的辅助程序,确保您所要求的数据能够全部发送成功和接收
成功.
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
后退
顶部