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