python实现聊天室功能

快过年了,我这颗躁动的心啊,根本集中不了精神来详细整理博客了,所以干脆直接贴上代码来,等年后我会详细介绍每一步实现方法。给代码加上详细注释的,大家见谅啊~~~

聊天室程序需求:

我们要实现的是简单的聊天室的例子,就是允许多个人同时一起聊天,每个人发送的消息所有人都能接收到,类似于 QQ 群的功能,而不是点对点的 QQ 好友之间的聊天。如下图:

这里写图片描述

这里我们首先要知道《python网络编程》知识,其中要明白什么是Socket以及如何使用Socket 实现不同主机间的通信。具体内容大家可以参考Python Socket网络编程

OK,我这里直接上TCP版本的server.py和client.py文件
运行时分别运行server.py和client.py文件即可,或者在编译器上直接运行,效果图在文章末尾。

server.py
# -*- encoding:utf-8 -*-
# socket.getaddrinfo(host,  port, family=0, socktype=0, proto=0, flags=0)
# 根据给定的参数host/port,相应的转换成一个包含用于创建socket对象的五元组,
# 参数host为域名,以字符串形式给出代表一个IPV4/IPV6地址或者None.
# 参数port如果字符串形式就代表一个服务名,比如“http”"ftp""email"等,或者为数字,或者为None
# 参数family为地主族,可以为AF_INET  ,AF_INET6 ,AF_UNIX.
# 参数socktype可以为SOCK_STREAM(TCP)或者SOCK_DGRAM(UDP)
# 参数proto通常为0可以直接忽略
# 参数flags为AI_*的组合,比如AI_NUMERICHOST,它会影响函数的返回值
# 附注:给参数host,port传递None时建立在C基础,通过传递NULL。
# 该函数返回一个五元组(family, socktype, proto, canonname, sockaddr),同时第五个参数sockaddr也是一个二元组(address, port)
# 更多的方法及链接请访问
# Echo server program

#socket - tcp - server.py(服务端):
from socket import *
import sys
import threading
from time import ctime
from time import localtime
import traceback
import time
import subprocess

reload(sys)
sys.setdefaultencoding("utf8")

HOST = '127.0.0.1'
PORT = 8555  # 设置侦听端口
BUFSIZ = 1024


class TcpServer():
    def __init__(self):
        self.ADDR = (HOST, PORT)
        try:
            self.sock = socket(AF_INET, SOCK_STREAM)
            print '%d is open' % PORT

            self.sock.bind(self.ADDR)
            self.sock.listen(5)
            # 设置退出条件
            self.STOP_CHAT = False

            # 所有监听的客户端
            self.clients = {}
            self.thrs = {}
            self.stops = []

        except Exception, e:
            print "%d is down" % PORT
            return False

    def IsOpen(ip, port):

        s = socket(AF_INET, SOCK_STREAM)
        try:
            s.connect((ip, int(port)))
            # s.shutdown(2)
            # 利用shutdown()函数使socket双向数据传输变为单向数据传输。shutdown()需要一个单独的参数,
            # 该参数表示s了如何关闭socket。具体为:0表示禁止将来读;1表示禁止将来写;2表示禁止将来读和写。
            print '%d is open' % port
            return True
        except:
            print '%d is down' % port
            return False

    def listen_client(self):
        while not self.STOP_CHAT:
            print(u'等待接入,侦听端口:%d' % (PORT))
            self.tcpClientSock, self.addr = self.sock.accept()
            print(u'接受连接,客户端地址:', self.addr)
            address = self.addr
            # 将建立的client socket链接放到列表self.clients中
            self.clients[address] = self.tcpClientSock
            # 分别将每个建立的链接放入进程中,接收且分发消息
            self.thrs[address] = threading.Thread(target=self.readmsg, args=[address])
            self.thrs[address].start()
            time.sleep(0.5)

    def readmsg(self, address):
        # 如果地址不存在,则返回False
        if address not in self.clients:
            return False
        # 得到发送消息的client socket
        client = self.clients[address]
        while True:
            try:
                # 获取到消息内容data
                data = client.recv(BUFSIZ)
            except:
                print error
                self.close_client(address)
                break
            if not data:
                break
            # python3使用bytes,所以要进行编码
            # s='%s发送给我的信息是:[%s] %s' %(addr[0],ctime(), data.decode('utf8'))
            # 对日期进行一下格式化
            ISOTIMEFORMAT = '%Y-%m-%d %X'
            stime = time.strftime(ISOTIMEFORMAT, localtime())
            s = u'%s发送给我的信息是:%s' % (str(address), data.decode('utf8'))
            # 将获得的消息分发给链接中的client socket
            for k in self.clients:
                self.clients[k].send(s.encode('utf8'))
                self.clients[k].sendall('sendall:' + s.encode('utf8'))
                print str(k)
            print [stime], ':', data.decode('utf8')
            # 如果输入quit(忽略大小写),则程序退出
            STOP_CHAT = (data.decode('utf8').upper() == "QUIT")
            if STOP_CHAT:
                print "quit"
                self.close_client(address)
                print "already quit"
                break

    def close_client(self, address):
        try:
            client = self.clients.pop(address)
            self.stops.append(address)
            client.close()
            for k in self.clients:
                self.clients[k].send(str(address) + u"已经离开了")
        except:
            pass
        print str(address) + u'已经退出'


