Python边学边用BT客户端实现之(三)Peer协议设计

与peer建立tcp连接后,首先发送handshake消息进行握手

handshake消息格式如下:

一个字节0x19 + 一个字符串'BitTorrent protocol' + 8 byte 保留字节默认值为0(draft中对保留字节有定义)

+ 种子文件中info 部分的sha1字,大小为20个字节 + 20个自己的peer id(从tracker获取到的peer信息大多没有peerid,这个可以使用本地的peer id)

如果handshake信息协商不上,tcp连接将被关闭。

 

BT标准BEP-3中定义了8种peer消息:消息格式为msg_len(4个字节) + msg_type(1一个字节) + payload

0 - choke  --发送该消息表示本段发送阻塞,对端将不能获取到piece数据,payload 为 0

1 - unchoke  --发送该消息表示解阻塞,对端可以开始发送请求获取piece数据,payload 为 0

2 - interested  --发送该消息,表示对对端的pieces数据有兴趣,payload 为 0

3 - not interested  ---发送该消息,表示对对端的pieces数据没有兴趣了,payload 为 0

4 - have       ---发送该消息,通告对端 本段拥有的pieces,payload为4个字节的piece index

5 - bitfield  ---发送该消息,通告对端 本段拥有的pieces,为bit map的方式表示每个piece index在本端是否拥有。piece index所在bit位为1,表示拥有。

                     该消息为handshake成功后的第一个消息。

6 - request   ---piece请求消息,payload为: index, begin, and length,都是4个字节表示,length一般实现为0x8000, 最大不能超过0x20000。

7 - piece     ---piece  数据,payload为: index, begin,data 

8 - cancel    ---发送该消息,表示本端取消了某个piece请求。payload为:index, begin, and length

使用python的异步socket接口实现,为了减少处理过程被socket阻塞,使用多个线程处理每个peer。

每个peer包括3个线程:request timeout timer ,socket send data thread, socket receive data thread,使用select 函数判断socket是否可读、可写。

对socket读写操作时使用RLock进行保护,select阻塞进程时不加锁,避免阻塞其他线程。

发送数据数据时先写一个队列,然后通过set threading.Event 变量出发socket send data thread发送数据,保证发送数据的线程不阻塞

由于 python没有结束线程的接口,socket send data thread, socket receive data thread 需要依赖特殊变量的赋值,使socket处理进程结束。

使用同步调用来触发下载过程运转,尽量不使用timer轮询的方式,可以降低cpu使用率并加快下载过程。

但是,多线程间的同步调用由于锁的存在,会导致性能下降并容易引入信号量死锁的问题。需要仔细设计好多线程的运行轨迹避免死锁。

draft BEP中定义的功能暂未实现,peer的上传流控未实现,peer质量分级未实现。

