服务器
from socket import *
import select
import sys
from threading import Thread
import os
import time
s = socket()
s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
s.bind(('127.0.0.1', 8421))
s.listen(5)
rlist = [s]
wlist = []
xlist = []
user = {}
userlist = ['admin']
class XcqServer:
# 处理客户端退出请求
@classmethod
def quit(slef, r):
print(user[r][0] + "客户端退出")
for i in user:
if i is r:
pass
else:
i.send((user[r][0] + "已下线\n").encode())
userlist.remove[user[r][0]]
del user[r]
rlist.remove(r)
xlist.remove(r)
r.close()
# 处理用户获取成员列表
@classmethod
def lst(self, r):
lst = ','.join(userlist)
r.send(lst.encode())
# 处理客户端登录请求
@classmethod
def land(self, r, L):
name = L[1]
pwd = L[2]
with open('user', 'r') as fr:
while True:
a = fr.readline()
if not a:
r.send(")(**&^&%%*(".encode())
break
b = a[:(len(a) - 1)]
c = b.split(",")
if c[0] == name and c[1] == pwd:
r.send("*!&@*~((~^!^%".encode())
user[r] = L[1:4]
userlist.append(name)
for i in user:
if i is r:
pass
else:
i.send(("%s已上线\n" % name).encode())
return
# 处理客户端消息发送
@classmethod
def say(self, r):
for i in user:
if i is r:
pass
else:
i.send((user[r][0] + "说:" + data).encode())
# 处理用户注册请求
@classmethod
def sign(self, r, L):
name = L[1]
pwd = L[2]
np = name + "," + pwd
with open('user', 'r') as fr:
while True:
a = fr.readline()
b = a[:(len(a) - 1)]
c = b.split(",")
if not a:
break
if c[0] == L[1]:
r.send("^%#&^@*&^#%%@@@".encode())
return
with open('user', 'a') as f:
f.write(np)
f.write('\n')
user[r] = L[1:4]
print("%s已注册" % name)
r.send("**#(@*!))*#*(@!*&".encode())
return
# 管理员广播函数
def admin(s):
while True:
msg = input()
if not msg:
break
for i in user:
if i is s:
pass
else:
i.send(("管理员说:" + msg).encode())
while True:
try:
rs, ws, es = select.select(rlist, wlist, xlist)
for r in rs:
if r is s:
c, addr = r.accept()
print("连接到", addr)
rlist.append(c)
xlist.append(c)
t = Thread(target=admin, args=(s,))
t.start()
else:
data = r.recv(1024).decode()
namelst = data.split(" ")
if data == '@×&#还7@8#7':
XcqServer.quit(r)
elif namelst[0] == "*#*&!((#*!@@&&&":
XcqServer.land(r, namelst)
elif namelst[0] == "&@……%#sh!@#3@*&":
XcqServer.sign(r, namelst)
elif namelst[0] == "lstaaaaa":
XcqServer.lst(r)
else:
XcqServer.say(r)
for w in ws:
pass
for e in es:
if e is s:
s.close()
sys.exit(0)
else:
e.close()
rlist.remove(e)
xlist.remove(e)
except KeyboardInterrupt:
if user == []:
pass
else:
for i in user:
if i is s:
pass
i.send("!&$*#@%!*@^#$^!@&@5!&".encode())
print("服务器关闭")
s.close()
os._exit(0)
except Exception:
continue
客户端
from socket import *
import os
from threading import Thread
from tkinter import *
import time
HOST = '127.0.0.1'
PORT = 8421
ADDR = (HOST, PORT)
BUFFERSIZE = 1024
connfd = socket()
connfd.connect(ADDR)
user = [] # 成员列表
island = 0 # 判断用户是否为登录状态
# 用户注册函数
def sign():
def usrsign(var):
names = str(ns.get())
passwds = str(pwds.get())
passwds1 = str(pwds1.get())
if not names:
print("姓名不合法,请重新输入")
var.set('姓名不合法,请重新输入')
return
if passwds != passwds1:
print("输入的两次密码不一致,请重新输入")
var.set('输入的两次密码不一致,请重新输入')
return
S = "&@……%#sh!@#3@*&" + " " + names + " " + passwds
connfd.send(S.encode())
data = connfd.recv(1024).decode()
if data == "**#(@*!))*#*(@!*&":
print("注册成功")
var.set('注册成功')
top2.destroy()
return
elif data == "^%#&^@*&^#%%@@@":
print("用户名重复")
var.set('用户名重复')
return
# 创建注册窗口(在登录窗口的基础上创建)
top2 = Toplevel(top)
top2.title("注册")
top2.geometry("400x200+200+20")
Label(top2, text="用户名:").place(x=50, y=40)
Label(top2, text="密码:").place(x=50, y=80)
Label(top2, text="确认密码:").place(x=50, y=120)
var = StringVar()
Label(top2, textvariable=var).place(x=190, y=150)
ns = StringVar()
ns.set("请输入用户名")
entrynames = Entry(top2, textvariable=ns)
entrynames.place(x=120, y=40)
pwds = Variable()
entrypwds = Entry(top2, textvariable=pwds)
entrypwds.place(x=120, y=80)
pwds1 = Variable()
entrypwds1 = Entry(top2, textvariable=pwds1)
entrypwds1.place(x=120, y=120)
b_sign = Button(top2, text='注册', command=lambda: usrsign(var))
b_sign.place(x=130, y=150)
top2.mainloop()
# 用户登录函数
def land():
global island
island = 1
name = str(n.get())
passwd = str(pwd.get())
if not name:
print("姓名不合法,请重新输入")
return
S = "*#*&!((#*!@@&&&" + " " + name + " " + passwd
connfd.send(S.encode())
data = connfd.recv(1024).decode()
if data == "*!&@*~((~^!^%":
print("登录成功")
top.destroy()
return
elif data == ")(**&^&%%*(":
print("用户名或密码错误")
return
# 客户端接收消息函数
def recv():
while True:
try:
data = connfd.recv(1024).decode()
if data == "!&$*#@%!*@^#$^!@&@5!&":
print("服务器出现异常")
text_recv.insert(END, "服务器出现异常")
t1.close()
os._exit(0)
msgcon = time.strftime("%Y-%m-%d %H:%M:%S",
time.localtime()) + '\n'
text_recv.insert(END, msgcon, 'green')
text_recv.insert(END, data)
if data[-4:] == '已上线\n':
user.append(data[:-4])
updatelst()
if data[-4:] == '已下线\n':
user.remove(data[:-4])
updatelst()
except KeyboardInterrupt:
connfd.send('@×&#还7@8#7'.encode())
print("已下线")
os._exit(0)
except Exception:
os._exit(0)
# 客户端发送消息函数
def send():
def sendmsg():
try:
msgcon = time.strftime("%Y-%m-%d %H:%M:%S",
time.localtime()) + '\n'
text_recv.insert(END, msgcon, 'green')
text_recv.insert(END, text_msg.get('0.0', END))
msg = text_msg.get('0.0', END)
if not msg:
return
connfd.send(msg.encode())
text_msg.delete('0.0', END)
return
except KeyboardInterrupt:
t1.close()
except Exception:
os._exit(0)
button_sendmsg = Button(top1, text='发送', command=sendmsg)
button_sendmsg.place(x=371, y=365)
# 更新成员列表函数
def updatelst():
lb.delete(0, len(user) + 1)
for i in user:
lb.insert(END, ('<-----', i, '----->'))
# 创建登录窗口
top = Tk()
top.title("登录")
top.geometry("400x300+200+20")
Label(top, text="用户名:").place(x=50, y=150)
Label(top, text="密码:").place(x=50, y=190)
n = StringVar()
n.set("请输入用户名")
entryname = Entry(top, textvariable=n)
# Entry:单行文字,收集键盘输入
entryname.place(x=120, y=150)
pwd = Variable()
entrypwd = Entry(top, textvariable=pwd, show="*")
# textvariable:指定一个变量,变量的值转变为字符串在控件上显示
entrypwd.place(x=120, y=190)
b_login = Button(top, text='登录', command=land)
b_login.place(x=130, y=230)
b_sign = Button(top, text='注册', command=sign)
b_sign.place(x=230, y=230)
top.mainloop()
# 判断用户是否进行了登录操作
if not island:
os._exit(0)
else:
pass
# 获取成员列表
connfd.send("lstaaaaa".encode())
datauser = connfd.recv(1024).decode()
user = datauser.split(',')
print(user)
# 创建聊天窗口
top1 = Tk()
top1.title("聊天室")
top1.geometry("600x400+200+20")
# 建立接收消息的部件
text_recv = Text(top1, width=58, height=19)
text_recv.place(x=0, y=0)
text_recv.tag_config('green', foreground='#008b00')
# 建立发送消息的部件
text_msg = Text(top1, width=59, height=6)
text_msg.place(x=0, y=275)
# 建立接收消息部件中的滚动条
sb = Scrollbar(top1, orient="vertical")
sb.place(x=410, y=0, height=270)
text_recv.config(yscrollcommand=sb.set)
# yscrollcommand:指定行的最大字符数,超过则转到下一行显示
sb.config(command=text_recv.yview)
# 建立成员列表部件
lb = Listbox(top1, width=23, height=18)
lb.place(x=423, y=20)
updatelst()
# 建立列表部件的滚动条
sb1 = Scrollbar(top1)
sb1.place(x=586, y=22, height=341)
lb.config(yscrollcommand=sb1.set)
sb1.config(command=lb.yview)
Label(top1, text="在线成员", font=('黑体', 8)).place(x=480, y=0)
# 创建线程,用来发送消息
t1 = Thread(target=send)
t1.start()
# 创建线程,用来接收消息
t2 = Thread(target=recv)
t2.start()
top1.mainloop()
connfd.send('@×&#还7@8#7'.encode())