if __name__ == '__main__':
    tserver = TcpServer()
    tserver.listen_client()
client.py
# -*- encoding:utf-8 -*-
from socket import *
import sys
import threading
import time
#socket - tcp - client.py (客户端):
reload(sys)
sys.setdefaultencoding("utf8")

# 测试,连接本机
HOST = '127.0.0.1'
# 设置侦听端口
PORT = 8555
BUFSIZ = 1024


class TcpClient:
    ADDR = (HOST, PORT)

    def __init__(self):
        self.HOST = HOST
        self.PORT = PORT
        self.BUFSIZ = BUFSIZ
        # 创建socket连接
        self.client = socket(AF_INET, SOCK_STREAM)
        self.client.connect(self.ADDR)
        # 起一个线程,监听接收的信息
        self.trecv = threading.Thread(target=self.recvmsg)
        self.trecv.start()

    def sendmsg(self):
        # 循环发送聊天消息,如果socket连接存在则一直循环,发送quit时关闭链接
        while self.client.connect_ex(self.ADDR):
            data = raw_input('>:')
            if not data:
                break
            self.client.send(data.encode('utf8'))
            print(u'发送信息到%s:%s' % (self.HOST, data))
            if data.upper() == "QUIT":
                self.client.close()
                print u"已关闭"
                break

    def recvmsg(self):
        # 接收消息,如果链接一直存在,则持续监听接收消息
        try:
            while self.client.connect_ex(self.ADDR):
                data = self.client.recv(self.BUFSIZ)
                print(u'从%s收到信息:%s' % (self.HOST, data.decode('utf8')))
        except Exception, e:
            print str(e)


if __name__ == '__main__':
    client = TcpClient()
    client.sendmsg()

结果展示:
我运行了两次client.py文件,表示我有两个用户进行通信,服务器会接收到两个用户发送的消息。

server.py

这里写图片描述

client.py

第一个用户首先与服务器连接

这里写图片描述

第二个用户也进来了,现在两个用户之间可以相互发送消息了

