I want to build a chat demo, but I can not receive the server-side things sent, in addition to the first time to start, anyone know why?
code from https://docs.python.org/3.4/library/asyncio-protocol.html#tcp-echo-client-protocol
Server.py
import asyncio
class EchoServerClientProtocol(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):
message = data.decode()
print('Data received: {!r}'.format(message))
print('Send: {!r}'.format(message))
self.transport.write(data)
loop = asyncio.get_event_loop()
# Each client connection will create a new protocol instance
coro = loop.create_server(EchoServerClientProtocol, '127.0.0.1', 8888)
server = loop.run_until_complete(coro)
# Serve requests until Ctrl+C is pressed
print('Serving on {}'.format(server.sockets[0].getsockname()))
try:
loop.run_forever()
except KeyboardInterrupt:
pass
# Close the server
server.close()
loop.run_until_complete(server.wait_closed())
loop.close()
Client.py
class EchoClientProtocol(asyncio.Protocol):
def __init__(self, message, loop):
self.message = message
self.loop = loop
self.transport = None
def connection_made(self, transport):
self.transport = transport
transport.write(self.message.encode())
print('Data sent: {!r}'.format(self.message))
# while 1:
# message=input('please input the message:')
# transport.write(message.encode())
# print('Data sent: {!r}'.format(message))
def data_received(self, data):
# print('data_received')
print('Data received: {!r}'.format(data.decode()))
while 1:
message = input('please input the message:')
self.transport.write(message.encode())
print('Data sent: {!r}'.format(message))
def connection_lost(self, exc):
print('The server closed the connection')
print('Stop the event loop')
self.loop.stop()
loop = asyncio.get_event_loop()
message = 'Hello World!'
coro = loop.create_connection(lambda: EchoClientProtocol(message, loop),
'127.0.0.1', 8888)
loop.run_until_complete(coro)
loop.run_forever()
loop.close()
result show:
cant not show 'Data received: '#####'
like 'def data_received(self, data)' is only used onece
anyone have solution?
[result][1]
[1]: https://i.stack.imgur.com/IoqA9.png
You created so-called blocking function from EchoClientProtocol.data_received(). Every delivered message from server can be delivered into EchoClientProtocol.data_received() only when the event loop can process it but blocking function prevents it.
This code
while 1: # More Pythonic way is While True
message = input('please input the message:')
self.transport.write(message.encode())
get message from user and send it to the server, until this moment it's all fine. In the next step it starts another loop but the code never get into the event loop (so the incoming message can't be processed).
You can edit the client code like this:
def data_received(self, data):
print('Data received: {!r}'.format(data.decode()))
message = input('please input the message:')
self.transport.write(message.encode())
The data_received in client is first called when you received Hello World! from server (it's the Hello World! sends from connection_made). Now the processing is following:
It prints received message (in the first call it's Hello World!)
Get new message from user
Send it to the server
The function returns and the control is given to the event loop.
The server received new message and send it back to client
The event loop on client call data_received
Go to the step 1
Related
I've developed a pattern to use for a commanding a python daemon through cmd module shell using an eventloop. However, its not ready yet because I can't figure out how to gracefully exit the two applications (I'm still learning asyncio and can't figure out the following problem). When the cmd module is commanded to exit I get:
(Cmd) exit
Shutting down client...
Traceback (most recent call last):
File "client_loop.py", line 10, in <module>
loop.run_until_complete(test.cmdloop())
File "...\asyncio\base_events.py", line 467, in run_until_complete
future = tasks.ensure_future(future, loop=self)
File "...\lib\asyncio\tasks.py", line 526, in ensure_future
raise TypeError('An asyncio.Future, a coroutine or an awaitable is '
TypeError: An asyncio.Future, a coroutine or an awaitable is required
I'm not good with asyncio yet, what am I doing wrong? Sorry for the long question but the files/errors make it long and hopefully makes it easier to debug.
Here are the supporting files:
shell.py
# implementation of the (Cmd) prompt with history functionality
# standard imports
import cmd as cmd
class Shell(cmd.Cmd):
def __init__(self, **kwargs):
cmd.Cmd.__init__(self, **kwargs)
self.eventloop = None
self.shutdown_client = None
self.tcp_echo_client = None
def set_eventloop(self, loop):
self.eventloop = loop
def set_funcs(self, tcp_echo_client, shutdown_client):
self.tcp_echo_client = tcp_echo_client
self.shutdown_client = shutdown_client
def do_exit(self,*args):
"""
Exits the shell gracefully
:param args:
:return:
"""
print('Shutting down client...')
self.shutdown_client(self.eventloop)
return True
def default(self, line):
try:
self.eventloop.run_until_complete(self.tcp_echo_client(line, self.eventloop))
except SystemExit:
pass
server.py
# server logic to parse arguments coming over the TCP socket and echo it back
# standard imports
import asyncio
async def handle_echo(reader, writer):
data = await reader.read(100)
message = data.decode()
addr = writer.get_extra_info('peername')
print("Received %r from %r" % (message, addr))
print("Send: %r" % message)
writer.write(data)
await writer.drain()
print("Close the client socket")
writer.close()
loop = asyncio.get_event_loop()
coro = asyncio.start_server(handle_echo, '127.0.0.1', 8888, loop=loop)
server = loop.run_until_complete(coro)
# Serve requests until Ctrl+C is pressed
print('Serving on {}'.format(server.sockets[0].getsockname()))
try:
loop.run_forever()
except KeyboardInterrupt:
pass
finally:
# Close the server
for task in asyncio.Task.all_tasks():
loop.run_until_complete(task)
server.close()
loop.run_until_complete(server.wait_closed())
loop.stop()
loop.close()
exit(0)
client.py
# client functions to send message over TCP and process response
# standard imports
import asyncio
# user imports
import shell
async def tcp_echo_client(message, loop):
reader, writer = await asyncio.open_connection('127.0.0.1', 8888,
loop=loop)
print('Send: %r' % message)
writer.write(message.encode())
data = await reader.read(100)
print('Received: %r' % data.decode())
print('Close the socket')
writer.close()
def shutdown_client(loop):
loop.stop()
# Find all running tasks:
pending = asyncio.Task.all_tasks()
# Run loop until tasks done:
loop.run_until_complete(asyncio.gather(*pending))
loop = asyncio.get_event_loop()
test = shell.Shell()
test.set_eventloop(loop)
test.set_funcs(tcp_echo_client, shutdown_client)
loop.run_until_complete(test.cmdloop())
loop.close()
The problem lies in the fact that cmd doesn't require asyncio to process input from the user and send a message to through the TCP/IP socket. Simply removing asyncio from the client side solved the problem. It still offers the shell implementation and the client-server pattern. Here is the new code:
server.py
# server logic to parse arguments coming over the TCP socket and echo it back
# standard imports
import asyncio
async def handle_echo(reader, writer):
data = await reader.read(100)
message = data.decode()
addr = writer.get_extra_info('peername')
print("Received %r from %r" % (message, addr))
print("Send: %r" % message)
writer.write(data)
await writer.drain()
print("Close the client socket")
writer.close()
loop = asyncio.get_event_loop()
coro = asyncio.start_server(handle_echo, '127.0.0.1', 8888, loop=loop)
server = loop.run_until_complete(coro)
# Serve requests until Ctrl+C is pressed
print('Serving on {}'.format(server.sockets[0].getsockname()))
try:
loop.run_forever()
except KeyboardInterrupt:
pass
finally:
# Close the server
for task in asyncio.Task.all_tasks():
loop.run_until_complete(task)
server.close()
loop.run_until_complete(server.wait_closed())
loop.stop()
loop.close()
exit(0)
client_shell.py
# implementation of a shell prompt (using Cmd module) to send message over TCP and process response
# standard imports
import socket
import cmd as cmd
class Shell(cmd.Cmd):
def __init__(self, **kwargs):
cmd.Cmd.__init__(self, **kwargs)
def do_exit(self,*args):
"""
Exits the shell gracefully
:param args:
:return:
"""
print('Shutting down client...')
return True
def default(self, line):
try:
self._tcp_echo_client(line.encode())
except SystemExit:
pass
def _tcp_echo_client(self, message):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
print('Send: %r' % message)
s.connect(('127.0.0.1', 8888))
s.sendall(message)
data = s.recv(1000)
print('Received: %r' % data.decode())
print('Close the socket')
if __name__ == '__main__':
Shell().cmdloop()
so i am making a chatroom in python using sockets for practice. I have made the server code using threading so that i can have more clients. Ive also made the client code, and when i try to run two clients at once so that they message from one to another, they connect to server, but the server doesnt seem to be receiving the message sent from either of the clients.
SERVER CODE:
import select
from threading import *
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# takes the first argument from command prompt as IP address
IP_address = "127.0.0.1"
# takes second argument from command prompt as port number
Port = int("50204")
server.bind((IP_address, Port))
server.listen(1000)
list_of_clients = []
def clientthread(conn, addr):
# sends a message to the client whose user object is conn
conn.send("Welcome to this chatroom!")
while True:
try:
message = conn.recv(4096)
if message:
print("<" + addr[0] + "> " + message.decode("UTF-8"))
# Calls broadcast function to send message to all
message_to_send = "<" + addr[0] + "> " + message
broadcast(message_to_send.encode("UTF-8"), conn)
else:
remove(conn)
except:
continue
def broadcast(message, connection):
for clients in list_of_clients:
if clients != connection:
try:
clients.send(message)
except:
clients.close()
# if the link is broken, we remove the client
remove(clients)
def remove(connection):
if connection in list_of_clients:
list_of_clients.remove(connection)
while True:
conn, addr = server.accept()
list_of_clients.append(conn)
# prints the address of the user that just connected
print(addr[0] + " connected")
# creates and individual thread for every user
# that connects
Thread(target=clientthread, args=(conn, addr))
conn.close()
server.close()
CLIENT CODE:
import socket
import sys
import time
class client:
def __init__(self):
self.server_ip = "127.0.0.1"
self.port = 50204
self.s = self.connect()
def connect(self):
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error:
print("Failed to create socket.")
sys.exit()
print("Socket created")
try:
s.connect((self.server_ip, self.port))
except socket.error:
print("Failed to connect to ip " + self.server_ip)
print("Connected to: " + str(s.getsockname()))
return s
def SocketQuery(self, Sock, cmd):
try:
try:
# Send cmd string
Sock.send(cmd)
print("Sent!")
time.sleep(1)
except socket.error:
# Send failed
print("Send failed!")
sys.exit()
reply = Sock.recv(4096)
return reply
except ConnectionResetError:
print("Server is down!")
def SocketClose(self, Sock):
# close the socket
Sock.close()
time.sleep(.300)
if __name__ == "__main__":
c = client()
c.connect()
print("connected")
while True:
inp = input(">>> ")
if inp == ":q":
break
reply = c.SocketQuery(c.s, inp.encode("UTF-8"))
if reply:
print(reply.decode("UTF-8"))
c.SocketClose(c.s)
So as i have already mentioned, they do connect, but dont send/receive messages.
i have checked the value in conn.recv(), and it is the same, also everything gets encoded to UTF-8 before sent, and then decoded back. I cant seem to find any other problem except that im running them all on localhost.
If anyone knows the answer to this, please tell me.
cheers!
I want to add a timeout for my 0MQ client.
I tried zmq.Poller(). It seems to work at the beginning. But when I move code into a function, I find it doesn't return anything. It just stuck there.
I have two print lines.
First print:
I print the result zmq_Response successfully before this function returns. But when it comes to the next line, nothing returns.
Second print:
I guess that's why my last print does not work.
def send_message():
context = zmq.Context()
zmq_Socket = context.socket(zmq.REQ)
zmq_Socket.connect('tcp://localhost:5000')
zmq_Data = {'Register': 'default'}
zmq_Socket.send_string(json.dumps(zmq_Data), flags=0, encoding='utf8')
poller = zmq.Poller()
poller.register(zmq_Socket, flags=zmq.POLLIN)
if poller.poll(timeout=1000):
zmq_Response = zmq_Socket.recv_json()
else:
# raise IOError("Timeout processing auth request")
zmq_Response = {'test': 'test'}
poller.unregister(zmq_Socket)
print(zmq_Response) # **This print works!**
return zmq_Response
res = send_message()
print(res)
It is expected to print zmq_Response but it does not.
I solve it now...
It seems that when the value of zmq_LINGER is the default value, which is -1, context will wait until messages have been sent successfully before allowing termination.
So I set zmq_LINGER to 1 at timeout branch.
It works for now.
def send_message():
context = zmq.Context()
zmq_Socket = context.socket(zmq.REQ)
zmq_Socket.connect('tcp://localhost:5000')
zmq_Data = {'Register': 'default'}
zmq_Socket.send_string(json.dumps(zmq_Data), flags=0, encoding='utf8')
poller = zmq.Poller()
poller.register(zmq_Socket, flags=zmq.POLLIN)
if poller.poll(timeout=1000):
zmq_Response = zmq_Socket.recv_json()
else:
# --------------------------------------------
# I change the value of zmq.LINGER here.
zmq_Socket.setsockopt(zmq.LINGER, 1)
# --------------------------------------------
zmq_Response = {'test': 'test'}
poller.unregister(zmq_Socket)
print(zmq_Response)
return zmq_Response
res = send_message()
print(res)
I have implemented zmq.poller() for timeout functionality with zmq.REQ and zmq.REP socket to handle deadlock. Have a look at the code.
For more explanation check out my repo
Client Code
#author: nitinashu1995#gmail.com
#client.py
import zmq
context = zmq.Context()
# Socket to talk to server
print("Connecting to hello world server…")
socket = context.socket(zmq.REQ)
socket.connect("tcp://localhost:5555")
socket.setsockopt(zmq.LINGER, 0)
# use poll for timeouts:
poller = zmq.Poller()
poller.register(socket, zmq.POLLIN)
# Do 10 requests, waiting each time for a response
for request in range(10):
print("Sending request %s …" % request)
socket.send(b"Hello")
'''
We have set response timeout of 6 sec.
'''
if poller.poll(6*1000):
message = socket.recv()
print("Received reply %s [ %s ]" % (request, message))
else:
print("Timeout processing auth request {}".format(request))
print("Terminating socket for old request {}".format(request))
socket.close()
context.term()
context = zmq.Context()
socket = context.socket(zmq.REQ)
socket.connect("tcp://localhost:5555")
socket.setsockopt(zmq.LINGER, 0)
poller.register(socket, zmq.POLLIN)
print("socket has been re-registered for request {}".format(request+1))
Server Code
#server.py
import time
import zmq
context = zmq.Context()
#socket = context.socket(zmq.PULL)
socket = context.socket(zmq.REP)
socket.bind("tcp://*:5555")
#socket.RCVTIMEO = 6000
i = 0
while True:
# Wait for next request from client
message = socket.recv()
print("Received request: %s" % message)
#Get the reply.
time.sleep(i)
i+=1
# Send reply back to client
socket.send(b"World")
I'm trying a example to create a simple socket server, I need to receive multiline data from clients so this is my code for the socket server:
import socket
import sys
host = 'localhost'
port = 5006
c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
c.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
c.bind((host, port))
c.listen(1)
while True:
try:
print("1")
csock, caddr = c.accept()
print("2")
with csock.makefile('rw', 2**16) as cfile:
print("3")
print(cfile.readline()) // When I use readline, it goes ok, but only get the first line, I need every line from data sent by client
print("4")
cfile.close()
print("5")
print("5.5")
csock.sendall("OK".encode('UTF-8'))
print("6")
csock.close()
print("7")
except KeyboardInterrupt:
print("Keyboard exit")
if 'csock' in locals():
csock.close()
sys.exit()
except Exception as e:
print(e)
Now when I use readlines(), my program just stuck and "does nothing" after print("3")
I tried with read() too, but still stuck, keep waiting both client and server
This is the code I'm using for client:
import socket
def query(host, port):
msg = \
'MSH|^~\&|REC APP|REC FAC|SEND APP|SEND FAC|20110708163513||QBP^Q22^QBP_Q21|111069|D|2.5|||||ITA||EN\r' \
'QPD|IHE PDQ Query|111069|#PID.5.2^SMITH||||\r' \
'RCP|I|'
# establish the connection
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.connect((host, port))
# send the message
sock.sendall(msg.encode('UTF-8'))
# receive the answer
received = sock.recv(1024*1024)
return received
finally:
sock.close()
if __name__ == '__main__':
res = query('localhost', 5006)
print("Received response: ")
print(repr(res))
When I use readlines() and stop client after executing, server prints full message sent, I'm confused
I'm learning python 3 and is my first language, so sorry if it's a silly question, but I cant't find out why it doesn't work...
I'm testing a simple echo client/server application. According to my book, I first created a file named tincanchat:
import socket
HOST = ''
PORT = 4040
def create_listen_socket(host, port):
""" Setup the sockets our server will receive connection
requests on """
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((host, port))
sock.listen(100)
return sock
def recv_msg(sock):
""" Wait for data to arrive on the socket, then parse into
messages using b'\0' as message delimiter """
data = bytearray()
msg = ''
# Repeatedly read 4096 bytes off the socket, storing the bytes
# in data until we see a delimiter
while not msg:
recvd = sock.recv(4096)
if not recvd:
# Socket has been closed prematurely
raise ConnectionError()
data = data + recvd
if b'\0' in recvd:
# we know from our protocol rules that we only send
# one message per connection, so b'\0' will always be
# the last character
msg = data.rstrip(b'\0')
msg = msg.decode('utf-8')
return msg
def prep_msg(msg):
""" Prepare a string to be sent as a message """
msg += '\0'
return msg.encode('utf-8')
def send_msg(sock, msg):
""" Send a string over a socket, preparing it first """
data = prep_msg(msg)
sock.sendall(data)
Then, I wrote the server:
import tincanchat
HOST = tincanchat.HOST
PORT = tincanchat.PORT
def handle_client(sock, addr):
""" Receive data from the client via sock and echo it back """
try:
msg = tincanchat.recv_msg(sock) # Blocks until received
# complete message
print('{}: {}'.format(addr, msg))
tincanchat.send_msg(sock, msg) # Blocks until sent
except (ConnectionError, BrokenPipeError):
print('Socket error')
finally:
print('Closed connection to {}'.format(addr))
sock.close()
if __name__ == '__main__':
listen_sock = tincanchat.create_listen_socket(HOST, PORT)
addr = listen_sock.getsockname()
print('Listening on {}'.format(addr))
while True:
client_sock, addr = listen_sock.accept()
print('Connection from {}'.format(addr))
handle_client(client_sock, addr)
And the client:
import sys, socket
import tincanchat
HOST = sys.argv[-1] if len(sys.argv) > 1 else '127.0.0.1'
PORT = tincanchat.PORT
if __name__ == '__main__':
while True:
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST, PORT))
print('\nConnected to {}:{}'.format(HOST, PORT))
print("Type message, enter to send, 'q' to quit")
msg = input()
if msg == 'q': break
tincanchat.send_msg(sock, msg) # Blocks until sent
print('Sent message: {}'.format(msg))
msg = tincanchat.recv_msg(sock) # Block until
# received complete
# message
print('Received echo: ' + msg)
except ConnectionError:
print('Socket error')
break
finally:
sock.close()
print('Closed connection to server\n')
I run the server, then the client, which connects with the server and asks for input. At this point, it returns this error:
Connected to 127.0.0.1:4040
Type message, enter to send, 'q' to quit
Hello
Closed connection to server
Traceback (most recent call last):
File "C:\xxxxxxxxx\1.2-echo_client-uni.py", line 22, in <module>
except ConnectionError:
NameError: name 'ConnectionError' is not defined
Where is the problem?
Thanks in advance :)
If u want to catch the specified Errors or Exceptions, U should import them first.
What you could do for for example is:
from requests.exceptions import ConnectionError
try:
r = requests.get("http://example.com", timeout=0.001)
except ConnectionError as e: # This is the correct syntax
print e
r = "No response"
In this case your program will not return 'NameError'