聊天室 Tkinter I/O多路复用select

服务器

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())


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值