【python】实现多人网络聊天室

利用socket套接字实现多台计算机之间的连接

server:

import socket                                               #socket 是一种套接字,用来描述IP和port
import os
import threading                                            #多线程
import queue
import sys
import time

host="127.0.0.1"                                   #server's IP
port=6000                                                   #server's port


class Server(threading.Thread):
    def __init__(self):
        self.messages = queue.Queue()
        self.lock = threading.Lock()
        self.users=[]                           #记录当前在线的用户
        threading.Thread.__init__(self)
        self.tcpsocket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)  #实例化一个socket,用于Internet进程间通信,使用TCP协议
        os.chdir(sys.path[0])


    #事件处理函数
    def handle(self,conn,addr):
        try:
            while True:
                data=conn.recv(1024).decode()
                if data=="register":
                    self.register(conn,addr)
                elif data=="submit":
                    username=self.submit(conn,addr)
                elif data=="send":
                    self.send(conn,addr,username)
            conn.close()
        except:
            self.users.remove(conn)
            conn.close()


    #处理账号登录
    def submit(self,conn,addr):
        conn.send("y".encode())                #第二次握手
        username=conn.recv(1024).decode()
        password=conn.recv(1024).decode()
        filenames=os.listdir(r"user")
        calculator=0
        for i in filenames:
            if (username+".txt")==i:
                with open(f"user/{username}.txt", "r") as file:
                    data = file.read()
                if password==data:
                    self.users.append(conn)
                    conn.send("y".encode())
                else:
                    conn.send("n".encode())
                break
            else:
                calculator+=1
                continue
        if calculator==len(filenames):
            conn.send("n".encode())
        return username

    #处理账号注册
    def register(self,conn,addr):
        conn.send("y".encode())                #第二次握手
        username=conn.recv(1024).decode()
        password=conn.recv(1024).decode()
        filenames=os.listdir(r"user")
        calculator=0
        for i in filenames:
            if (username+".txt")==i:
                conn.send("n".encode())
                break
            else:
                calculator+=1
                continue
        if calculator==len(filenames):
            with open(f"user/{username}.txt","w") as file:
                file.write(password)
            conn.send("y".encode())

    #处理发送消息
    def send(self,conn,addr,username):
        mes=conn.recv(1024).decode()
        m=username+": "+mes
        self.Load(m)

    # 将地址与数据(需发送给客户端)存入messages队列
    def Load(self, data):
        self.lock.acquire()
        try:
            self.messages.put(data)
        finally:
            self.lock.release()

    #将messages中的消息发送给所有登录的用户
    def sendData(self):
        while True:
            if not self.messages.empty():
                message = self.messages.get()
                print(message)
                for i in self.users:
                    i.send(message.encode())


        
    def run(self):
        self.tcpsocket.bind((host,port))          #将host和port(元组)绑定在tcpsocket套接字上
        self.tcpsocket.listen(5)                  #开始TCP监听,传入参数为可以同时挂起的最大数量
        print("server is waiting for client's linking...")
        q = threading.Thread(target=self.sendData)
        q.start()
        while True:
            conn, addr = self.tcpsocket.accept()       #新建一个套接字
            print("连接成功")
            t = threading.Thread(target=self.handle, args=(conn, addr))
            t.start()
        self.tcpsocket.close()


if __name__ == '__main__':
    server = Server()
    server.start()
a=socket.gethostname()

client:

import socket
import wx
import time
import threading

host="121.62.17.41"     #  填服务器的ip                               
port=61167              #  填服务器的端口,这里我用了内网穿透所以不是6000


