2014-10-01 70 views
1

我有一個客戶端連接到服務器併發送列表中的所有消息,並且發送每條消息,它將從列表中刪除。如何保證使用python asyncio發送的tcp數據?

但是,當我強制關閉服務器時,客戶端仍然繼續發送和從列表中刪除消息。我希望如果連接關閉,客戶端停止發送消息,或者如果不能保證服務器已收到消息,則不要從列表中刪除。

我檢查當連接斷開後發送超過四條消息時,顯示錯誤「socket.send()引發異常」。但我不知道如何得到這個錯誤,我認爲它是異步的。無論如何,如果我得到那個錯誤,如果列表連接關閉後發送少於五條消息,錯誤不會發生。

Ps:我寫了服務器只是爲了我的測試,但服務器我將無法訪問。因此,需要盡一切努力保證數據發送的客戶端。

非常感謝。

client.py
import asyncio 

class Client(asyncio.Protocol): 
    TIMEOUT = 1.0 
    event_list = [] 
    for i in range(10): 
     event_list.append('msg' + str(i)) 

    def __init__(self): 
     self.client_tcp_timeout = None 
     print(self.event_list) 

    def connection_made(self, transport): 
     print('Connected to Server.') 
     self.transport = transport 
     self.client_tcp_timeout = loop.call_later(self.TIMEOUT, self.send_from_call_later) 

    def data_received(self, data): 
     self.data = format(data.decode()) 
     print('data received: {}'.format(data.decode())) 

    def send_from_call_later(self): 
     self.msg = self.event_list[0].encode() 
     self.transport.write(self.msg) 
     print('data sent: {}'.format(self.msg)) 
     print('Removing data: {}'.format(self.event_list[0])) 
     del self.event_list[0] 
     print(self.event_list) 
     print('-----------------------------------------') 
     if len(self.event_list) > 0: 
      self.client_tcp_timeout = loop.call_later(self.TIMEOUT, self.send_from_call_later) 
     else: 
      print('All list was sent to the server.') 

    def connection_lost(self, exc): 
     print('Connection lost!!!!!!.') 

loop = asyncio.get_event_loop() 

coro = loop.create_connection(Client, 'localhost', 8000) 
client = loop.run_until_complete(coro) 

loop.run_forever() 

server.py
import asyncio 

class Server(asyncio.Protocol): 
    def connection_made(self, transport): 
     peername = transport.get_extra_info('peername') 
     print('connection from {}'.format(peername)) 
     self.transport = transport 

    def data_received(self, data): 
     print('data received: {}'.format(data.decode())) 
     #self.transport.write(data) 

loop = asyncio.get_event_loop() 
coro = loop.create_server(Server, 'localhost', 8000) 
server = loop.run_until_complete(coro) 

print('serving on {}'.format(server.sockets[0].getsockname())) 

try: 
    loop.run_forever() 
except KeyboardInterrupt: 
    print("exit") 
finally: 
    server.close() 
    loop.close() 

服務器輸出(力(CTRL + C)接收MSG4之後關閉服務器):

$ python3 server.py 
serving on ('127.0.0.1', 8000) 
connection from ('127.0.0.1', 56119) 
data received: msg0 
data received: msg1 
data received: msg2 
data received: msg3 
data received: msg4 
^Cexit 

客戶端輸出

$ python3 client.py 
['msg0', 'msg1', 'msg2', 'msg3', 'msg4', 'msg5', 'msg6', 'msg7', 'msg8', 'msg9'] 
Connected to Server. 
data sent: b'msg0' 
Removing data: msg0 
['msg1', 'msg2', 'msg3', 'msg4', 'msg5', 'msg6', 'msg7', 'msg8', 'msg9'] 
----------------------------------------- 
data sent: b'msg1' 
Removing data: msg1 
['msg2', 'msg3', 'msg4', 'msg5', 'msg6', 'msg7', 'msg8', 'msg9'] 
----------------------------------------- 
data sent: b'msg2' 
Removing data: msg2 
['msg3', 'msg4', 'msg5', 'msg6', 'msg7', 'msg8', 'msg9'] 
----------------------------------------- 
data sent: b'msg3' 
Removing data: msg3 
['msg4', 'msg5', 'msg6', 'msg7', 'msg8', 'msg9'] 
----------------------------------------- 
data sent: b'msg4' 
Removing data: msg4 
['msg5', 'msg6', 'msg7', 'msg8', 'msg9'] 
----------------------------------------- 
Connection lost!!!!!!. 
data sent: b'msg5' 
Removing data: msg5 
['msg6', 'msg7', 'msg8', 'msg9'] 
----------------------------------------- 
data sent: b'msg6' 
Removing data: msg6 
['msg7', 'msg8', 'msg9'] 
----------------------------------------- 
data sent: b'msg7' 
Removing data: msg7 
['msg8', 'msg9'] 
----------------------------------------- 
data sent: b'msg8' 
Removing data: msg8 
['msg9'] 
----------------------------------------- 
socket.send() raised exception. 
data sent: b'msg9' 
Removing data: msg9 
[] 
----------------------------------------- 
All list was sent to the server. 

回答

3

寫入TCP套接字並不能保證數據的接收。它只將數據發送到操作系統內核,然後儘可能地將數據發送到另一端。但是,一旦數據發送到操作系統內核,寫入調用就會返回成功。如果數據然後被對等OS內核接收到,它將在TCP級別上確認它們。但是,這隻意味着數據由內核接收,而不是由應用程序處理。

如果您希望保證消息傳遞並處理可能的對等關閉,則必須在協議內部實施某種確認,並且只有在您的對等應用程序成功處理後才能得到來自對等應用程序的明確確認後纔會刪除數據數據。

1

我想,如果連接關閉,客戶端停止發送消息,或者如果不能保證服務器已收到消息,則不要從列表中刪除。

因此,編寫這樣的代碼。直到服務器指示它已收到消息,才能刪除該消息。你可以用你喜歡的任何方式來實現,但如果它是你想要的行爲,你必須對它進行編碼。