PeerConnect
  1 '''
  2 Created on 2012-10-3
  3 
  4 @author: ddt
  5 '''
  6 from socket import *
  7 import threading
  8 import log_info
  9 import select
 10 
 11 class PeerConnect(object):
 12     '''
 13     TODO: upload flow control
 14     TODO: peer quality management
 15     '''
 16     def __init__(self, ip, port, task_info):
 17         '''
 18         Constructor
 19         '''
 20         self.__ip = ip
 21         self.__port = port
 22         
 23         self.__info_hash = task_info.get_info_hash()
 24         self.__local_id = task_info.get_local_id()
 25         self.__task_info = task_info
 26         
 27         leading_string = chr(19)+'BitTorrent protocol'
 28         reserved_string = chr(0)*8
 29         self.__handshake_info = leading_string + reserved_string 
 30         self.__handshake_info += self.__info_hash + self.__local_id
 31     
 32         self.__request_piece_len = 0x4000
 33         self.__receive_data_len = 0x8000
 34         
 35         self.__tcp_con = None
 36         self.__tcp_connect_timeout = 60
 37         
 38         self.__tcp_handshake_timeout = 60
 39         
 40         self.__keepalive_timer = None
 41         self.__sck_send_thread = None
 42         
 43         self.__retry_timer = None
 44         self.__retry_intvl = 2 # second
 45         self.__retry_times = 0
 46         self.__max_retrys = 10
 47         
 48         self.__local_choked = True
 49         self.__peer_choked = True
 50         self.__local_interested = False
 51         self.__peer_interested = False
 52         
 53         self.__peer_have_pieces = []
 54 
 55     
 56         self.__local_requesting = False;
 57         self.__local_requesting_pieces = []
 58         self.__local_max_requesting = 10
 59         self.__local_requesting_timer = None
 60         self.__local_requesting_timeout_intvl = 30
 61             
 62         self.__receiving_cache = ''
 63     
 64         self.__peer_pending_request = []
 65         self.__local_pending_request = []
 66         
 67         self.__local_pending_request_less = 10
 68         self.__peer_have_pieces_pending = []
 69         
 70         self.__local_sending_queue = None
 71         self.__rlock_sck_send = threading.RLock() 
 72         self.__local_sending_event = threading.Event()
 73         self.__min_sck_send_msg = 0x1000
 74         
 75         self.__rlock_common = threading.RLock()
 76         
 77         self.__peer_started = False
 78         
 79         self.__peer_choked_timer = None
 80         self.__peer_choked_timeout_intvl = 180
 81         
 82         self.__dispatch_timer = None
 83         self.__dispatch_timeout = 5
 84 
 85     def start(self):
 86         with self.__rlock_common:
 87             if not self.__peer_started:
 88                 self.__retry_times = 0
 89                 self.__startup_thread = threading.Thread(target=PeerConnect.__connect,args=(self,))
 90                 self.__peer_started = True
 91                 self.__startup_thread.start()
 92     
 93     def stop(self):
 94         with self.__rlock_common:
 95             if self.__peer_started:
 96                 self.__retry_times = self.__max_retrys
 97                 self.__disconnect()
 98                 self.__peer_started = False
 99         pass
