Implement chat room program based on python
- 2020-11-25 07:20:03
- OfStack
Example of this article for you to share python implementation of simple chat room specific code, for your reference, the specific content is as follows
Just contact python programming, and from contact java 1 directly interested in socket module, so I made a chat room of the small program.
The program consists of the client and the server, using UDP service. The server side binds the local IP and port, and the client side chooses the port randomly by the system.
Realized the mass, private, point - to - point file transfer function.
The client built a class to inherit the Cmd module, used the custom command command to operate, and called the corresponding do_command method.
json module is used to encapsulate and serialize messages and parse them at the receiver.
The client code is as follows:
import socket
import threading
import json
import os
from cmd import Cmd
class Client(Cmd):
"""
The client
"""
prompt = '>>>'
intro = '[Welcome] Simple chat room client (Cli version )\n' + '[Welcome] The input help To get help \n'
buffersize = 1024
def __init__(self, host):
"""
structure
"""
super().__init__()
self.__socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# self.__id = None
self.__nickname = None
self.__host = host
self.thread_recv = None
self.threadisalive = False
# Whether to receive a file
self.recvfile = False
# Whether you are sending a file
self.sendfile = False
self.filesize = None
self.sendfilesize = None
# Receive file package count
self.filecount = None
# Receive file name
self.filename = None
# Send file name
self.sendfilename = None
# The sender
self.filefrom = None
# The receiver
self.fileto = None
# Receive file stream
self.file_recv = None
# Send file stream
self.file_send = None
# Receiving file address
self.filefrom_addr = None
# Send file address
self.fileto_addr = None
def __receive_message_thread(self):
"""
Message receiving thread
"""
while self.threadisalive:
# noinspection PyBroadException
try:
buffer, addr = self.__socket.recvfrom(1024)
'''
The file flow is sent directly by the sending end without passing through the server, so when the message is sent by the sending end, the received data is stored in the file
'''
if (addr != self.__host) & (addr == self.filefrom_addr) & self.recvfile:
self.file_recv.write(buffer)
self.filecount += 1
if self.filecount * 1024 >= self.filesize:
self.file_recv.close()
print(self.filename, 'is received.')
self.recvfile = False
continue
js = json.loads(buffer.decode())
# Displays if the received data is message information
if js['type'] == 'message':
print(js['message'])
# If the received data is a file send request, the file information is stored and displayed
elif js['type'] == 'filequest':
if self.recvfile:
self.__socket.sendto(json.dumps({
'type': 'fileres',
'fileres': 'no',
'nickname': self.__nickname,
'who': js['nickname'],
'errormessage': 'is transfroming files.',
}).encode(), self.__host)
continue
filename = js['filename']
who = js['nickname']
filesize = js['filesize']
self.recvfile = True
self.filesize = filesize
self.filename = filename
self.filecount = 0
self.filefrom = who
self.filefrom_addr = (js['send_ip'], js['send_port'])
print('[system]:', who, ' send a file(',
filename, ') to you. receive? ')
# The data received is the request reply, and if agreed to receive, the address of the recipient sent from the server is stored and the sending thread is opened
elif js['type'] == 'fileres':
if js['fileres'] == 'yes':
print(js['recv_ip'], js['recv_port'])
self.fileto_addr = (js['recv_ip'], js['recv_port'])
thread = threading.Thread(
target=self.__send_file_thread)
thread.start()
else:
print(js['nickname'], js['errormessage'])
self.sendfile = False
except Exception as e:
print(e)
print('[Client] Unable to retrieve data from server ')
def __send_broadcast_message_thread(self, message):
"""
Send a broadcast message thread
:param message: The message content
"""
self.__socket.sendto(json.dumps({
'type': 'broadcast',
'nickname': self.__nickname,
'message': message,
}).encode(), self.__host)
def __send_file_thread(self):
"""
Sending file thread
:param message: The message content
"""
filecount = 0
print('[system]', 'sending the file...')
while filecount * 1024 <= self.sendfilesize:
self.__socket.sendto(
self.file_send.read(1024), self.fileto_addr)
filecount += 1
self.file_send.close()
self.sendfile = False
print('[system]', 'the file is sended.')
def __send_whisper_message_thread(self, who, message):
"""
The sending private message thread
:param message: The message content
"""
self.__socket.sendto(json.dumps({
'type': 'sendto',
'who': who,
'nickname': self.__nickname,
'message': message
}).encode(), self.__host)
def send_exit(self):
self.__socket.sendto(json.dumps({
'type': 'offline',
'nickname': self.__nickname,
}).encode(), self.__host)
def start(self):
"""
Start the client
"""
self.cmdloop()
def do_login(self, args):
"""
Log on to chat room
:param args: parameter
"""
nickname = args.split(' ')[0]
# Sends the nickname to the server to get the user id
self.__socket.sendto(json.dumps({
'type': 'login',
'nickname': nickname,
}).encode(), self.__host)
# Attempt to receive data
buffer = self.__socket.recvfrom(1300)[0].decode()
obj = json.loads(buffer)
if obj['login'] == 'success':
self.__nickname = nickname
print('[Client] Login to chat room successfully ')
self.threadisalive = True
# Open child threads to receive data
self.thread_recv = threading.Thread(
target=self.__receive_message_thread)
self.thread_recv.setDaemon(True)
self.thread_recv.start()
else:
print('[Client] Unable to log into the chat room ', obj['errormessage'])
def do_send(self, args):
"""
Send a message
:param args: parameter
"""
if self.__nickname is None:
print(' Please log in first! login nickname')
return
message = args
# The child thread is opened for sending data
thread = threading.Thread(
target=self.__send_broadcast_message_thread, args=(message, ))
thread.setDaemon(True)
thread.start()
def do_sendto(self, args):
"""
Send private messages
:param args: parameter
"""
if self.__nickname is None:
print(' Please log in first! login nickname')
return
who = args.split(' ')[0]
message = args.split(' ')[1]
# # Displays the messages you sent
# print('[' + str(self.__nickname) + '(' + str(self.__id) + ')' + ']', message)
# The child thread is opened for sending data
thread = threading.Thread(
target=self.__send_whisper_message_thread, args=(who, message))
thread.setDaemon(True)
thread.start()
def do_catusers(self, arg):
if self.__nickname is None:
print(' Please log in first! login nickname')
return
catmessage = json.dumps({'type': 'catusers'})
self.__socket.sendto(catmessage.encode(), self.__host)
def do_catip(self, args):
if self.__nickname is None:
print(' Please log in first! login nickname')
return
who = args
catipmessage = json.dumps({'type': 'catip', 'who': who})
self.__socket.sendto(catipmessage.encode(), self.__host)
def do_help(self, arg):
"""
help
:param arg: parameter
"""
command = arg.split(' ')[0]
if command == '':
print('[Help] login nickname - Log in to the chat room, nickname Is the nickname you choose ')
print('[Help] send message - Send a message, message It's the message that you entered ')
print('[Help] sendto who message - Private messaging, who It's the user name, message It's the message that you entered ')
print('[Help] catusers - View all users ')
print('[Help] catip who - To view the user IP . who To the user name ')
print('[Help] sendfile who filedir - Send a file to a user, who Is the user name, filedir Is the file path ')
print('[Help] getfile filename who yes/no - To receive files, filename For the file name ,who For the sender, yes/no To receive or not to receive ')
elif command == 'login':
print('[Help] login nickname - Log in to the chat room, nickname Is the nickname you choose ')
elif command == 'send':
print('[Help] send message - Send a message, message It's the message that you entered ')
elif command == 'sendto':
print('[Help] sendto who message - Sending private messages, message It's the message that you entered ')
else:
print('[Help] No instructions were queried for what you want to know ')
def do_exit(self, arg): # In order to do_* Begins with a command
print("Exit")
self.send_exit()
try:
self.threadisalive = False
self.thread_recv.join()
except Exception as e:
print(e)
# self.__socket.close()
def do_sendfile(self, args):
who = args.split(' ')[0]
filepath = args.split(' ')[1]
filename = filepath.split('\\')[-1]
# Determine if a file is being sent
if self.sendfile:
print('you are sending files, please try later.')
return
if not os.path.exists(filepath):
print('the file is not exist.')
return
filesize = os.path.getsize(filepath)
# print(who, filename, filesize)
self.sendfile = True
self.fileto = who
self.sendfilename = filename
self.sendfilesize = filesize
self.file_send = open(filepath, 'rb')
self.__socket.sendto(json.dumps({
'type': 'filequest',
'nickname': self.__nickname,
'filename': self.sendfilename,
'filesize': self.sendfilesize,
'who': self.fileto,
'send_ip': '',
'send_port': '',
}).encode(), self.__host)
print('request send...')
# fileres = self.__socket.recvfrom(1024)[0].decode()
# js = json.loads(fileres)
def do_getfile(self, args):
filename = args.split(' ')[0]
who = args.split(' ')[1]
ch = args.split(' ')[2]
# print(self.filename is not None, filename, self.filename, who, self.filefrom)
if (self.filename is not None) & (filename == self.filename) & (who == self.filefrom):
if ch == 'yes':
self.file_recv = open(self.filename, 'wb')
self.__socket.sendto(json.dumps({
'type': 'fileres',
'fileres': 'yes',
'nickname': self.__nickname,
'who': who,
'recv_ip': '',
'recv_port': '',
}).encode(), self.__host)
print('you agree to reveive the file(', filename, ') from', who)
else:
self.__socket.sendto(json.dumps({
'type': 'fileres',
'fileres': 'no',
'nickname': self.__nickname,
'errormessage': 'deny the file.',
'who': who,
'recv_ip': '',
'recv_port': '',
}).encode(), self.__host)
print('you deny to reveive the file(', filename, ') from', who)
self.recvfile = False
else:
print('the name or sender of the file is wrong.')
c = Client(('127.0.0.1', 12346))
c.start()
The server side mainly carries on the classified forwarding processing of the message and the maintenance of the user list and address list.
The server-side code is as follows:
import socket
import json
obj = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
obj.bind(('127.0.0.1', 12346))
conn_list = []
user_list = []
while True:
try:
receive_data, client_address = obj.recvfrom(1024)
js = json.loads(receive_data.decode())
# The login information
if js['type'] == 'login':
nickname = str(js['nickname'])
if nickname in user_list:
obj.sendto(json.dumps({'login': 'fail',
'errormessage': 'the nickname is exists'}).encode(),
client_address)
else:
# Send notifications to other users
for i in range(len(conn_list)):
obj.sendto(json.dumps(
{
'type': 'message',
'message': '[system]' + nickname + ' Is logged in .'
}).encode(), conn_list[i])
user_list.append(nickname)
conn_list.append(client_address)
print(nickname, client_address, ' Login successful! ')
obj.sendto(json.dumps({'login': 'success',
'nickname': nickname}).encode(), client_address)
# Group-sent message
elif js['type'] == 'broadcast':
message = js['message']
nickname = js['nickname']
for i in range(len(conn_list)):
obj.sendto(json.dumps(
{
'type': 'message',
'message': nickname + ':' + message
}).encode(), conn_list[i])
# Private message
elif js['type'] == 'sendto':
who = js['who']
nickname = js['nickname']
message = js['message']
# Check if the user exists
if who not in user_list:
obj.sendto(json.dumps(
{
'type': 'message',
'message': who + ' not exist or not online.please try later.'
}).encode(),
client_address)
else:
obj.sendto(json.dumps(
{
'type': 'message',
'message': nickname + ' whisper to you: ' + message
}).encode(),
conn_list[user_list.index(who)])
# View user list
elif js['type'] == 'catusers':
users = json.dumps(user_list)
obj.sendto(json.dumps(
{
'type': 'message',
'message': users,
}).encode(),
client_address)
# To view the user IP
elif js['type'] == 'catip':
who = js['who']
if who not in user_list:
obj.sendto(json.dumps(
{
'type': 'message',
'message': who + ' not exist or not online.please try later.'
}).encode(),
client_address)
else:
addr = json.dumps(conn_list[user_list.index(who)])
obj.sendto(json.dumps(
{
'type': 'message',
'message': addr,
}).encode(),
client_address)
# Offline message
elif js['type'] == 'offline':
user_list.remove(js['nickname'])
conn_list.remove(client_address)
obj.sendto(
(js['nickname'] + 'offline.').encode(),
client_address)
# Send notifications to other users
for i in range(len(conn_list)):
obj.sendto(json.dumps(
{
'type': 'message',
'message': '[system]' + nickname + ' Get offline .'
}).encode(), conn_list[i])
# Send file request
elif js['type'] == 'filequest':
who = js['who']
if who not in user_list:
obj.sendto(json.dumps(
{
'type': 'message',
'message': who + ' not exist or not online.please try later.'
}).encode(),
client_address)
else:
js['send_ip'] = client_address[0]
js['send_port'] = client_address[1]
obj.sendto(json.dumps(js).encode(),
conn_list[user_list.index(who)])
print(js['nickname'], 'request to send file to', who)
# Send file for reply
elif js['type'] == 'fileres':
who = js['who']
if js['fileres'] == 'yes':
js['recv_ip'] = client_address[0]
js['recv_port'] = client_address[1]
print(js['nickname'], 'agree to receive file from', js['who'])
else:
print(js['nickname'], 'deny to receive file from', js['who'])
obj.sendto(json.dumps(js).encode(),
conn_list[user_list.index(who)])
except Exception as e:
print(e)