2016-07-27 2 views
2

방금 ​​DCC SEND 부분을 추가 한 새 IRC 클라이언트를 작성하여 두 사용자 모두에게 직접 파일 전송을 지원합니다. 아무것도 아니에요, fancy, 저는 GUI 용 클라이언트와 Django에 irc 파이썬 라이브러리를 사용하고 있습니다. 훌륭한 miniupnpc lib는 포트 포워딩을 처리합니다. 그러나 파일이 제대로 전송/수신되는 동안 속도는 절대적으로 엄청납니다 : 대략 20KB/s입니다. 서버를 테스트하기 위해 Hexchat을 사용하여 패키지를 보냈습니다. 업로드 속도는 최대 이론적 인 대역폭 속도 (즉, 우수)였습니다. 내가 놓친 일종의 버퍼를 찾으려고 노력했다. 결국, 내 업로드 속도가 왜 그렇게 진절머리 나고 어떤 통찰력을 필요로하는지 전혀 모르겠다. 다음은 업로드 스크립트의 관련 부분입니다.Python3; 데이터 전송 속도 : IRC 프로토콜, DCC 파일 전송

def on_dcc_connect(self, c, e): 
    t = threading.Timer(0, upload_monitoring, [self, c]) 
    t.start()  
    log("connection made with %s" % self.nickname).write() 
    self.file = open(self.filename, 'rb') 
    self.sendBlock() 


def sendBlock(self): 
    if self.position > 0: 
     self.file.seek(self.position) 
    block = self.file.read(1024) 
    if block: 
     self.dcc.send_bytes(block) 
     self.bytesSent = self.bytesSent + len(block) 
    else: 
     # Nothing more to send, transfer complete. 
     self.connection.quit() 

def on_dccsend(self, c, e): 
    if e.arguments[1].split(" ", 1)[0] == "RESUME": 
     self.position = int(e.arguments[1].split(" ")[3]) 
     c.ctcp("DCC", self.nickname, "ACCEPT %s %d %d" % (
     os.path.basename(self.filename), 
     self.eport, 
     self.position)) 



def on_dccmsg(self, connection, event): 
    data = event.arguments[0] 
    bytesAcknowledged = struct.unpack("!Q", data)[0] 
    if bytesAcknowledged < self.bytesSent: 
     return 
    elif bytesAcknowledged > self.bytesSent: 
     self.connection.quit() 
     return 
    self.sendBlock() 

send_bytes(block)있어서 기본적인 socket.send() 방법이다. file.read()의 버퍼를 늘리면 클라이언트의 블록 수신 확인 (struct.pack)이 내 send 스크립트에서 제대로 읽히지 않기 때문에 struct.pack 오류가 발생합니다. 바이트 길이가 8 인 데이터가 아닙니다. file.read 버퍼를 변경해야합니까? 그렇다면 수신 된 바이트가 다운로더 측과 같이 송신 측에서 동일하지 않은 이유는 무엇입니까? 그렇지 않다면 어디서 업로드 속도를 향상시켜야합니까?

+1

성능에 대한 재현 방법이 없기 때문에 이에 대해 말할 수는 없습니다. 내 생각 엔, 1KB 청크로 파일을 읽고 1KB 패킷으로 청크를 보내면 성능이 매우 떨어집니다. 최소한이 파일은 64/128/512KB 청크로 읽을 수 있으며 가능한 한 네트워크에서 보내는 패킷의 크기를 늘리십시오. – Bakuriu

+0

그런 경우 bytesAcknowledged가 클라이언트가 보낸 acknoldgement와 다른 이유는 무엇입니까? 그것은 단지'structured = struct.pack ("! Q", self.dict [bot] [ "received_bytes"])'그리고 나서'connection.send_bytes (structured) '입니다. – mrj

+0

당신이 나에게 묻고있는 것을 이해하지 못합니다. 소켓을 통해 데이터를 보낼 때 * 커널 *이 메시지를 더 많은 패킷으로 나누기로 결정하면 클라이언트가 데이터를 더 적게 읽게됩니다. 필요한 모든 데이터를받을 때까지 여러 번 전화를 거는 것은 귀하의 책임입니다. – Bakuriu

답변

0

내가 이미 의심하고 Bakuriu가 지적한 것처럼 문제는 실제로 file.read(buffer) 라인에있었습니다. 마침내 왜 struct.pack 오류가 발생했는지 알았습니다. 바이트 승인이 송신자에게 제대로 전송되었지만 때로는 몇 개의 패킷이 함께 결합되는 경우가있었습니다. 즉, 수신 된 모든 패킷에 대해 수신인은 8 바이트 길이의 팩형 부호없는 정수 형태로 발신자에게 응답합니다. 때때로 sock.recv()은 들어오는 데이터를 충분히 빠르게 읽지 않고 길이가 8 인 bytes 객체 대신 16, 24, 32, 40 또는 그 이상의 길이의 바이트 객체를 가지고 있습니다. 그래서 struct.pack("!Q", data)으로 개봉 할 수 없었습니다. 내가 그 알아 낸 한 후, 해결책은 찾을 상당히 쉬웠다 :

def on_dccmsg(self, connection, event): 
    data = event.arguments[0][-8:] 
    bytesAcknowledged = struct.unpack("!Q", data)[0] 

난 그냥 대신 모든 것을 읽는 sock.recv()에 의해 판독 된 데이터에서 마지막 8 바이트를 읽어보십시오. 이제 그것은 매력처럼 작동하며 업로드 속도는 내 대역폭이 허용하는 최대 이론 업로드 속도입니다 !!!