1

I have a client that connect to server and send all messages of the list, and each message sent, it is deleted from the list.

But when I force to close the server, client still continue sending and deleting messages from the list. I would like that if connection is down, client stop to send messages, or don't delete from list if has no guarantee that server has received the message.

I check that when I sent more than four messages after connection is down, show the error "socket.send() raised exception". But I don't know how to get that error, I think it is asynchronous. Anyway, if I get that error, the error don't happen if the list has less than five messages to sent after connection down.

Ps: I wrote the server just for my tests, but the server I will have no access. So, the client that need to do everything to have the guarantee of data sent.

Thank you so much.

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()

server output (force (CTRL+C) to close server after received 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

client output

$ 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.

2 Answers 2

3

A write to a TCP socket does not guarantee that the data get received. It only sends the data to the OS kernel which then will try as hard as possible to send the data to the other side. But, the write call will already return success once the data are sent to the OS kernel. If the data then get received by the peers OS kernel it will acknowledge them at the TCP level. But, that only means that the data are received by the kernel and not that they are processed by the application.

If you want to have guaranteed message delivery and deal with possible close of the peer you have to implement some kind of acknowledgements inside your protocol and only remove the data once you get an explicit acknowledgment from your peer application after it successfully processed the data.

Sign up to request clarification or add additional context in comments.

Comments

1

I would like that if connection is down, client stop to send messages, or don't delete from list if has no guarantee that server has received the message.

So write code that does that. Don't delete the message until the server indicates that it has received the message. You can implement this any way that you like, but if it's the behavior you want, you have to code it.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.