有socket编程经验或懂得网卡硬件的朋友请进!!!

最近在vc环境控制台下用api写了一个文件传输工程,为了能更好的解决我的问题,有意者请留下您的e-mail,我把工程发到您那里去。1、功能基本上实现了,但是对于大文件的传... 最近在vc环境控制台下用api写了一个文件传输工程,为了能更好的解决我的问题,有意者请留下您的e-mail,我把工程发到您那里去。
1、功能基本上实现了,但是对于大文件的传输还是出现了接收数据包格式与我发送的数据包格式不同。
我的发送格式是定义缓存为2000的rbuf和tbuf,分别用于收发。数据包长度是定长的,即tcp头20字节+我的2000字节。这2000字节里我的格式是cmd(5byte)+size(4byte)+data(1991byte)。接收端固定接收2000字节,如果前5字节是我定义的命令头字节,那么这个包就是可以识别的。当发送大文件的时候接收端会在5000或10000个数据包开始出现连续无法识别数据包。
调试过程中我试着在发送每发送完一个数据包后进行延时Sleep(1);数据长度改成800,发送100M的文件经过漫长的等待后接收端接收全部正确数据。如果没有延时就不行了。
以前我使用vb写网络程序的时候也出现过这样的问题,说是发送太快数据叠加导致两次发送当作一次发送,加上DoEvent()提交控制权限即可解决,据说在提交控制权后可以让缓存有清空的时间。

2、tcp数据包格式有20个字节,接下来是options和data,那么用api函数int send (SOCKET s,const char FAR 【* tbuf】,int len,int flags);和int recv ( SOCKET s, char FAR【* rbuf】, int len,int flags);里的buf指的因该就是tcp里的data吧,头20个字节我们不能直接写,网上说TCP的data长度最好小于是64k也可以不定,UDP的必须小于64k。
3、《网络安全开发包详解》书中介绍了libnet,libpcap等网络开发包,使用他们是不是可以编写包括tcp的头20个字节。
http://baike.baidu.com/view/32754.htm?fr=ala0_1_1
【4】、对于网络编程进行不下去或许更我对硬件的不了解有关,在使用send【之后】和recv【之前】我们的数据在哪里,即我们的数据从应用程序的tbuf发往哪里,rbuf又从哪里读取数据,我想在某个其他的缓存上(是网卡还是什么别的地方),如果是网卡,那么在从网卡上读取信息的时候应用程序依靠什么(进程号?)知道现在网卡上的信息是发个自己的,同一台计算机上面的网络连接可不仅仅又我们的应用程序,大家都在发生和接收,怎么使他们不混乱这个我不知道的缓存有多大。

在线等。。。。。
展开
 我来答
板唱Z9
2010-08-08 · TA获得超过1426个赞
知道小有建树答主
回答量:578
采纳率:100%
帮助的人:0
展开全部
Winsock没用过,不太清楚。
winpcap(libpcap的Windows版)可以处理二层及以上。

关于缓冲区的问题,你看看是不是这个Nagle算法?

【TCP传输小数据包效率问题(译自MSDN)】
水平有限,错误难免——builder++

摘要:当使用TCP传输小型数据包时,程序的设计是相当重要的。如果在设计方案中不对TCP数据包的延迟应答,Nagle算法,Winsock缓冲作用引起重视,将会严重影响程序的性能。这篇文章讨论了这些问题,列举了两个案例,给出了一些传输小数据包的优化设计方案。

背景:当Microsoft TCP栈接收到一个数据包时,会启动一个200毫秒的计时器。当ACK确认数据包发出之后,计时器会复位,接收到下一个数据包时,会再次启动200毫秒的计时器。为了提升应用程序在内部网和Internet上的传输性能,Microsoft TCP栈使用了下面的策略来决定在接收到数据包后什么时候发送ACK确认数据包:
1、如果在200毫秒的计时器超时之前,接收到下一个数据包,则立即发送ACK确认数据包。
2、如果当前恰好有数据包需要发给ACK确认信息的接收端,则把ACK确认信息附带在数据包上立即发送。
3、当计时器超时,ACK确认信息立即发送。
为了避免小数据包拥塞网络,Microsoft TCP栈默认启用了Nagle算法,这个算法能够将应用程序多次调用Send发送的数据拼接起来,当收到前一个数据包的ACK确认信息时,一起发送出去。下面是Nagle算法的例外情况:
1、如果Microsoft TCP栈拼接起来的数据包超过了MTU值,这个数据会立即发送,而不等待前一个数据
包的ACK确认信息。在以太网中,TCP的MTU(Maximum Transmission Unit)值是1460字节。
2、如果设置了TCP_NODELAY选项,就会禁用Nagle算法,应用程序调用Send发送的数据包会立即被投递到网络,而没有延迟。
为了在应用层优化性能,Winsock把应用程序调用Send发送的数据从应用程序的缓冲区复制到Winsock内核缓冲区。Microsoft TCP栈利用类似Nagle算法的方法,决定什么时候才实际地把数据投递到网络。
内核缓冲区的默认大小是8K,使用SO_SNDBUF选项,可以改变Winsock内核缓冲区的大小。如果有必要的话,Winsock能缓冲大于SO_SNDBUF缓冲区大小的数据。在绝大多数情况下,应用程序完成Send调用仅仅表明数据被复制到了Winsock内核缓冲区,并不能说明数据就实际地被投递到了网络上。唯一一种例外的情况是:
通过设置SO_SNDBUT为0禁用了Winsock内核缓冲区。

