Chinaunix

标题: 关于fastDFS中python客户端的接收数据不完整bug [打印本页]

作者: gg9654    时间: 2014-09-04 10:55
标题: 关于fastDFS中python客户端的接收数据不完整bug
本帖最后由 gg9654 于 2015-01-28 17:17 编辑

最近刚好用到FastDFS的python客户端,发现会有接收数据缺失的现象,并修复了一个socket接收代码的一个bug,如下

老代码(fdfs_client/connection.py):
  1. def tcp_recv_response(conn, bytes_size, buffer_size = 4096):
  2.     '''Receive response from server.
  3.         It is not include tracker header.
  4.         arguments:
  5.         @conn: connection
  6.         @bytes_size: int, will be received byte_stream size
  7.         @buffer_size: int, receive buffer size
  8.         @Return: tuple,(response, received_size)
  9.     '''
  10.     response = ''
  11.     total_size = 0
  12.     try:
  13.         while 1:
  14.             if bytes_size <= buffer_size:
  15.                 resp = conn._sock.recv(buffer_size)
  16.                 response +=resp
  17.                 total_size += len(resp)
  18.                 break
  19.             resp = conn._sock.recv(buffer_size)
  20.             response += resp
  21.             total_size += len(resp)
  22.             bytes_size = bytes_size - buffer_size  #注意这个地方的有问题
  23.     except (socket.error, socket.timeout), e:
  24.             raise ConnectionError('[-] Error: while reading from socket: (%s)' \
  25.                                     % e.args)
  26.     return (response, total_size)
复制代码
新代码:
  1. def tcp_recv_response(conn, bytes_size, buffer_size = 4096):
  2.     '''Receive response from server.
  3.         It is not include tracker header.
  4.         arguments:
  5.         @conn: connection
  6.         @bytes_size: int, will be received byte_stream size
  7.         @buffer_size: int, receive buffer size
  8.         @Return: tuple,(response, received_size)
  9.     '''
  10.     response = ''
  11.     total_size = 0
  12.     try:
  13.         while 1:
  14.             if bytes_size <= buffer_size:
  15.                 resp = conn._sock.recv(buffer_size)
  16.                 response +=resp
  17.                 total_size += len(resp)
  18.                 break
  19.             resp = conn._sock.recv(buffer_size)
  20.             response += resp
  21.             recv_size = len(resp)
  22.             total_size += recv_size
  23.             bytes_size = bytes_size - recv_size
  24.     except (socket.error, socket.timeout), e:
  25.             raise ConnectionError('[-] Error: while reading from socket: (%s)' \
  26.                                     % e.args)
  27.     return (response, total_size)
复制代码
修改说明:
  1. bytes_size = bytes_size - buffer_size
复制代码
改为
  1. recv_size = len(resp)
  2. total_size += recv_size
  3. bytes_size = bytes_size - recv_size
复制代码
在socket的接收的时候,bytes_size 应该是减去实际接收到数据的大小(即recv_size = len(resp)),而不是减去固定的buff_size, 这样很容易造成接收不完整,从而导致数据缺失

在附件中有我的修改后的版本,主要的修改地方有两个:

1、如上

2、在storage_client.py新增加一个tcp_recv_buff,用于收取buff数据
  1. def tcp_recv_buff(conn, file_size, buffer_size=4096):
  2.     '''
  3.     Receive buff from server, fragmented it while receiving and write to disk.
  4.     arguments:
  5.     @conn: connection
  6.     @file_size: int, remote file size
  7.     @buffer_size: int, receive buffer size
  8.     @Return int: file size if success else raise ConnectionError.
  9.     '''
  10.     total_file_size = 0
  11.     flush_size = 0
  12.     remain_bytes = file_size
  13.     respone = ""
  14.     print remain_bytes
  15.     while remain_bytes > 0:
  16.         try:
  17.             if remain_bytes >= buffer_size:
  18.                 file_buffer, recv_size = tcp_recv_response(conn, buffer_size, \
  19.                                                            buffer_size)
  20.             else:
  21.                 file_buffer, recv_size = tcp_recv_response(conn, remain_bytes, \
  22.                                                            buffer_size)
  23.             print recv_size
  24.             respone += file_buffer
  25.             remain_bytes -= recv_size
  26.             total_file_size += recv_size
  27.         except ConnectionError, e:
  28.             raise ConnectionError('[-] Error: while downloading buff(%s).' % e.args)
  29.         except IOError, e:
  30.             raise DataError('[-] Error: while writting local buff(%s).' % e.args)
  31.     return (respone,total_file_size)
复制代码
3、在storage_client.py中修改_storage_do_download_file里FDFS_DOWNLOAD_TO_BUFFER的调用函数
  1. recv_buffer, total_recv_size = tcp_recv_buff(store_conn, th.pkg_len)
复制代码
fdfs_client-py-1.2.6_ex.zip (193.28 KB, 下载次数: 15)


备注:这个python客户端问题比较多,效率不高,自己封装了一个,底层采用FastDFS C++接口,有兴趣的朋友可以看看,源码地址:github.com/cosysun/FastDFSClient_Python.git

作者: liuxuejin    时间: 2014-10-17 15:44
感谢,楼主有没有发现python版的客户端  无法饮用sendfile的错误,如何解决呢?
作者: fl8866    时间: 2014-10-17 20:36
这个感觉如何https://github.com/hay86/fdfs_client-py回复 1# gg9654


   
作者: gg9654    时间: 2015-01-28 16:45
建议不要使用这个python版本,发现效率不高,最后自己封装了一个客户端,底层采用C++客户端,稍后会开源回复 2# liuxuejin


   
作者: liuxuejin    时间: 2015-03-10 16:50
回复 4# gg9654


    那么靠谱 期待你的最新客户端,有github么,可以尽早放出来让大家看看




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2