100 
101     def dispatch_pieces(self,pieces, piece_len):
102         
103         with self.__rlock_common:
104         
105             self.__write_log(str(pieces))
106             self.__write_log(str(self.__peer_have_pieces))
107             
108             if len(pieces) == 0:
109                 return False
110             
111             for piece_index in pieces:
112                 if piece_index not in self.__peer_have_pieces:
113                     return False 
114                  
115             for piece_index in pieces:       
116                 for offset in range(0, piece_len, self.__request_piece_len):
117                     length = self.__request_piece_len
118                     if offset+length > piece_len:
119                         length = piece_len - offset
120                     piece = (piece_index, offset, length)
121                     if piece not in self.__local_pending_request:
122                         self.__local_pending_request.append(piece)
123             
124             if self.__dispatch_timer != None:
125                 self.__dispatch_timer.cancel()
126             
127             self.__check_local_request()
128             
129             if self.__peer_choked:
130                 if self.__peer_choked_timer == None or not self.__peer_choked_timer.is_alive():
131                     self.__peer_choked_timer = threading.Timer(self.__peer_choked_timeout_intvl, PeerConnect.__peer_choked_timeout, [self,])
132                     self.__peer_choked_timer.start()
133         
134             
135         return True
136     
137     def cancel_pieces(self, pieces):
138         with self.__rlock_common:
139             for piece in self.__local_pending_request:
140                 if piece[0] in pieces:
141                     self.__local_pending_request.remove(piece)
142                     
143             if self.__local_requesting:
144                 for piece in self.__local_requesting_pieces:
145                     if piece[0] in pieces:
146                         self.__send_cancel(piece)
147                         self.__local_requesting_pieces.remove(piece)
148                 if len(self.__local_requesting_pieces) == 0:
149                     self.__local_requesting = False
150                     if self.__local_requesting_timer != None:
151                         self.__local_requesting_timer.cancel()       
152                 self.__check_local_request()
153 
154         
155     def set_choke_state(self, choked):
156         with self.__rlock_common:
157             if self.__local_choked != choked:
158                 if choked:
159                     self.__send_choked()
160                 else:
161                     self.__send_unchoked()
162                     self.__check_peer_request()
163             pass
164         
165     def get_peer_have_pieces(self):
166         with self.__rlock_common:
167             return self.__peer_have_pieces
168     
169     def notify_local_have_pieces(self, pieces):
170         with self.__rlock_common:
171             self.__send_have(pieces)
172          
173     def is_dead_peer(self):
174         with self.__rlock_common:
175             return  self.__retry_times > self.__max_retrys
176     
177     def get_local_pending_pieces(self):
178         with self.__rlock_common:
179             pieces_index = []
180             for piece in self.__local_pending_request:
181                 if piece[0] not in pieces_index:
182                     pieces_index.append(piece[0])
183             if self.__local_requesting:
184                 for piece in self.__local_requesting_pieces: 
185                     if piece[0] not in pieces_index:
186                         pieces_index.append(piece[0])
187 
188         return pieces_index
189     
190     def get_peer_addr(self):
191         return (self.__ip, self.__port)
192         
193     def __connect(self):
194 
195         self.__tcp_con = socket(AF_INET, SOCK_STREAM)
196         self.__tcp_con.settimeout(self.__tcp_connect_timeout)
197 
198         try:
199             self.__tcp_con.connect((self.__ip,self.__port))
200         except error , e:
201             self.__write_log('peer connect error: %s, retry' %e)
202             self.__retry_connect()
203             return
204         
205         self.__tcp_con.settimeout(None)
206         
207         self.__start_send_proc()
208 
209         if not self.__handshake():
210             self.__retry_connect()
211             return
212         
213         self.__send_bitfield()
214         self.__send_unchoked()
215         self.__start_keepalive_timer()      
216 
217         self.__recv_loop()
218     pass
219 
220     def __disconnect(self):
221         self.__write_log('__disconnect:begin')
222         
223         if self.__retry_timer != None:
224             self.__retry_timer.cancel()
225         
226         if self.__keepalive_timer != None:
227             self.__keepalive_timer.cancel()
228             
229         if self.__local_sending_queue != None:
230             self.__local_sending_queue = None
231             self.__local_sending_event.set()
232             
233         if self.__peer_choked_timer != None:
234             self.__peer_choked_timer.cancel()
235             
236         if self.__dispatch_timer != None:
237             self.__dispatch_timer.cancel()    
238 
239         
240         if self.__local_requesting:
241             self.__local_requesting = False
242             self.__local_pending_request = self.__local_requesting_pieces + self.__local_pending_request
243             self.__local_requesting_pieces = []
244             if self.__local_requesting_timer != None:
245                 self.__local_requesting_timer.cancel()
246         
247         self.__tcp_con.close()
248         self.__write_log('__disconnect: self.__tcp_con.closed')
249         
250         self.__receiving_cache = ''
251         
252         self.__local_choked = True
253         self.__peer_choked = True
254         self.__local_interested = False
255         self.__peer_interested = False
256         self.__local_requesting_pieces = []
257         self.__peer_pending_request = []
258         self.__peer_have_pieces = []
259         self.__peer_have_pieces_pending = []
260         pass
261     
262     def __start_keepalive_timer(self):
263         if self.__keepalive_timer != None:
264             self.__keepalive_timer.cancel()
265         self.__keepalive_timer = threading.Timer(120,PeerConnect.__send_keepalive_timeout,[self,])
266         self.__keepalive_timer.start()
267         
268     def __send_keepalive_timeout(self):
269         
270         with self.__rlock_common:
271             self.__send_keepalive()
272             self.__start_keepalive_timer()
273         
274     def __recv_loop(self):
275         self.__tcp_con.setblocking(False)
276         while True:
277             ready_r, ready_w, in_err = select.select([self.__tcp_con,], [], [self.__tcp_con,], 600)
278             
279             with self.__rlock_common:
280                 if self.__tcp_con in in_err:
281                     self.__write_log('__recv_loop: socket in error select result:%s' %str(in_err))
282                     self.__retry_connect()
283                     break
284                 
285                 if self.__tcp_con not in ready_r:
286                     self.__write_log('__recv_loop: unexpected select result!')
287                     continue 
288                 
289                 try:
290                     received_data = self.__tcp_con.recv(self.__receive_data_len)
291                         
292                 except error, e:
293                     self.__write_log("receive data failed, error:%s, retry" %e)
294                     self.__retry_connect()
295                     break
296             
297                 if len(received_data) == 0:
298                     self.__write_log("have received null data")
299                     self.__retry_connect()
300                     break
301             
302                 self.__reveived_data(received_data)
303         pass
304     
305     def __start_send_proc(self):
306         with self.__rlock_sck_send:
307             self.__local_sending_queue = ''
308         self.__sck_send_thread = threading.Thread(target=PeerConnect.__proc_sending, args=(self,))
309         self.__sck_send_thread.start()
310         
311     def __proc_sending(self):
312         while self.__local_sending_queue != None:
313                         
314             ready_r, ready_w, in_err = select.select([], [self.__tcp_con,], [self.__tcp_con,])
315             
316             self.__local_sending_event.wait()
317 
318             with self.__rlock_common:
319                 
320                 if self.__tcp_con  in in_err:
321                     self.__tcp_con.close()
322                     break
323                 
324                 if self.__tcp_con not in ready_w:
325                     self.__write_log('__proc_sending: unexpected select result!')
326                     continue
327                 
328                 if self.__local_sending_queue == None:
329                     break
330                 
331                 try:
332                     sent_len = self.__tcp_con.send(self.__local_sending_queue)
333                     self.__local_sending_queue = self.__local_sending_queue[sent_len:]
334                     
335                 except error,e:
336                     self.__tcp_con.close()
337                     self.__write_log('__proc_sending failed! error:%s' %str(e))
338                     break
339                     
340                 if len(self.__local_sending_queue) == 0:
341                     self.__local_sending_event.clear()
342         pass
343     
344     def __check_peer_request(self):
345         if self.__peer_interested and not self.__local_choked:
346             while len(self.__peer_pending_request) > 0:
347                 piece = self.__peer_pending_request.pop(0)
348                 piece_index, offset, length = piece
349                 if self.__local_have(piece_index):
350                     data = self.__read_piecedata(piece_index,offset, length)
351                     self.__send_piece(piece_index, offset, data)
352                 else:
353                     self.__write_log('peer request piece:%d not have.' %piece_index)
354         pass
355 
356     def __check_local_request(self): 
357         with self.__rlock_common:
358             self.__check_interested() 
359             
360             if self.__local_requesting and len(self.__local_requesting_pieces) >= self.__local_max_requesting:
361                 return
362             
363             if len(self.__local_pending_request) != 0:
364                 if not self.__local_interested:
365                     self.__send_interested()
366             else:
367                 if len(self.__peer_have_pieces) != 0:
368                     if self.__dispatch_timer != None:
369                         self.__dispatch_timer.cancel()
370                         
371                     self.__dispatch_timer = threading.Timer(self.__dispatch_timeout,PeerConnect.__check_local_request ,[self,])
372                     self.__dispatch_timer.start()
373                     self.__local_interested = False
374                     self.__notify_pieces_completed()
375                 return
376             
377             if self.__peer_choked:
378                 return
379         
380             adding_piece = self.__local_pending_request.pop(0)
381             if adding_piece[0] not in self.__peer_have_pieces:
382                 for piece in self.__local_pending_request:
383                     if piece[0] == adding_piece[0]:
384                         self.__local_pending_request.remove(piece)
385                 self.__notify_pieces_canceled([adding_piece[0],])
386                 self.__check_local_request()
387             else:
388                 self.__local_requesting = True
389                 self.__local_requesting_pieces.append(adding_piece)    
390                 self.__send_request(adding_piece)
391                 self.__check_local_request()
392                 
393                 if self.__local_requesting_timer == None or not self.__local_requesting_timer.is_alive():
394                     self.__local_requesting_timer = threading.Timer(self.__local_requesting_timeout_intvl, PeerConnect.__local_requesting_timeout, [self,])
395                     self.__local_requesting_timer.start()
396             pass
397     
398     def __local_requesting_timeout(self):
399         with self.__rlock_common:
400             if self.__local_requesting:
401                 self.__local_requesting = False
402                 self.__local_pending_request = self.__local_requesting_pieces + self.__local_pending_request
403                 self.__local_requesting_pieces = []
404                 self.__local_interested = False
405                 self.__check_local_request()
406 
407         pass
408     
409     def __peer_choked_timeout(self):
410         with self.__rlock_common:
411             if self.__peer_choked:
412                 pending_pieces = []
413                 for piece in self.__local_pending_request:
414                     if piece[0] not in pending_pieces:
415                         pending_pieces.append(piece[0])
416                 if len(pending_pieces) != 0:
417                     self.__notify_pieces_canceled(pending_pieces)
418                     self.__local_pending_request = []
419         
420                     
421     
422     def __check_interested(self):
423         if not self.__local_requesting:
424             if len(self.__local_pending_request) != 0 and not self.__local_interested:
425                 self.__send_interested()
426                 
427         if not self.__local_requesting and len(self.__local_pending_request) == 0:
428             if self.__local_interested:
429                 self.__send_notintrested()
430         pass
431                 
432     def __retry_connect(self):
433         
434         self.__write_log('__retry_connect')
435         pending_pieces = []
436         peer_dead = False
437          
438         with self.__rlock_common:
439             self.__disconnect()
440             
441             for piece in self.__local_pending_request:
442                 if piece[0] not in pending_pieces:
443                     pending_pieces.append(piece[0])
444                     
445             self.__retry_times += 1
446             if self.__retry_times > self.__max_retrys:
447                 peer_dead = True
448 
449             else:
450                 self.__retry_timer = threading.Timer(self.__retry_intvl**self.__retry_times, PeerConnect.__connect, [self,])
451                 self.__retry_timer.start()
452                 
453         if peer_dead == True:        
454             self.__notify_peer_dead()
455             
456         if len(pending_pieces) != 0:
457             self.__notify_pieces_canceled(pending_pieces)
458             self.__local_pending_request = []
459 
460     def __reveived_data(self, data):
461         self.__receiving_cache += data
462             
463         while len(self.__receiving_cache) >= 4:
464             msg_len = _str_ntohl(self.__receiving_cache[0:4])
465             
466             if (len(self.__receiving_cache)-4) >= msg_len:
467                 self.__proc_msg(self.__receiving_cache[4:(4+msg_len)])
468                 self.__receiving_cache = data[4+msg_len:]
469             else:
470                 break
471                     
472                 
473     def __proc_msg(self, msg):
474         with self.__rlock_common:
475             if len(msg) == 0:
476                 self.__received_keepalive()
477             else: 
478                 msg_type = msg[0]
479                 if msg_type == chr(0):
480                     self.__received_choked()
481                 elif msg_type == chr(1):
482                     self.__received_unchoked()
483                 elif msg_type == chr(2):
484                     self.__received_interested()
485                 elif msg_type == chr(3):
486                     self.__received_notinterested()
487                 elif msg_type == chr(4):
488                     self.__received_have(msg[1:])                                
489                 elif msg_type == chr(5):
490                     self.__received_bitfield(msg[1:])
491                 elif msg_type == chr(6):
492                     self.__received_request(msg[1:])             
493                 elif msg_type == chr(7):
494                     self.__received_piece(msg[1:])
495                 elif msg_type == chr(8):
496                     self.__received_cancel(msg[1:]) 
497                 else:
498                     self.__write_log('received unknown msg :%s' %list(msg))
499     
500     def  __handshake(self):
501         self.__write_log('send handshake: %s' %list(self.__handshake_info))
502         self.__tcp_con.sendall(self.__handshake_info)
503         
504         try:
505             self.__tcp_con.settimeout(self.__tcp_handshake_timeout)
506             rsp = self.__tcp_con.recv(68)
507             
508             if len(rsp) != 68:
509                 return False
510             
511             self.__tcp_con.settimeout(None)
512             self.__write_log('recived handshake rsp: %s' %list(rsp))
513             self.__peer_id = rsp[47:67]
514             self.__write_log('peer_id:%s' %self.__peer_id)
515             
516         except (error,timeout), e:
517             self.__write_log('handshake failed, error:%s' %e)
518             return False
519         return True
520     
521     def __received_keepalive(self):
522         self.__write_log('received keepalive')
523         #self.__send_keepalive()
524         pass
525             
526     def __received_choked(self):
527 
528         self.__peer_choked = True
529         
530         if self.__local_requesting:
531             self.__local_requesting = False
532             self.__local_pending_request =  self.__local_requesting_pieces + self.__local_pending_request
533             self.__local_requesting_pieces = []
534             
535         self.__notify_peer_choked()
536         
537         if len(self.__local_pending_request) != 0:
538             pending_pieces = []
539             for piece in self.__local_pending_request:
540                 if piece[0] not in pending_pieces:
541                     pending_pieces.append(piece[0])
542             self.__notify_pieces_canceled(pending_pieces)
543             self.__local_pending_request = []
544             self.__local_interested = False
545             
546         self.__write_log('received choked')
547         
548     def __received_unchoked(self):
549         self.__peer_choked = False
550         
551         self.__notify_peer_unchoked()
552         
553         #if len(self.__local_pending_request) < self.__local_pending_request_less:
554         self.__check_local_request()
555         
556         if self.__peer_choked_timer != None:
557             self.__peer_choked_timer.cancel()
558             
559         self.__write_log('received unchoked')
560         
561     
562     def __received_interested(self):
563         self.__peer_interested = True
564         #self.__send_unchoked()
565         self.__write_log('received interested')
566         
567     def __received_notinterested(self):
568         self.__peer_interested = False
569         self.__peer_pending_request = [] 
570         self.__write_log('received notinterested')
571         
572     def __received_have(self, data):
573         '''
574         TODO:Notify peer have pieces changed
575         '''
576         piece_index = _str_ntohl(data[0:4])
577         if piece_index not in self.__peer_have_pieces:
578             self.__peer_have_pieces.append(piece_index)
579             self.__peer_have_pieces_pending.append(piece_index)
580             if len(self.__local_pending_request) < self.__local_pending_request_less:
581                 self.__notify_pieces_have(self.__peer_have_pieces_pending)
582                 self.__peer_have_pieces_pending = []
583             
584             
585         self.__write_log('received have piece:%d' %piece_index)
586 
587     def __received_bitfield(self, data):
588         '''
589         '''
590         bitfield_len = len(data)
591         for i in range(0,bitfield_len):
592             byte = data[i]
593             for j in range(0,8):
594                 byte_mask = 1<<(7-j)
595                 piece_index = i*8+j
596                 have = ord(byte)&byte_mask
597                 if have != 0:
598                     if piece_index not in self.__peer_have_pieces:
599                         self.__peer_have_pieces.append(piece_index)
600                         
601         self.__notify_pieces_have(self.__peer_have_pieces)
602 
603         self.__write_log('received bitfield ,peer have pieces:%s' %self.__peer_have_pieces)
604 
605     def __received_request(self, data):
606         piece_index = _str_ntohl(data[0:4])
607         offset      = _str_ntohl(data[4:8])
608         data_len    = _str_ntohl(data[8:12])
609         if self.__peer_interested:
610                 self.__peer_pending_request.append((piece_index, offset, data_len))
611         else:
612             self.__write_log("received request piece:%d , but peer not interested" %piece_index)
613         
614         self.__check_peer_request()
615         self.__write_log("received request piece:%d " %piece_index)
616     
617     def __received_piece(self, data):
618         piece_index = _str_ntohl(data[0:4])
619         offset      = _str_ntohl(data[4:8])
620         piece = (piece_index, offset, len(data)-8)
621         
622         if self.__local_requesting:
623             if piece in self.__local_requesting_pieces:
624                 self.__write_piecedata(piece_index, offset, data[8:])
625                 self.__local_requesting_pieces.remove(piece)
626                 
627             if self.__local_requesting_timer != None:
628                 self.__local_requesting_timer.cancel()
629                 
630             if len(self.__local_requesting_pieces) == 0:  
631                 self.__local_requesting = False
632                 
633             self.__check_local_request()
634             self.__write_log("received  piece: %s" %str((piece_index, offset, len(data)-8)))
635         else:
636             self.__write_log("received unexpected piece: %s" %str((piece_index, offset, len(data)-8)))
637 
638     def __received_cancel(self, data):
639         piece_index = _str_ntohl(data[0:4])
640         offset      = _str_ntohl(data[4:8])
641         data_len    = _str_ntohl(data[8:12])
642         request = (piece_index, offset, data_len)
643         if request in self.__peer_pending_request:
644             self.__peer_pending_request.remove(request)
645         self.__check_peer_request()
646         self.__write_log("received cancel: %s" %str((piece_index,offset,data_len)))
647             
648     def __send_keepalive(self):
649         msg_len = 0
650         msg = _htonl_str(msg_len)
651         self.__write_log('send keepalive: %s' %list(msg))
652         self.__sck_send(msg)
653         
654     def __send_choked(self):
655         self.__local_choked = True
656         msg_type = chr(0)
657         msg_len = 1
658         msg = _htonl_str(msg_len) + msg_type
659         self.__write_log('send choked: %s' %list(msg))
660         self.__sck_send(msg)
661         
662     def __send_unchoked(self):
663         self.__local_choked = False
664         msg_type = chr(1)
665         msg_len = 1
666         msg = _htonl_str(msg_len) + msg_type
667         self.__write_log('send unchoked: %s' %list(msg))
668         self.__sck_send(msg)    
669         
670     def __send_interested(self):
671         self.__local_interested = True
672         msg_type = chr(2)
673         msg_len = 1
674         msg = _htonl_str(msg_len) + msg_type
675         self.__write_log('send intrested: %s' %list(msg))
676         self.__sck_send(msg)
677         
678     def __send_notintrested(self):
679         self.__local_interested = False
680         msg_type = chr(3)
681         msg_len = 1
682         msg = _htonl_str(msg_len) + msg_type
683         self.__write_log('send notintrested: %s' %list(msg))
684         self.__sck_send(msg)
685         
686     def __send_have(self,pieces):
687         msg = ''
688         msg_type = chr(4)
689         msg_len = 5
690         for piece_index in pieces:
691             msg += _htonl_str(msg_len) + msg_type +  _htonl_str(piece_index)
692         self.__write_log('send have: %s' %str(list(msg)))
693         self.__sck_send(msg)
694         
695     def __send_bitfield(self):
696         bitfield = self.__get_local_bitfield()
697         msg_type = chr(5)
698         msg_len = 1 + len(bitfield)
699         msg = _htonl_str(msg_len) + msg_type + bitfield
700         self.__sck_send(msg)
701         self.__write_log('send bitfield: %s' %list(msg))
702         
703     def __send_request(self, piece):
704         msg = ''
705         msg_type = chr(6)
706         msg_len = 13
707         (piece_index, begin, length) = piece
708         msg += _htonl_str(msg_len) + msg_type + _htonl_str(piece_index) + _htonl_str(begin) + _htonl_str(length)
709         self.__write_log('send request: %s' %list(msg))
710         self.__sck_send(msg)
711     
712     def __send_piece(self, piece_index, offset, data):
713         msg = ''
714         msg_type = chr(7)
715         data_len = len(data)
716         msg_len = 1 + 4 + 4 + data_len
717         msg += _htonl_str(msg_len) + msg_type + _htonl_str(piece_index) + _htonl_str(offset)
718         msg += data
719         self.__write_log('send piece (%d,%d)' %(piece_index, offset))
720         self.__sck_send(msg)
721         
722     def __send_cancel(self, piece_index, offset, length):
723         msg = ''
724         msg_type = chr(8)
725         msg_len = 13
726         msg += _htonl_str(msg_len) + msg_type + _htonl_str(piece_index) + _htonl_str(offset) + _htonl_str(length)
727         self.__write_log('send cancel: %s' %list(msg))
728         self.__sck_send(msg)
729             
730     def __sck_send(self, msg):
731         with self.__rlock_common:
732             if self.__local_sending_queue == None:
733                 self.__write_log('sck send msg failed, because queue is none!')
734                 return
735             
736             self.__local_sending_queue += msg
737             self.__local_sending_event.set()
738             #self.__tcp_con.sendall(msg)
739 
740         
741     def __local_have(self,piece_index):
742         pieces = self.__task_info.get_local_have_pieces()
743         if piece_index in pieces:
744             return True
745         else:
746             return False
747 
748     def __read_piecedata(self, piece_index, offset, data_len):
749         return self.__task_info.read_piecedata(piece_index, offset, data_len)
750     
751     def __write_piecedata(self, piece_index, offset, data):
752         self.__task_info.write_piecedata(piece_index, offset, data)
753     
754     def __notify_pieces_canceled(self, pieces):
755         self.__write_log('notify taskinfo canceled pieces')
756         self.__task_info.peer_pieces_canceled(self, pieces)
757     
758     def __notify_pieces_have(self, pieces):
759         self.__write_log('notify taskinfo peeer have pieces')
760         self.__task_info.peer_have_pieces(self, pieces)
761         
762     def __notify_pieces_completed(self):
763         self.__task_info.peer_pieces_completed(self)
764     
765     def __notify_peer_choked(self):
766         self.__task_info.peer_choked(self)
767         
768     def __notify_peer_unchoked(self):
769         self.__task_info.peer_unchoked(self)
770         
771     def __notify_peer_dead(self):
772         self.__task_info.peer_dead(self)
773     
774     def __get_local_bitfield(self):
775         pieces_num = self.__task_info.get_pieces_num()
776         bitfield_len = pieces_num/8
777         if pieces_num%8 != 0:
778             bitfield_len += 1
779         bitfield = [chr(0),]*bitfield_len
780         
781         pieces = self.__task_info.get_local_have_pieces()
782         for index in pieces:
783             bit_filed_index = index / 8
784             bit_field_offset = index % 8
785             byte_mask = 1<<bit_field_offset
786             byte = ord(bitfield[bit_filed_index])
787             byte |= byte_mask
788             bitfield[bit_filed_index] = chr(byte)
789         return ''.join(bitfield)
790     
791     def __write_log(self, info):
792         log_info.write_log('#peer_connect[%s]# '  %self.__ip + info)
793         pass
794          
795 def _htonl_str(integer):
796     msg = ''
797     msg += chr((integer>>24)%0x100)
798     msg += chr((integer>>16)%0x100)
799     msg += chr((integer>>8)%0x100)
800     msg += chr(integer%0x100)
801     return msg
802 
803 def _str_ntohl(msg):
804     integer = 0
805     integer += ord(msg[0])<<24
806     integer += ord(msg[1])<<16
807     integer += ord(msg[2])<<8
808     integer += ord(msg[3])
809     return integer
原文地址:https://www.cnblogs.com/piaoliu/p/2714598.html