这里写图片描述

  • 2
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
以下是一个基于 Python 的多人聊天的示例代码,包括了用户名和密码验证、私聊功能、禁言和踢出用户功能、历史记录功能、表情符号和图片功能功能。 服务器端代码: ```python import socket import threading import os import pickle class User: def __init__(self, username, password): self.username = username self.password = password self.socket = None self.address = None self.muted = False class ChatRoom: def __init__(self): self.users = [] self.history = [] def add_user(self, user): self.users.append(user) def remove_user(self, user): self.users.remove(user) def broadcast(self, message, sender=None): for user in self.users: if user != sender and not user.muted: user.socket.send(message) def send_to_user(self, message, username): for user in self.users: if user.username == username: user.socket.send(message) break def save_history(self, message): self.history.append(message) if len(self.history) > 100: self.history = self.history[-100:] def send_history(self, user): for message in self.history: user.socket.send(message) def handle_client(client_socket, address): username = None chat_room.send_history(user) while True: try: data = client_socket.recv(1024) if not data: break message = data.decode().strip() if not username: if message.startswith('login '): username, password = message[6:].split() for user in chat_room.users: if user.username == username and user.password == password: user.socket = client_socket user.address = address chat_room.broadcast(f'{username} has joined the chat room.\n') chat_room.add_user(user) chat_room.send_history(user) break else: client_socket.send(b'Invalid username or password.\n') else: client_socket.send(b'Please log in first.\n') else: if message.startswith('logout'): client_socket.send(b'Bye.\n') break elif message.startswith('mute'): if username == 'admin': target = message[5:].strip() for user in chat_room.users: if user.username == target: user.muted = True chat_room.send_to_user(f'You have been muted by {username}.\n', target) chat_room.broadcast(f'{target} has been muted by {username}.\n') break else: client_socket.send(f'User {target} not found.\n'.encode()) else: client_socket.send(b'Permission denied.\n') elif message.startswith('unmute'): if username == 'admin': target = message[7:].strip() for user in chat_room.users: if user.username == target: user.muted = False chat_room.send_to_user(f'You have been unmuted by {username}.\n', target) chat_room.broadcast(f'{target} has been unmuted by {username}.\n') break else: client_socket.send(f'User {target} not found.\n'.encode()) else: client_socket.send(b'Permission denied.\n') elif message.startswith('kick'): if username == 'admin': target = message[5:].strip() for user in chat_room.users: if user.username == target: user.socket.send(b'You have been kicked by the admin.\n') user.socket.close() chat_room.remove_user(user) chat_room.broadcast(f'{target} has been kicked by the admin.\n') break else: client_socket.send(f'User {target} not found.\n'.encode()) else: client_socket.send(b'Permission denied.\n') elif message.startswith('sendto'): target, message = message[6:].split(' ', 1) chat_room.send_to_user(f'(private) {username}: {message}\n', target) else: message = f'{username}: {message}\n' chat_room.broadcast(message, sender=username) chat_room.save_history(message) except Exception as e: print(f'Error: {e}') break for user in chat_room.users: if user.socket == client_socket: chat_room.remove_user(user) chat_room.broadcast(f'{user.username} has left the chat room.\n') break client_socket.close() chat_room = ChatRoom() # load users from file if os.path.exists('users.pickle'): with open('users.pickle', 'rb') as f: chat_room.users = pickle.load(f) server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.bind(('localhost', 8888)) server_socket.listen(5) while True: client_socket, address = server_socket.accept() thread = threading.Thread(target=handle_client, args=(client_socket, address)) thread.start() ``` 客户端代码: ```python import socket import threading import getpass import os import time import random def receive(): while True: data = client_socket.recv(1024) if not data: break message = data.decode() print(message, end='') if message.startswith('(private) '): sender = message.split(' ')[1][:-1] print(f'Send a message to {sender}:') def send(): while True: message = input() client_socket.send(message.encode()) def login(): while True: username = input('Username: ') password = getpass.getpass('Password: ') message = f'login {username} {password}' client_socket.send(message.encode()) response = client_socket.recv(1024) if response == b'Invalid username or password.\n': print('Invalid username or password.') else: print('Logged in successfully.') break def menu(): while True: print('Menu:') print('1. Send message') print('2. Private message') print('3. Mute user') print('4. Unmute user') print('5. Kick user') print('6. Logout') choice = input('Choice: ') if choice == '1': message = input('Message: ') client_socket.send(message.encode()) elif choice == '2': target = input('Target: ') message = input('Message: ') client_socket.send(f'sendto {target} {message}'.encode()) elif choice == '3': target = input('Target: ') client_socket.send(f'mute {target}'.encode()) elif choice == '4': target = input('Target: ') client_socket.send(f'unmute {target}'.encode()) elif choice == '5': target = input('Target: ') client_socket.send(f'kick {target}'.encode()) elif choice == '6': client_socket.send(b'logout') break def show_history(): client_socket.send(b'history') data = client_socket.recv(1024) history = data.decode().split('\n')[:-1] for message in history: print(message) def show_emoticons(): emoticons = ['(smile)', '(laugh)', '(wink)', '(sad)', '(angry)', '(shock)', '(love)', '(kiss)', '(heart)'] for i, emoticon in enumerate(emoticons): print(f'{i+1}. {emoticon}', end=' ') if (i+1) % 3 == 0: print() print() while True: choice = input('Choice: ') if choice.isdigit() and int(choice) in range(1, len(emoticons)+1): return emoticons[int(choice)-1] else: print('Invalid choice.') def show_images(): images = ['dog.jpg', 'cat.jpg', 'flower.jpg', 'sunset.jpg', 'waterfall.jpg'] for i, image in enumerate(images): print(f'{i+1}. {image}', end=' ') if (i+1) % 3 == 0: print() print() while True: choice = input('Choice: ') if choice.isdigit() and int(choice) in range(1, len(images)+1): with open(images[int(choice)-1], 'rb') as f: return f.read() else: print('Invalid choice.') client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client_socket.connect(('localhost', 8888)) login() thread_receive = threading.Thread(target=receive) thread_send = threading.Thread(target=send) thread_receive.start() thread_send.start() while True: menu_choice = input('Enter "menu" to show menu: ') if menu_choice == 'menu': menu() elif menu_choice == 'history': show_history() elif menu_choice == 'emoticons': message = show_emoticons() client_socket.send(message.encode()) elif menu_choice == 'image': data = show_images() message = f'{getpass.getuser()} sent an image: {len(data)} bytes\n' client_socket.send(message.encode()) client_socket.send(data) elif menu_choice == 'exit': client_socket.send(b'logout') break client_socket.close() ``` 注意:以上代码示例仅用于演示多人聊天的基本原理和部分功能实现,实际应用中还需要考虑更多的安全性、可扩展性等问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值