Winsock使用下面的规则来向应用程序表明一个Send调用的完成:
1、如果socket仍然在SO_SNDBUF限额内,Winsock复制应用程序要发送的数据到内核缓冲区,完成Send调用。
2、如果Socket超过了SO_SNDBUF限额并且先前只有一个被缓冲的发送数据在内核缓冲区,Winsock复制要发送的数据到内核缓冲区,完成Send调用。
3、如果Socket超过了SO_SNDBUF限额并且内核缓冲区有不只一个被缓冲的发送数据,Winsock复制要发送的数据到内核缓冲区,然后投递数据到网络,直到Socket降到SO_SNDBUF限额内或者只剩余一个要发送的数据,才完成Send调用。

案例1
一个Winsock TCP客户端需要发送10000个记录到Winsock TCP服务端,保存到数据库。记录大小从20字节到100字节不等。对于简单的应用程序逻辑,可能的设计方案如下:
1、客户端以阻塞方式发送,服务端以阻塞方式接收。
2、客户端设置SO_SNDBUF为0,禁用Nagle算法,让每个数据包单独的发送。
3、服务端在一个循环中调用Recv接收数据包。给Recv传递200字节的缓冲区以便让每个记录在一次Recv调用中被获取到。

性能:
在测试中发现,客户端每秒只能发送5条数据到服务段,总共10000条记录,976K字节左右,用了半个多小时才全部传到服务器。

分析:
因为客户端没有设置TCP_NODELAY选项,Nagle算法强制TCP栈在发送数据包之前等待前一个数据包的ACK确认信息。然而,客户端设置SO_SNDBUF为0,禁用了内核缓冲区。因此,10000个Send调用只能一个数据包一个数据包的发送和确认,由于下列原因,每个ACK确认信息被延迟200毫秒:
1、当服务器获取到一个数据包,启动一个200毫秒的计时器。
2、服务端不需要向客户端发送任何数据,所以,ACK确认信息不能被发回的数据包顺路携带。
3、客户端在没有收到前一个数据包的确认信息前,不能发送数据包。
4、服务端的计时器超时后,ACK确认信息被发送到客户端。

如何提高性能:
在这个设计中存在两个问题。
第一,存在延时问题。客户端需要能够在200毫秒内发送两个数据包到服务端。因为客户端默认情况下使用Nagle算法,应该使用默认的内核缓冲区,不应该设置SO_SNDBUF为0。一旦TCP栈拼接起来的数据包超过MTU值,这个数据包会立即被发送,不用等待前一个ACK确认信息。
第二,这个设计方案对每一个如此小的的数据包都调用一次Send。发送这么小的数据包是不很有效率的。在这种情况下,应该把每个记录补充到100字节并且每次调用Send发送80个记录。为了让服务端知道一次总共发送了多少个记录,客户端可以在记录前面带一个头信息。

案例二:
一个Winsock TCP客户端程序打开两个连接和一个提供股票报价服务的Winsock TCP服务端通信。第一个连接作为命令通道用来传输股票编号到服务端。第二个连接作为数据通道用来接收股票报价。两个连接被建立后,客户端通过命令通道发送股票编号到服务端,然后在数据通道上等待返回的股票报价信息。客户端在接收到第一个股票报价信息后发送下一个股票编号请求到服务端。客户端和服务端都没有设置SO_SNDBUF和TCP_NODELAY选项。

性能:
测试中发现,客户端每秒只能获取到5条报价信息。

分析:

这个设计方案一次只允许获取一条股票信息。第一个股票编号信息通过命令通道发送到服务端,立即接收到服务端通过数据通道返回的股票报价信息。然后,客户端立即发送第二条请求信息,send调用立即返回,发送的数据被复制到内核缓冲区。然而,TCP栈不能立即投递这个数据包到网络,因为没有收到前一个数据包的ACK确认信息。200毫秒后,服务端的计时器超时,第一个请求数据包的ACK确认信息被发送回客户端,客户端的第二个请求包才被投递到网络。第二个请求的报价信息立即从数据通道返回到客户端,因为此时,客户端的计时器已经超时,第一个报价信息的ACK确认信息已经被发送到服务端。这个过程循环发生。

