• 9291阅读
  • 11回复

请教个网络传输文件的问题 [复制链接]

上一主题 下一主题
 
只看楼主 倒序阅读 楼主  发表于: 2009-03-06
目前我传输文件用的方法是,服务器端循环往TCPSOCKET里WRITE 包,一个WHILE循环.
这是服务器端,当服务器端收到下载命令后,打开文件,然后进行下面的循环读取文件并发送.
while (maxsize > size)
    {
        memset (buff,0,101);
        buff[0] = '$';          //文件传输中的包头
    file.read(&buff[1],100);       //从文件里读取数据到buff
        size += socket->write(buff,readsize+1) - 1;     //从buff写入socket
    }

客户端的问题就来了.我应该用什么信号让客户端进行接收呢?
我试过用readReady 信号,然后执行一个槽函数,这个槽函数就是从socket里读取字节,然后写入文件,文件对象在另一个函数里已经打开了.

问题就是,只要一运行下载,服务器端显示是发送完毕,很成功,可客户端就死机了.

似乎用readReady做信号,槽函数执行次数过多造成的吧?

后来我试过用个按钮来调用客户端的这个槽函数,来手动读取数据,就没任何问题.

请问各位谁知道这个readReady信号在这里是不是只能用来作为数据开头的信号而不能重复循环.
只看该作者 1楼 发表于: 2009-03-06
另外就是,服务器端那样循环发送数据给客户端会不会有很打缺陷?
如果我客户端没有接收,而传输的文件很大,会造成什么后果?
socket 能承受多大数据的等待队列?
只看该作者 2楼 发表于: 2009-03-06
write不会即时写入数据,发送数据是在loopevent里完成的,所以你这样while和写一句
socket->write(file.readAll())无异
结果必然是服务器端占用极大量的内存

你应该用bytesWritten和bytesToWrite来判断写入时机,等一批数据发送出去之后再写入下一批,并且不要把等待操作放在一个while里
只看该作者 3楼 发表于: 2009-03-06
另外, QTcpSocket::read(buff,size)  这个函数
返回值和size 我看说明是可能不一样的,因为返回值是实际读取的个数,而SIZE是你要求的个数.

如果网络上服务器端还没传过来那么多你就再读,就会读不到那么多.那么解决的办法我可以不可以用个循环来直到返回值和SIZE相等?

在文件传输途中看上去好像没什么问题,网络再慢,客户端这边也在循环等待SIZE那么大的包传输完.但是这个问题就在于,如果最后一个包,他没有SIZE那么大,那就会造成死循环拉.

但是我必须等SIZE那么大的包才行,因为每个SIZE那么大的包都有包头,我会根据包头是什么来做相应的处理,比如文件结束的包头.
如果不这样,中途的包头就会乱套了.
只看该作者 4楼 发表于: 2009-03-06
切记不要用循环来等待,用循环等待唯一的结果就是死程序

用readyRead来判断读取时机

另外你没有办法从分次读入来分隔包的

你可以把读入的东西先存入一个缓存中,够数量了再处理
只看该作者 5楼 发表于: 2009-03-06
请问我用这个方法好不好?安全性我觉得是很高的,但是速度我不知道会不会降低很多,特别是传大文件.

就是,服务器端发101个字节的数据包,第一个字节是包头.客户端接收这101个数据包,接收到后,写入文件,然后发送确认数据包,1个字节给服务器端.
服务器端接收到这个确认的数据包后,再发下101个字节的数据包.

这样的好处就是,两边都可以用 readReady 信号了,因为这个信号,一个包只会有一次了.
但是坏处就是,每次都要一来一回会不会大大影响速度.

不过我还是担心在网络很卡的时候,会不会导致这101个字节都会分成2次读完,导致客户端产生2次 readReady 信号?
只看该作者 6楼 发表于: 2009-03-06
这样做简直是浪费嘛……

一个tcp包的最大大小是14xx,你非要100个字节一送,一次发送包头占10%,不知道浪费到哪里去了

101个字节分2次读完倒是不可能,因为这101个字节必然在一个tcp包里,不过这点我也没有做实验确认过,因为没必要用readready去分割数据

但问题是你就应该考虑大数据量发送,然后产生多次readready的情况产生啊

读入进来的包加到缓存里,然后每次判断缓存是不是到101字节了,到了的话处理下,没处理完的部分继续存在缓存,这不就好了

另外根据tcp的定义我记得是不会产生丢包、乱序的情况的,这又不是udp,所以服务器端确认怎么也觉得没必要呢……
只看该作者 7楼 发表于: 2009-03-06
请问服务器端如果不用循环来写的话,那用什么信号来分开写数据啊?
客户端倒还可以用readReady ,服务器端发送数据应该用什么办法避开循环?
只看该作者 8楼 发表于: 2009-03-06
不是说了byteswritten了么……判断下还有没有数据没发送,没有了就写入新数据

而且……干嘛要分开数据啊……
只看该作者 9楼 发表于: 2009-03-06
谢谢谢谢,因为没看到你的回复就在继续回复了.

我对网络实在是不太了解,不知道TCP是分包发送的,所以101个字节肯定在一个包里发送过去. 这样的话,我就可以1K的发送了.

我说的分开写数据是因为我不懂网络传输原理.我怕如果我直接用循环往SOCKET里写,而客户端那边根本没收那么快,服务器的SOCKET会不会就塞满了?

比如我传1G的文件,我直接循环发送而不通过信号来分开发送的话,会不会SOCKET写满.我是担心这个,所以才想到要等客户端接收一个包,然后发送一个确认过来,服务器端再发送.
只看该作者 10楼 发表于: 2009-03-06
引用第9楼算了不说了于2009-03-06 10:40发表的  :
谢谢谢谢,因为没看到你的回复就在继续回复了.
我对网络实在是不太了解,不知道TCP是分包发送的,所以101个字节肯定在一个包里发送过去. 这样的话,我就可以1K的发送了.
我说的分开写数据是因为我不懂网络传输原理.我怕如果我直接用循环往SOCKET里写,而客户端那边根本没收那么快,服务器的SOCKET会不会就塞满了?
.......

所以你应该服务器端自己确认数据发送完成了你再往里送数据啊

稍微了解下tcp原理吧……不然这做出来很诡异……
只看该作者 11楼 发表于: 2009-03-06
谢谢你的耐心解答,很感谢你.
服务器端用bytesWritten来分批发送数据.
服务器端用readReady分批接收数据,一个制定的包接收完整后,再分析包头,写入文件.

非常感谢你
快速回复
限100 字节
 
上一个 下一个