class MyFrame(wx.Frame):   
    def __init__(self,parent,id):
        wx.Frame.__init__(self,parent,id,title="网络聊天室",pos=(400,200),size=(400,300))
        panel=wx.Panel(parent=self)                               #创建画板
        self.title=wx.StaticText(panel,label="请输入用户名和密码")    #创建标题

        #创建确定和取消按钮并绑定事件
        self.bt_confirm=wx.Button(panel,label="确定")
        self.bt_confirm.Bind(wx.EVT_BUTTON,self.OnclickSubmit)
        self.bt_cancel=wx.Button(panel,label="清空")
        self.bt_cancel.Bind(wx.EVT_BUTTON,self.OnclickCancel)
        self.bt_register=wx.Button(panel,label="注册")
        self.bt_register.Bind(wx.EVT_BUTTON,self.OnclickRegister)

        self.label_user=wx.StaticText(panel,label="用户名:")
        self.text_user=wx.TextCtrl(panel,style=wx.TE_LEFT)
        self.label_pwd=wx.StaticText(panel,label="密   码:")
        self.text_password=wx.TextCtrl(panel,style=wx.TE_PASSWORD)

        #添加容器,容器中控件横向排列
        hsizer_user=wx.BoxSizer(wx.HORIZONTAL)
        hsizer_user.Add(self.label_user,proportion=0,flag=wx.ALL,border=5)
        hsizer_user.Add(self.text_user,proportion=1,flag=wx.ALL,border=5)
        hsizer_pwd=wx.BoxSizer(wx.HORIZONTAL)
        hsizer_pwd.Add(self.label_pwd,proportion=0,flag=wx.ALL,border=5)
        hsizer_pwd.Add(self.text_password,proportion=1,flag=wx.ALL,border=5)
        hsizer_button=wx.BoxSizer(wx.HORIZONTAL)
        hsizer_button.Add(self.bt_confirm,proportion=0,flag=wx.ALIGN_CENTER,border=5)
        hsizer_button.Add(self.bt_cancel,proportion=0,flag=wx.ALIGN_CENTER,border=5)
        hsizer_button.Add(self.bt_register,proportion=0,flag=wx.ALIGN_CENTER,border=5)

        #添加容器,容器中控件纵向排列
        vsizer_all=wx.BoxSizer(wx.VERTICAL)
        vsizer_all.Add(self.title,proportion=0,flag=wx.BOTTOM|wx.TOP|wx.ALIGN_CENTER,border=15)
        vsizer_all.Add(hsizer_user,proportion=0,flag=wx.EXPAND|wx.LEFT|wx.RIGHT,border=45)
        vsizer_all.Add(hsizer_pwd,proportion=0,flag=wx.EXPAND|wx.LEFT|wx.RIGHT,border=45)
        vsizer_all.Add(hsizer_button,proportion=0,flag=wx.ALIGN_CENTER|wx.TOP,border=15)
   
        panel.SetSizer(vsizer_all)

    def OnclickSubmit(self,event):
        message=""
        username=self.text_user.GetValue()
        password=self.text_password.GetValue()
        if username=="" or password=="":
            message="用户名和密码不能为空"
            wx.MessageBox(message)
        elif len(username)>=20 or len(password)>=20:
            message="用户名和密码不匹配或用户名不存在"
            wx.MessageBox(message)
        else:
            send_data="submit"
            clientsocket.send(send_data.encode())
            clientsocket.recv(1024)                                #第二次握手
            clientsocket.send(username.encode())
            clientsocket.send(password.encode())
            recvdata=clientsocket.recv(1024).decode()
            if recvdata=="n":
                message="用户名和密码不匹配或用户名不存在"
                wx.MessageBox(message)
            elif recvdata=="y":
                message="登录成功"
                wx.MessageBox(message)
                self.Onclose()                         
                mainframe=MainFrame(parent=None,id=-1)   
                mainframe.Show()
                r = threading.Thread(target=mainframe.receive)
                r.start()  # 开始线程接收信息                         
                return True
            
    
    def OnclickCancel(self,event):
        self.text_user.SetValue("")               #清空输入的用户名
        self.text_password.SetValue("")           #清空输入的密码

    def OnclickRegister(self,event):
        self.Onclose()                       
        registerframe=RegisterFrame(parent=None,id=-1)   
        registerframe.Show()                        
        return True

    def Onclose(self):
        self.Destroy()




class MainFrame(wx.Frame):
    def __init__(self,parent,id):
        wx.Frame.__init__(self,parent,id,title="网络聊天室",pos=(400,200),size=(800,500))
        panel=wx.Panel(parent=self)                                 #创建画板
        self.title=wx.StaticText(panel,label="欢迎来到网络聊天室")    #创建标题
        #创建发送按钮
        self.bt_send=wx.Button(panel,label="发送")
        self.bt_send.Bind(wx.EVT_BUTTON,self.OnclickSend)
        #页面元素
        self.text_send=wx.TextCtrl(panel,style=wx.TE_LEFT)
        self.text=wx.TextCtrl(panel,style=wx.TE_MULTILINE|wx.TE_READONLY)
        self.text.AppendText("加入聊天室\n")#
        #添加容器,容器中控件横向排列
        hsizer_send=wx.BoxSizer(wx.HORIZONTAL)
        hsizer_send.Add(self.text_send,proportion=1,flag=wx.ALL,border=5)
        hsizer_send.Add(self.bt_send,proportion=0,flag=wx.ALL,border=5)
        #添加容器,容器中控件纵向排列
        vsizer_all=wx.BoxSizer(wx.VERTICAL)
        vsizer_all.Add(self.title,proportion=0,flag=wx.BOTTOM|wx.TOP|wx.ALIGN_CENTER,border=15)
        vsizer_all.Add(self.text,proportion=5,flag=wx.EXPAND|wx.LEFT|wx.RIGHT,border=45)
        vsizer_all.Add(hsizer_send,proportion=1,flag=wx.EXPAND|wx.LEFT|wx.RIGHT,border=40)
        panel.SetSizer(vsizer_all)

    def OnclickSend(self,event):
        message=self.text_send.GetValue()
        self.text_send.Clear()
        if message=="":
            pass
        else:
            send_data="send"
            clientsocket.send(send_data.encode())
            time.sleep(0.5)                                  #还没解决三次握手的问题
            clientsocket.send(message.encode())
    
    def receive(self):
        try:
            while True:
                recvdata=clientsocket.recv(1024).decode()
                self.text.AppendText(recvdata+"\n")
        except:
            pass                                #静默退出