如何提高性能:
在这里,两个连接的设计是没有必要的。如果使用一个连接来请求和接收报价信息,股票请求的ACK确认信息会被返回的报价信息立即顺路携带回来。要进一步的提高性能,客户端应该一次调用Send发送多个股票请求,服务端一次返回多个报价信息。如果由于某些特殊原因必须要使用两个单向的连接,客户端和服务端都应该设置TCP_NODELAY选项,让小数据包立即发送而不用等待前一个数据包的ACK确认信息。

提高性能的建议:
上面两个案例说明了一些最坏的情况。当设计一个方案解决大量的小数据包发送和接收时,应该遵循以下的建议:
1、如果数据片段不需要紧急传输的话,应用程序应该将他们拼接成更大的数据块,再调用Send。因为发送缓冲区很可能被复制到内核缓冲区,所以缓冲区不应该太大,通常比8K小一点点是很有效率的。只要Winsock内核缓冲区得到一个大于MTU值的数据块,就会发送若干个数据包,剩下最后一个数据包。发送方除了最后一个数据包,都不会被200毫秒的计时器触发。
2、如果可能的话,避免单向的Socket数据流接连。
3、不要设置SO_SNDBUF为0,除非想确保数据包在调用Send完成之后立即被投递到网络。事实上,8K的缓冲区适合大多数情况,不需要重新改变,除非新设置的缓冲区经过测试的确比默认大小更高效。
4、如果数据传输不用保证可靠性,使用UDP。
Storm代理
2023-06-05 广告
StormProxies是全球大数据IP资源服务商,其住宅代理网络由真实的家庭住宅IP组成,可为企业或个人提供满足各种场景的代理产品。点击免费测试(注册即送1G流量)StormProxies有哪些优势?1、IP+端口提取形式,不限带宽,IP... 点击进入详情页
本回答由Storm代理提供
lzwml1989a
2010-08-09
知道答主
回答量:3
采纳率:0%
帮助的人:0
展开全部
用小号来补充问题
发送其中一种数据包
memcpy(tbuf,CmdFileContent,LEN_CMD); //加上数据包头,【文件内容头】
memcpy(tbuf+LEN_CMD,&lenInf,LEN_SIZE);//数据包长度,注意inter存储方式是倒序的
fread (tbuf+LEN_CMD+LEN_SIZE,sizeof(unsigned char),LEN_FULLINF,fd);//接着数据包内容,即使文件内容不足LEN_FULLINF也不会出错
lenFile -= LEN_FULLINF;
ret = SendSocket(&client,tbuf,LEN_PACK);
接收
ret = ReceiveSocket(skt,rbuf,LEN_PACK);t
lenInf = rbuf[LEN_CMD+3] << 24 | rbuf[LEN_CMD+2] << 16 | rbuf[LEN_CMD+1] << 8 | rbuf[LEN_CMD];//获取信息量长度
if (CompareCmd(rbuf,CmdFileContent,LEN_CMD)){.}//*********文件内容*********
else if(CompareCmd(rbuf,CmdFileHead,LEN_CMD)) {...}//*********文件信息头(文件名,文件大小等)*********
else if(CompareCmd(rbuf,CmdFileEnd,LEN_CMD)) {...} //*********文件结束*********
else {这个数据包无法头识别}
数据包头判断
bool CompareCmd(unsigned char* buf1, unsigned char* buf2, int len)
{
for(int i=0; i<len; i++)
if(*(buf1+i) != *(buf2+i))
return false;
return true;
}
我昨天试着让发送端发送2000个数据,其中后1000个数据是空的,接收方每次接收1000个数据,不能识别时有一定延时(必须有延时)。果然接收方每个一个数据包就不能识别,但是几百M的数据竟然接收全部成功,不明其中原由,【只要发送方的空数据是有效数据的整数倍就没问题】。
原来的程序是在发送文件过程当作,接收方只管发送不管接收,现在我试着让接收方在出现不能识别数据包头时让另一方重发,看否能解决。
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
dreagonwoo
2010-08-09
知道答主
回答量:4
采纳率:0%
帮助的人:0
展开全部
C语言里的Sleep函数可以实现DoEvent()的功能
Remarks
A thread can relinquish the remainder of its time slice by calling this function with a sleep time of zero milliseconds.
一个线程能够呼叫这个函数时把参数设置成为0实现放弃所拥有的剩余时间片。
本回答被提问者采纳
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
研究报告站
2010-08-08 · TA获得超过195个赞
知道小有建树答主
回答量:441
采纳率:0%
帮助的人:320万
展开全部
这个问题是因为你的发生函数或接收函数没写好,可以贴代码出来瞧瞧的。
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
gongtaikj
2010-08-08 · 超过13用户采纳过TA的回答
知道答主
回答量:70
采纳率:0%
帮助的人:44.6万
展开全部
顶我,我告诉你!gongtaikj@163.com
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
收起 更多回答(3)
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式