Skip to content

Instantly share code, notes, and snippets.

@gregvish gregvish/chat.py
Last active Mar 16, 2019

Embed
What would you like to do?
Python 3.4 asyncio chat server example
from socket import socket, SO_REUSEADDR, SOL_SOCKET
from asyncio import Task, coroutine, get_event_loop
class Peer(object):
def __init__(self, server, sock, name):
self.loop = server.loop
self.name = name
self._sock = sock
self._server = server
Task(self._peer_handler())
def send(self, data):
return self.loop.sock_sendall(self._sock, data.encode('utf8'))
@coroutine
def _peer_handler(self):
try:
yield from self._peer_loop()
except IOError:
pass
finally:
self._server.remove(self)
@coroutine
def _peer_loop(self):
while True:
buf = yield from self.loop.sock_recv(self._sock, 1024)
if buf == b'':
break
self._server.broadcast('%s: %s' % (self.name, buf.decode('utf8')))
class Server(object):
def __init__(self, loop, port):
self.loop = loop
self._serv_sock = socket()
self._serv_sock.setblocking(0)
self._serv_sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
self._serv_sock.bind(('',port))
self._serv_sock.listen(5)
self._peers = []
Task(self._server())
def remove(self, peer):
self._peers.remove(peer)
self.broadcast('Peer %s quit!\n' % (peer.name,))
def broadcast(self, message):
for peer in self._peers:
peer.send(message)
@coroutine
def _server(self):
while True:
peer_sock, peer_name = yield from self.loop.sock_accept(self._serv_sock)
peer_sock.setblocking(0)
peer = Peer(self, peer_sock, peer_name)
self._peers.append(peer)
self.broadcast('Peer %s connected!\n' % (peer.name,))
def main():
loop = get_event_loop()
Server(loop, 1234)
loop.run_forever()
if __name__ == '__main__':
main()
@suchislife801

This comment has been minimized.

Copy link

commented Feb 20, 2014

Hi. I've worked on a chat client for your server. It works so far. Just my 2 cents. Trying to figure out how to prompt the client for a username prior to connecting and having the server use this username instead of ip address and port as it is right now.

from socket import *
from threading import Thread

host = 'localhost'
port = 1234
s = socket(AF_INET, SOCK_STREAM)
s.connect((host, port))

def Listener():
try:
while True:
data = s.recv(1024).decode('utf-8')
print('', data)
except ConnectionAbortedError:
pass

t = Thread(target=Listener)
t.start()

try:
while True:
message = input('')
s.send(message.encode('utf-8'))
except EOFError:
pass
finally:
s.close()

@sneils

This comment has been minimized.

Copy link

commented Apr 9, 2014

asyncio already brings the whole socket stuff with it, so you can cut that out. Plus using the power of the Protocol class does shorten the code (not perfect, just for demonstration purposes):

import asyncio

clients = []

class SimpleChatClientProtocol(asyncio.Protocol):
    def connection_made(self, transport):
        self.transport = transport
        self.peername = transport.get_extra_info("peername")
        print("connection_made: {}".format(self.peername))
        clients.append(self)

    def data_received(self, data):
        print("data_received: {}".format(data.decode()))
        for client in clients:
            if client is not self:
                client.transport.write("{}: {}".format(self.peername, data.decode()).encode())

    def connection_lost(self, ex):
        print("connection_lost: {}".format(self.peername))
        clients.remove(self)

if __name__ == '__main__':
    print("starting up..")

    loop = asyncio.get_event_loop()
    coro = loop.create_server(SimpleChatClientProtocol, port=1234)
    server = loop.run_until_complete(coro)

    for socket in server.sockets:
        print("serving on {}".format(socket.getsockname()))

    loop.run_forever()
@LukeB42

This comment has been minimized.

Copy link

commented Apr 22, 2016

Greg do you mind if this forms the basis of psyrcd-0.21? Project currently lives here: https://github.com/LukeB42/Psyrcd

Cheers

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.