Python聊天室

查看 113|回复 9
作者:Mikepython0721   
Python聊天室2.0隆重推出!!!!
一.前言
12月22日,我提出了一个想法,那就是实现Python聊天室!
一开始我觉得很难,毕竟我从未接接触过用python编写关于网络的东西
于是我就在网上发帖求助,也遇到了许多帮助
时隔(好像是9天吧)我终于做出了一个“残缺”的程序( )
二.整体思路
整体思路是用python的socket模块,与我的服务器进行连接,然后服务端把一个用户发送的内容再发送到每一个用户手上,就实现了群聊。
想要更多思路的可以私信我{:10_281:}
三.程序内容
该程序实现了
  • 群聊
  • 在线列表
  • 登陆验证

    等基本功能
    接下来的版本会实现
  • 数据传输加密
  • 客户端哈希值验证
  • 程序自毁功能
  • 表情包发送
  • 图片发送

    已知问题
  • 当注册不成功时,只能强制退出
  • 待机久了会掉线(我是这样,别人没有遇到)

    这也就当测试版看看吧{:10_256:}
    四.程序运行截图
    五.程序源码
    客户端:
    Mac版:[ol]
  • from tkinter import *
  • from tkinter.font import Font
  • # from tkinter.ttk import *
  • from tkinter import messagebox as mg
  • import time
  • import threading
  • import socket
  • def center_window(root, width, height):
  •     """
  •     窗口居中代码
  •     """
  •     screenwidth = root.winfo_screenwidth()  # 获取显示屏宽度
  •     screenheight = root.winfo_screenheight()  # 获取显示屏高度
  •     size = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)  # 设置窗口居中参数
  •     root.geometry(size)  # 让窗口居中显示
  • def fasong(*args):
  •     time.sleep(0.1)
  •     # re_data = input(">>")
  •     re_data = send_entry.get("1.0", END)[:-1]
  •     if 'exit' == re_data:   # 判断是否退出
  •         client.send(("Q "+ username).encode())  # 发送退出的请求
  •         client.close()
  •     elif (re_data != " \n" and re_data != "\n" and re_data != "" and re_data != " "):    # 判断内容不为空
  •         client.send(("C " + username + ": " + re_data).encode())
  •         time_ = time.strftime('%Y-%m-%d %H:%M:%S')                  # 以下为自己说的话
  •         chat_text.config(state=NORMAL)
  •         f1 = Font(size=10)
  •         chat_text.tag_config("tag_3", font=f1, foreground="grey")
  •         chat_text.insert(END, time_, "tag_3")   # 发送时间
  •         chat_text.insert(END, "\n")
  •         f = Font(size=15)
  •         chat_text.tag_config("tag_41", font=f, foreground="#808080")
  •         chat_text.insert(END, username + ":", "tag_41")    # 发送文本内容
  •         chat_text.insert(END, "\n")
  •         
  •         f = Font(size=14)
  •         chat_text.tag_config("tag_4", font=f, foreground="#2E8B57")
  •         chat_text.insert(END, re_data, "tag_4")    # 发送文本内容
  •         chat_text.insert(END, "\n")
  •         chat_text.config(state=DISABLED)
  •         chat_text.see("end")    # 转到最后一行
  •         # send_entry.first()
  •         # send_entry.delete(0.1,2.0)      # 设置发送为空
  •         # send_entry.insert('1 wordstart' , "s")
  •         # time.sleep(0.1)
  •         send_entry.delete("0.0", END)   # 设置发送为空
  • def fa_(*args):
  •     fasong()
  •     # send_entry.delete("0.0", END)   # 设置发送为空
  •     return 'break'
  • def jieshou():
  •     while True:
  •         # time.sleep(0.3)
  •         try:
  •             data = client.recv(1024)
  •             res = data.decode()
  •             if(res != ''):
  •                 # print("1")
  •                 if (res.split(" ", 2)[0]=="C"): # 如果为聊天的请求
  •                     # print(res.split(" ", 1)[0])
  •                     # print(res.split(" ", 1)[1])
  •                     # print(res)
  •                     time_ = time.strftime('%Y-%m-%d %H:%M:%S')
  •                     chat_text.config(state=NORMAL)
  •                     f1 = Font(size=10)
  •                     chat_text.tag_config("tag_1", font=f1, foreground="grey")   
  •                     chat_text.insert(END, time_, "tag_1")
  •                     chat_text.insert(END, "\n")
  •                     f = Font(size=15)
  •                     chat_text.tag_config("tag", font=f, foreground="#808080")
  •                     chat_text.insert(END, res.split(" ", 2)[1], "tag")
  •                     chat_text.insert(END, "\n")
  •                     
  •                     f = Font(size=14)
  •                     chat_text.tag_config("tag_2", font=f)
  •                     chat_text.insert(END, res.split(" ", 2)[2], "tag_2")
  •                     chat_text.insert(END, "\n")
  •                     chat_text.config(state=DISABLED)
  •                     chat_text.see("end")
  •                 elif(res.split(" ", 1)[0]=="R"):    # 在线用户请求
  •                     afd = False
  •                     print(res.split(" ", 1)[1])
  •                     for kk in range(0, online_user.size()): # 循环判断在线列表里是否有用户名
  •                         if online_user.get(kk) == (res.split(" ", 1)[1]):   # 检测到是
  •                             afd = True  # 判断变量为真
  •                             break   # 退出
  •                     if (afd ==  False): # 如果判断变量为假
  •                         online_user.insert(END,res.split(" ", 1)[1])    # 插入用户名
  •                 elif(res.split(" ", 1)[0]=="E"):    # 退出请求
  •                     for kk in range(0, online_user.size()): # 循环判断要删除的用户名
  •                         if online_user.get(kk) == (res.split(" ", 1)[1]):   
  •                             online_user.delete(kk)  # 从在线列表去除
  •                             break
  •                         
  •         # else:
  •         #     continue
  •         except Exception as e:  
  •             print(e)
  •             print("客户端已退出")
  •             #break
  • def send():
  •     """
  •     发送文字
  •     """
  •     global username
  •     username = username_string.get()    # 用户名变量
  •     # time.sleep(3)
  •     if __name__ == "__main__":
  •         # print("Welcome to Gouzi WD Chat")
  •         # print(username)
  •         #注册业务
  •         while True:
  •             # username=input("请输入用户名")
  •             if ' ' not in username and username != " " and username != "":  # 判断用户名不为空
  •                 client.send(("R "+username + " " + password_string.get()+"\n").encode())   # 发送注册请求
  •                 data=client.recv(2048).decode() # 最大接受字节
  •                 if data=="OK":  # 如果穿回信息为 “OK”
  •                     break
  •             else:
  •                 mg.showerror("", "用户名不能为空,请强制退出后重新进入")    # 用户名如果为空,发出警告
  •                
  •         try:
  •             # 创建一个新的线程
  •             new_thread = threading.Thread(target=jieshou, name="T1")   
  •             # 启动新线程
  •             new_thread.start()
  •             new_thread1 = threading.Thread(target=fasong, name="T2")
  •             # 启动新线程
  •             new_thread1.start()
  •         except:
  •             client.close()
  • def insert_newline(*args):
  •     send_entry.insert("insert", "\n")
  •     return "break"
  • def main():
  •     """
  •     加入聊天后界面
  •     """
  •     global chat_text, send_msg, online_user, send_entry
  •     root = Toplevel()
  •     root.title("聊天界面")
  •     center_window(root, 800, 500)
  •     send_msg = StringVar()
  •     """
  •     ——————————————————————————
  •     查收文件text开始
  •     """
  •     frame = Frame(root)
  •     frame.place(x = 20, y = 20)
  •     gun_song_tiao_y = Scrollbar(frame)
  •     gun_song_tiao_x = Scrollbar(frame, orient=HORIZONTAL)
  •     chat_text = Text(frame, height=20, width=60, wrap='none', relief=GROOVE, state=DISABLED, font=('微软雅黑', 14))#, state=DISABLED
  •     gun_song_tiao_y.pack(side=RIGHT,fill=Y)
  •     gun_song_tiao_x.pack(side=BOTTOM, fill=X)
  •     chat_text.pack()
  •     gun_song_tiao_y.config(command=chat_text.yview)
  •     gun_song_tiao_x.config(command=chat_text.xview)
  •     chat_text.config(yscrollcommand=gun_song_tiao_y.set)
  •     chat_text.config(xscrollcommand=gun_song_tiao_x.set)
  •     """
  •     查收文件区域text结束
  •     ——————————————————————————
  •     """
  •     send_entry = Text(root, width=70, height=6) # 发送区域
  •     send_entry.place(x=20, y=390)
  •     send_button = Button(root, text="发送", command=fa_)     # 发送按钮
  •     send_button.place(x=520, y=390)
  •     send_entry.bind("", fa_)
  •     send_entry.bind("", insert_newline)
  •     Label(root, text="在线列表", font=("微软雅黑", 18)).place(x=600, y=20)
  •     online_user = Listbox(root, height=25)
  •     online_user.place(x=600, y=50)
  •     # online_user.insert(END, username_string.get())
  • def help():
  •     """
  •     帮助界面
  •     """
  •     mg.showerror("暂无", "NONE")
  • def if_login(*args):
  •     main()
  •     send()
  • def if_res():
  •     pass
  • def login():
  •     """注册/登陆"""
  •     global username_string
  •     global username_string, password_string
  •     global client
  •     root = Tk()
  •     center_window(root, 400, 300)   # 实现页面居中
  •     root.title("Gouzi WD在线聊天室")    # 标题
  •     client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  •     client.connect(('43.138.0.102', 80))
  •     username_string = StringVar()   # 存储用户名变量
  •     password_string = StringVar()   # 密码存储变量
  •     Label(root, text="登陆界面", font=("微软雅黑", 20)).place(x=130, y=30)  # 表头
  •     Label(root, text="用户名:", font=("微软雅黑", 14)).place(x=10, y=100)  # 用户名一栏
  •     username = Entry(root, textvariable=username_string)    #用户名Entry
  •     username.place(x=110, y=100)
  •     Label(root, text="密码:", font=("微软雅黑", 14)).place(x=10, y=150)  # 密码一栏
  •     password = Entry(root, textvariable=password_string, show="*")    # 密码Entry
  •     password.place(x=110, y=150)
  •     username.bind("", if_login)
  •     password.bind("", if_login)
  •     join_button = Button(root, text="登陆", command=if_login, font=("微软雅黑", 12))    # 进入聊天界面按钮
  •     join_button.place(x=60, y=200)
  •     res_button = Button(root, text="注册", command=if_res, font=("微软雅黑", 12))    # 注册
  •     res_button.place(x=230, y=200)
  •     # if_login()
  •     root.mainloop()
  • login()
  • # def login():
  • #     """
  • #     登陆界面,也是初始界面
  • #     """
  • #     root = Tk()
  • #     center_window(root, 400, 500)   # 实现页面居中
  • #     root.title("Gouzi WD在线聊天室")    # 标题
  • #     username_string = StringVar()   # 存储用户名变量
  • #     ip_string = StringVar() # ip存储变量
  • #     password_string = StringVar()   # 密码存储变量
  • #     Label(root, text="初始界面", font=("微软雅黑", 20)).place(x=130, y=30)  # 表头
  • #     Label(root, text="用户名:", font=("微软雅黑", 14)).place(x=10, y=100)  # 用户名一栏
  • #     username = Entry(root, textvariable=username_string)    #用户名Entry
  • #     username.place(x=110, y=100)
  • #     Label(root, text="ip:", font=("微软雅黑", 14)).place(x=10, y=150)  # ip一栏
  • #     ip = Entry(root, textvariable=ip_string)    #ipEntry
  • #     ip.place(x=110, y=150)
  • #     Label(root, text="ip密码(选填):", font=("微软雅黑", 14)).place(x=10, y=200)  # 密码一栏
  • #     password = Entry(root, textvariable=password_string)    # 密码Entry
  • #     password.place(x=110, y=200)
  • #     Label(root, text="预留位:", font=("微软雅黑", 14)).place(x=10, y=250)  # 预留一栏
  • #     password = Entry(root)    # 预留Entry
  • #     password.place(x=110, y=250)
  • #     join_button = Button(root, text="进入", command=join, font=("微软雅黑", 12))    # 进入聊天界面按钮
  • #     join_button.place(x=160, y=300)
  • #     help_button = Button(root, text="帮助", font=("微软雅黑", 9), command=help)   # 帮助按钮
  • #     help_button.place(x=163, y=350)
  • #     # join()
  • #     root.mainloop()
  • Windows版:[code]from tkinter import *
  • from tkinter.font import Font
  • # from tkinter.ttk import *
  • from tkinter import messagebox as mg
  • import time
  • import threading
  • import socket
  • def center_window(root, width, height):
  •     """
  •     窗口居中代码
  •     """
  •     screenwidth = root.winfo_screenwidth()  # 获取显示屏宽度
  •     screenheight = root.winfo_screenheight()  # 获取显示屏高度
  •     size = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)  # 设置窗口居中参数
  •     root.geometry(size)  # 让窗口居中显示
  • def fasong(*args):
  •     time.sleep(0.1)
  •     # re_data = input(">>")
  •     re_data = send_entry.get("1.0", END)[:-1]
  •     if 'exit' == re_data:   # 判断是否退出
  •         client.send(("Q "+ username).encode())  # 发送退出的请求
  •         client.close()
  •     elif (re_data != " \n" and re_data != "\n" and re_data != "" and re_data != " "):    # 判断内容不为空
  •         client.send(("C " + username + ": " + re_data).encode())
  •         time_ = time.strftime('%Y-%m-%d %H:%M:%S')                  # 以下为自己说的话
  •         chat_text.config(state=NORMAL)
  •         #f1 = Font("微软雅黑", 8)
  •         chat_text.tag_config("tag_3", font=("微软雅黑", 9), foreground="grey")
  •         chat_text.insert(END, time_, "tag_3")   # 发送时间
  •         chat_text.insert(END, "\n")
  •         #f = Font("微软雅黑", 13)
  •         chat_text.tag_config("tag_41", font=("微软雅黑", 14), foreground="#808080")
  •         chat_text.insert(END, username + ":", "tag_41")    # 发送文本内容
  •         chat_text.insert(END, "\n")
  •         
  •         #f = Font("微软雅黑", 12)
  •         chat_text.tag_config("tag_4", font=("微软雅黑", 13), foreground="#2E8B57")
  •         chat_text.insert(END, re_data, "tag_4")    # 发送文本内容
  •         chat_text.insert(END, "\n")
  •         chat_text.config(state=DISABLED)
  •         chat_text.see("end")    # 转到最后一行
  •         # send_entry.first()
  •         # send_entry.delete(0.1,2.0)      # 设置发送为空
  •         # send_entry.insert('1 wordstart' , "s")
  •         # time.sleep(0.1)
  •         send_entry.delete("0.0", END)   # 设置发送为空
  • def fa_(*args):
  •     fasong()
  •     # send_entry.delete("0.0", END)   # 设置发送为空
  •     return 'break'
  • def jieshou():
  •     while True:
  •         # time.sleep(0.3)
  •         try:
  •             data = client.recv(1024)
  •             res = data.decode()
  •             if(res != ''):
  •                 # print("1")
  •                 if (res.split(" ", 2)[0]=="C"): # 如果为聊天的请求
  •                     # print(res.split(" ", 1)[0])
  •                     # print(res.split(" ", 1)[1])
  •                     # print(res)
  •                     time_ = time.strftime('%Y-%m-%d %H:%M:%S')
  •                     chat_text.config(state=NORMAL)
  •                     #f1 = Font("微软雅黑", 10)
  •                     chat_text.tag_config("tag_1", font=("微软雅黑", 9), foreground="grey")   
  •                     chat_text.insert(END, time_, "tag_1")
  •                     chat_text.insert(END, "\n")
  •                     #f = Font("微软雅黑", 13)
  •                     chat_text.tag_config("tag", font=("微软雅黑", 14), foreground="#808080")
  •                     chat_text.insert(END, res.split(" ", 2)[1], "tag")
  •                     chat_text.insert(END, "\n")
  •                     
  •                    #f = Font("微软雅黑", 12)
  •                     chat_text.tag_config("tag_2", font=("微软雅黑", 13))
  •                     chat_text.insert(END, res.split(" ", 2)[2], "tag_2")
  •                     chat_text.insert(END, "\n")
  •                     chat_text.config(state=DISABLED)
  •                     chat_text.see("end")
  •                 elif(res.split(" ", 1)[0]=="R"):    # 在线用户请求
  •                     afd = False
  •                     print(res.split(" ", 1)[1])
  •                     for kk in range(0, online_user.size()): # 循环判断在线列表里是否有用户名
  •                         if online_user.get(kk) == (res.split(" ", 1)[1]):   # 检测到是
  •                             afd = True  # 判断变量为真
  •                             break   # 退出
  •                     if (afd ==  False): # 如果判断变量为假
  •                         online_user.insert(END,res.split(" ", 1)[1])    # 插入用户名
  •                 elif(res.split(" ", 1)[0]=="E"):    # 退出请求
  •                     for kk in range(0, online_user.size()): # 循环判断要删除的用户名
  •                         if online_user.get(kk) == (res.split(" ", 1)[1]):   
  •                             online_user.delete(kk)  # 从在线列表去除
  •                             break
  •                         
  •         # else:
  •         #     continue
  •         except Exception as e:  
  •             print(e)
  •             print("客户端已退出")
  •             #break
  • def send():
  •     """
  •     发送文字
  •     """
  •     global username
  •     username = username_string.get()    # 用户名变量
  •     # time.sleep(3)
  •     if __name__ == "__main__":
  •         # print("Welcome to Gouzi WD Chat")
  •         # print(username)
  •         #注册业务
  •         while True:
  •             # username=input("请输入用户名")
  •             if ' ' not in username and username != " " and username != "":  # 判断用户名不为空
  •                 client.send(("R "+username + " " + password_string.get()+"\n").encode())   # 发送注册请求
  •                 data=client.recv(2048).decode() # 最大接受字节
  •                 if data=="OK":  # 如果穿回信息为 “OK”
  •                     break
  •             else:
  •                 mg.showerror("", "用户名不能为空,请强制退出后重新进入")    # 用户名如果为空,发出警告
  •                
  •         try:
  •             # 创建一个新的线程
  •             new_thread = threading.Thread(target=jieshou, name="T1")   
  •             # 启动新线程
  •             new_thread.start()
  •             new_thread1 = threading.Thread(target=fasong, name="T2")
  •             # 启动新线程
  •             new_thread1.start()
  •         except:
  •             client.close()
  • def insert_newline(*args):
  •     send_entry.insert("insert", "\n")
  •     return "break"
  • def main():
  •     """
  •     加入聊天后界面
  •     """
  •     global chat_text, send_msg, online_user, send_entry
  •     root = Toplevel()
  •     root.title("聊天界面")
  •     center_window(root, 800, 500)
  •     send_msg = StringVar()
  •     """
  •     ——————————————————————————
  •     查收文件text开始
  •     """
  •     frame = Frame(root)
  •     frame.place(x = 20, y = 20)
  •     gun_song_tiao_y = Scrollbar(frame)
  •     gun_song_tiao_x = Scrollbar(frame, orient=HORIZONTAL)
  •     chat_text = Text(frame, height=14, width=50, wrap='none', relief=GROOVE, state=DISABLED, font=('微软雅黑', 14))#, state=DISABLED
  •     gun_song_tiao_y.pack(side=RIGHT,fill=Y)
  •     gun_song_tiao_x.pack(side=BOTTOM, fill=X)
  •     chat_text.pack()
  •     gun_song_tiao_y.config(command=chat_text.yview)
  •     gun_song_tiao_x.config(command=chat_text.xview)
  •     chat_text.config(yscrollcommand=gun_song_tiao_y.set)
  •     chat_text.config(xscrollcommand=gun_song_tiao_x.set)
  •     """
  •     查收文件区域text结束
  •     ——————————————————————————
  •     """
  •     send_entry = Text(root, width=70, height=6) # 发送区域
  •     send_entry.place(x=20, y=390)
  •     send_button = Button(root, text="发送", command=fa_)     # 发送按钮
  •     send_button.place(x=520, y=390)
  •     send_entry.bind("", fa_)
  •     send_entry.bind("", insert_newline)
  •     Label(root, text="在线列表", font=("微软雅黑", 18)).place(x=600, y=20)
  •     online_user = Listbox(root, height=20)
  •     online_user.place(x=600, y=50)
  •     # online_user.insert(END, username_string.get())
  • def help():
  •     """
  •     帮助界面
  •     """
  •     mg.showerror("暂无", "NONE")
  • def if_login(*args):
  •     main()
  •     send()
  • def if_res():
  •     pass
  • def login():
  •     """注册/登陆"""
  •     global username_string
  •     global username_string, password_string
  •     global client
  •     root = Tk()
  •     center_window(root, 400, 300)   # 实现页面居中
  •     root.title("Gouzi WD在线聊天室")    # 标题
  •     client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  •     client.connect(('43.138.0.102', 80))
  •     username_string = StringVar()   # 存储用户名变量
  •     password_string = StringVar()   # 密码存储变量
  •     Label(root, text="登陆界面", font=("微软雅黑", 20)).place(x=130, y=30)  # 表头
  •     Label(root, text="用户名:", font=("微软雅黑", 14)).place(x=10, y=100)  # 用户名一栏
  •     username = Entry(root, textvariable=username_string)    #用户名Entry
  •     username.place(x=110, y=100)
  •     Label(root, text="密码:", font=("微软雅黑", 14)).place(x=10, y=150)  # 密码一栏
  •     password = Entry(root, textvariable=password_string)    # 密码Entry
  •     password.place(x=110, y=150)
  •     username.bind("", if_login)
  •     password.bind("", if_login)
  •     join_button = Button(root, text="登陆", command=if_login, font=("微软雅黑", 12))    # 进入聊天界面按钮
  •     join_button.place(x=60, y=200)
  •     res_button = Button(root, text="注册", command=if_res, font=("微软雅黑", 12))    # 注册
  •     res_button.place(x=230, y=200)
  •     # if_login()
  •     root.mainloop()
  • login()
  • # def login():
  • #     """
  • #     登陆界面,也是初始界面
  • #     """
  • #     root = Tk()
  • #     center_window(root, 400, 500)   # 实现页面居中
  • #     root.title("Gouzi WD在线聊天室")    # 标题
  • #     username_string = StringVar()   # 存储用户名变量
  • #     ip_string = StringVar() # ip存储变量
  • #     password_string = StringVar()   # 密码存储变量
  • #     Label(root, text="初始界面", font=("微软雅黑", 20)).place(x=130, y=30)  # 表头
  • #     Label(root, text="用户名:", font=("微软雅黑", 14)).place(x=10, y=100)  # 用户名一栏
  • #     username = Entry(root, textvariable=username_string)    #用户名Entry
  • #     username.place(x=110, y=100)
  • #     Label(root, text="ip:", font=("微软雅黑", 14)).place(x=10, y=150)  # ip一栏
  • #     ip = Entry(root, textvariable=ip_string)    #ipEntry
  • #     ip.place(x=110, y=150)
  • #     Label(root, text="ip密码(选填):", font=("微软雅黑", 14)).place(x=10, y=200)  # 密码一栏
  • #     password = Entry(root, textvariable=password_string)    # 密码Entry
  • #     password.place(x=110, y=200)
  • #     Label(root, text="预留位:", font=("微软雅黑", 14)).place(x=10, y=250)  # 预留一栏
  • #     password = Entry(root)    # 预留Entry
  • #     password.place(x=110, y=250)
  • #     join_button = Button(root, text="进入", command=join, font=("微软雅黑", 12))    # 进入聊天界面按钮
  • #     join_button.place(x=160, y=300)
  • #     help_button = Button(root, text="帮助", font=("微软雅黑", 9), command=help)   # 帮助按钮
  • #     help_button.place(x=163, y=350)
  • #     # join()
  • #     root.mainloop()
  • [/ol]复制代码四.服务端代码
    [Python] 纯文本查看 复制代码from socket import *
    import threading
    import time
    BUFLEN = 2048
    user={}#储存用户信息
    username = {}
    # Note=open('后台记录.txt',mode='w')
    def deal(dataSocket, addr):
        while True:
            time.sleep(0.3)
            try:
                recved = dataSocket.recv(BUFLEN)    # 最大接收字节
                info = recved.decode()  # 接受的消息
                # 如果返回空bytes,表示对方关闭了连接
                # 退出循环,结束消息收发
                
                if len(info)==0:    # 如果接受的消息长度为0
                    #print("len=0")
                    for key, k in list(user.items()):   # 便利user的键-值对 key为键, k为值
                    #处理用户意外断开
                        if k == dataSocket: # 如果便利到的值与当前连接的数据一致
                            
                            #print(user[k])
                            del user[key]   # 删除掉这个值
                            #print(user)
                            if key == "" or key == " ": # 如果key为空(为了预防用户名传来为空客户端的在线列表无法显示,所以将“ ”改为“空”)
                                for ka in user: # 遍历user,发送退出的消息
                                    user[ka].send(("空" + "已退出群聊").encode())
                                    user[ka].send(("E " + "空").encode())   # 传回用户名为“空”的退出了群聊
                                    break
                            else:   # 如果不为空
                                for ka in user: # 一样的操作,只不过是传回原本的用户名
                                    user[ka].send((key + "已退出群聊").encode())
                                    user[ka].send(("E " + key).encode())
                                    break
                #处理注册业务
                elif info.split(' ',1)[0]=="R": # 如果请求为注册
                    user_text = open("./user_text.txt", mode="r")
                    lines = user_text.readlines()
                    if len(info.split(' ',2))==1:   # 没看懂(
                        dataSocket.send("No".encode())
                    elif info.split(' ',2)[1] in user:  # 如果这个用户名已经在user里了
                        dataSocket.send("No".encode())  # 拒接注册
                    elif " " in info.split(' ',2)[1] and " " in info.split(' ',2)[0]:   # 如果用户名为空,拒绝注册(好像并没有起作用)
                        dataSocket.send("No".encode())
                   
                    for user_len in range(0, len(lines)):
                        
                        if (lines[user_len].split(" ", 1)[0] == info.split(' ',2)[1] and lines[user_len].split(" ", 1)[1] == info.split(' ',2)[2]):
                            if (info.split(' ',2)[1] == " " or info.split(' ',2)[1] == ""): # 如果用户名为空,传回“空”
                                user[info.split(' ',2)[1]]=dataSocket   # 像user字典里添加新的键-值对
                                dataSocket.send("OK".encode())  # 传回ok
                                time.sleep(0.1)
                                for ll in user: # 遍历user,传回用户名
                                    if (user[ll] == user[ll]):  # 没卵用
                                        for key in user.keys():
                                            user[ll].send("R 空".encode())
                                            # Note.write("R 空")
                                            time.sleep(0.1)
                            else:   # 与if一样的操作,只不过用户名不为空
                                user[info.split(' ',2)[1]]=dataSocket
                                dataSocket.send("OK".encode())
                                time.sleep(0.1)
                                for ll in user:
                                    if (user[ll] == user[ll]):
                                        for key in user.keys():
                                            ppp = "R " + key
                                            user[ll].send(ppp.encode())
                                            # Note.write(ppp)
                                            time.sleep(0.1)
                            
                #处理聊天业务
                elif info.split(maxsplit=1)[0]=="C":    # 如果请求是聊天
                    print(info.split(maxsplit=1)[1], end=" ")   # 在服务端打印聊天信息
                    print(addr, end= " ")   # 在服务端打印ip地址
                    print(time.strftime('%Y-%m-%d %H:%M:%S'))   # 在服务端打印时间
                    for k in user:  # 遍历user
                        if (user[k] != dataSocket): # 发送至所有人(除了自己)
                            fs = "C " + info.split(' ',1)[1]    # 聊天内容
                            user[k].send(fs.encode())   # 发送聊天内容
                            # Note.write(fs)
                #处理正常流程用户推出
                elif info.split(' ',1)[0]=="Q": # 判断如果用户输入了exit的退出(好像不起作用)
                    del user[info.split(' ',1)[1]]  # 删除这个用户
                   
                    if user[info.split(' ',1)[1]] == " " or user[info.split(' ',1)[1]] == "":   # 如果用户名为空
                        k.send(("空"+"已退出群聊").encode())    # 传回空退出了群聊
                        k.send("E " + "空".encode())    # 返回空
                    else:
                        k.send((info.split(' ',1)[1]+"已退出群聊").encode())    # 一样的操作,只不过用户名不为空
                        k.send(("E " + info.split(' ',1)[1]).encode())
                    break
                # 发送的数据类型必须是bytes,所以要编码
                # dataSocket.send(f'服务端接收到了信息 {info}'.encode())
                #for p in range(len(a)):
                    #a

    .send(f'服务端接收到了信息 {info}'.encode())
            except: # 处理意外情况,大多是因为客户端异常退出引起的
                #print("123")
                #print(user)
                for key, k in list(user.items()):   # 与消息长度为0一样的操作
                #处理用户意外断开
                    if k == dataSocket:
                        
                        #print(user[k])
                        del user[key]
                        #print(user)
                        if key == "" or key == " ":
                            for ka in user:
                                user[ka].send(("空" + "已退出群聊").encode())
                                user[ka].send(("E " + "空").encode())
                                break
                        else:
                            for ka in user:
                                user[ka].send((key + "已退出群聊").encode())
                                user[ka].send(("E " + key).encode())
                                break
            #dataSocket.close()
                        
        dataSocket.close()  # 循环结束后,没有必要再进行下去,所以关闭监听
        # listenSocket.close()
    # 类型:socket.AF_INET 可以理解为 IPV4
    # 协议:socket.SOCK_STREAM
    listenSocket = socket(AF_INET, SOCK_STREAM)
    listenSocket.setsockopt(SOL_SOCKET, SOCK_STREAM, True)
    listenSocket.ioctl(SIO_KEEPALIVE_VALS, (1, 60*1000, 30*1000))
    # socket绑定地址和端口
    listenSocket.bind(('0.0.0.0', 80))
    listenSocket.listen()
    # server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # server.bind(('0.0.0.0', 8000))  # (client客户端ip, 端口)
    # server.listen()  # 监听
    print(f'服务端启动成功,在43.138.0.102端口等待客户端连接...')
    # dataSocket, addr = listenSocket.accept()
    # print('接受一个客户端连接:', addr)
    while True:
        dataSocket, addr = listenSocket.accept()  # 获得一个客户端的连接(阻塞式,只有客户端连接后,下面才执行)
        print('接受一个客户端连接:', addr)
        if (1==1):
            xd = threading.Thread(target=deal, args=(dataSocket, addr))
            xd.start()  # 启动一个线程

    微软, 用户名

  • 你是我的人   

    感谢大佬分享
    Mikepython0721
    OP
      

    我在鱼C也发过,别以为我是搬运的
    Wapj_Wolf   

    学习了,谢谢楼主无私分享。
    NingXIU   

    学习学习,感谢楼主无私分享
    小丑恶人   

    这还挺不错的嘛
    zz1181   

    想到就做,好强的行动力,膜拜
    wushengli   

    思路不错 感谢分享~!
    py学徒   

    感谢楼主分享,恭喜楼主成长!
    ppmjb   

    多谢楼主分享,学习中。
    您需要登录后才可以回帖 登录 | 立即注册

    返回顶部