class RegisterFrame(wx.Frame):
    def __init__(self,parent,id):
        wx.Frame.__init__(self,parent,id,title="网络聊天室",pos=(400,200),size=(400,300))
        panel=wx.Panel(parent=self)                               #创建画板
        self.title=wx.StaticText(panel,label="注册账号")    #创建标题

        #创建确定和取消按钮并绑定事件
        self.bt_confirm=wx.Button(panel,label="确定")
        self.bt_confirm.Bind(wx.EVT_BUTTON,self.OnclickSubmit)
        self.bt_cancel=wx.Button(panel,label="取消")
        self.bt_cancel.Bind(wx.EVT_BUTTON,self.OnclickCancel)

        self.label_user=wx.StaticText(panel,label="用户名:")
        self.text_user=wx.TextCtrl(panel,style=wx.TE_LEFT)
        self.label_pwd=wx.StaticText(panel,label="密   码:")
        self.text_password=wx.TextCtrl(panel,style=wx.TE_PASSWORD)

        #添加容器,容器中控件横向排列
        hsizer_user=wx.BoxSizer(wx.HORIZONTAL)
        hsizer_user.Add(self.label_user,proportion=0,flag=wx.ALL,border=5)
        hsizer_user.Add(self.text_user,proportion=1,flag=wx.ALL,border=5)
        hsizer_pwd=wx.BoxSizer(wx.HORIZONTAL)
        hsizer_pwd.Add(self.label_pwd,proportion=0,flag=wx.ALL,border=5)
        hsizer_pwd.Add(self.text_password,proportion=1,flag=wx.ALL,border=5)
        hsizer_button=wx.BoxSizer(wx.HORIZONTAL)
        hsizer_button.Add(self.bt_confirm,proportion=0,flag=wx.ALIGN_CENTER,border=5)
        hsizer_button.Add(self.bt_cancel,proportion=0,flag=wx.ALIGN_CENTER,border=5)

        #添加容器,容器中控件纵向排列
        vsizer_all=wx.BoxSizer(wx.VERTICAL)
        vsizer_all.Add(self.title,proportion=0,flag=wx.BOTTOM|wx.TOP|wx.ALIGN_CENTER,border=15)
        vsizer_all.Add(hsizer_user,proportion=0,flag=wx.EXPAND|wx.LEFT|wx.RIGHT,border=45)
        vsizer_all.Add(hsizer_pwd,proportion=0,flag=wx.EXPAND|wx.LEFT|wx.RIGHT,border=45)
        vsizer_all.Add(hsizer_button,proportion=0,flag=wx.ALIGN_CENTER|wx.TOP,border=15)
   
        panel.SetSizer(vsizer_all)

    def OnclickSubmit(self,event):
        message=""
        username=self.text_user.GetValue()
        password=self.text_password.GetValue()
        if username=="" or password=="":
            message="用户名和密码不能为空"
            wx.MessageBox(message)
        elif len(username)>=20 or len(password)>=20:
            message="用户名或密码太长"
            wx.MessageBox(message)
        else:
            send_data="register"
            clientsocket.send(send_data.encode())
            clientsocket.recv(1024)                               #第二次握手
            clientsocket.send(username.encode())
            clientsocket.send(password.encode())
            recvdata=clientsocket.recv(1024).decode()
            if recvdata=="n":
                message="用户名已存在"
                wx.MessageBox(message)
            elif recvdata=="y":
                message="注册成功"
                wx.MessageBox(message)
                self.Onclose()                         
                frame=MyFrame(parent=None,id=-1)   
                frame.Show()                         
                return True

    def OnclickCancel(self,event):
        self.Onclose()                         
        frame=MyFrame(parent=None,id=-1)   
        frame.Show()                         
        return True

    def Onclose(self):
        self.Destroy()



class App(wx.App):
    def OnInit(self):
        frame=MyFrame(parent=None,id=-1)
        frame.Show()
        return True
    

if __name__=="__main__":
    clientsocket=socket.socket(socket.AF_INET, socket.SOCK_STREAM)                                                 
    clientsocket.connect((host,port))
#GUI
    app=App()
    app.MainLoop()
    
    clientsocket.close()

你可能感兴趣的:(网络,python,开发语言)