python版 聊天軟體
from tkinter import *
from tkinter.filedialog import askopenfilename
import time
from threading import Thread
import socket
import sys
import os.path
import process
#聊天實現類
class ChatClient(Thread):
#建構函式
def __init__(self):
Thread.__init__(self)
#提示資訊輸出
self.__info_event=None
#讀取資料輸出
self.__out_event=None
#建立套接字
self.clientSock=socket.socket()
#重用地址
self.clientSock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
#返回提醒資訊
#info事件
@property
def info_event(self):
return self.__info_event
@info_event.setter
def info_event(self,handler):
self.__info_event=handler
#info輸出
def info(self,content):
if self.info_event!=None:
self.info_event(content)
#返回接收結果
#out事件
@property
def out_event(self):
return self.__out_event
@out_event.setter
def out_event(self,handler):
self.__out_event=handler
#out輸出
def out(self,content):
if self.out_event!=None:
self.out_event(content)
#傳送資訊
def send(self,content):
if self.clientSock==None:
self.info("已經斷開連線")
return -1
if type(content) is str:
content=content.encode()
elif type(content) is bytes:
pass
else:
self.info("傳送資訊型別錯誤")
return -1
try:
self.clientSock.send(content)
#self.info("已經發送資訊")
return 0
except:
self.info("丟失連線")
return -1
#接受資訊
def recv(self):
recv_msg={}
if self.clientSock==None:
return
fileobj=self.clientSock.makefile("rb")
while True:
try:
line=fileobj.readline()
except:
return None
if not len(line):
return None
elif line==b"\r\n":
break
else:
#print(line)
key,value=line.decode().strip().split(": ")
recv_msg[key]=value
if "Length" in recv_msg:
length=int(recv_msg["Length"])
recv_msg["Content"]=b""
while length>0:
r=fileobj.read(min(1024,length))
length-=len(r)
recv_msg["Content"]+=r
fileobj.close()
elif "Count" in recv_msg:
count=int(recv_msg["Count"])
#print(count)
recv_msg["Content"]=b""
while count>0:
recv_msg["Content"]+=fileobj.readline()
count-=1
fileobj.close()
return recv_msg
def run(self):
while True:
recv_msg=self.recv()
if recv_msg==None:
break
self.out(recv_msg)
#連線chat伺服器
def connserver(self,servername,serverport):
try:
self.clientSock.connect((servername,serverport))
#self.info("成功連線pchat伺服器")
return 0
except BaseException as e:
self.info("連線pchat伺服器失敗")
return -1
#斷開連線
def disconnserver(self):
if self.clientSock!=None:
self.clientSock.close()
self.clientSock=None
self.info("斷開連線")
return 0
#主介面類
class MainWindow(Tk):
#建構函式
def __init__(self,name,pwd,chatwith=None):
Tk.__init__(self)
#使用者名稱屬性
self.username=name
self.password=pwd
self.chatwith=chatwith
self.init()
self.conn()
def conn(self,host="127.0.0.1",port=1234):
#初始化chatclient
self.chatclient=ChatClient()
#新增事件處理
self.chatclient.info_event=self.info
self.chatclient.out_event=self.out
#連線
r=self.chatclient.connserver(host,port)
#開始接收伺服器傳送的資料
self.chatclient.start()
return r
#屬性使用者名稱
@property
def username(self):
return self.__username
@username.setter
def username(self,name):
self.__username=name
@property
def password(self):
return self.__password
@password.setter
def password(self,pwd):
self.__password=pwd
#屬性 聊天物件
@property
def chatwith(self):
return self.__chatwith
@chatwith.setter
def chatwith(self,name):
self.__chatwith=name
#初始化選單
def init_menu(self):
menubar=Menu(self,bg="lightblue")
self["menu"]=menubar
sysmenu=Menu(menubar,bg="lightblue")
menubar.add_cascade(label="系統",menu=sysmenu)
#下拉選單
sysmenu.add_command(label="配置",command=self.clientConfigure)
sysmenu.add_separator()
sysmenu.add_command(label="登陸",command=self.login)
sysmenu.add_command(label="註冊",command=self.register)
sysmenu.add_command(label="登出",command=self.outlogin)
sysmenu.add_separator()
sysmenu.add_command(label="結束",command=self.destroy)
#設定標題
def setTitle(self,name):
self.title("【%s】PChat [%s]"%(self.username,name))
#介面初始化
def init(self):
self.setTitle(self.chatwith)
self.init_menu()
left_frame=Frame(self)
left_frame.pack(expand=YES,fill=BOTH,side=LEFT)
right_frame=Frame(self)
right_frame.pack(fill=Y,side=LEFT)
self.friends_list=Listbox(right_frame,bg="lightblue")
self.friends_list.pack(expand=YES,fill=BOTH)
self.friends_list.bind("<Double-Button-1>",self.select_friend)
self.friend_entry=Entry(right_frame)
self.friend_entry.pack(fill=X)
self.flush_button=Button(right_frame,text="重新整理",command=self.flush)
self.flush_button.pack(side=LEFT)
self.add_button=Button(right_frame,text="增加",command=self.add)
self.add_button.pack(side=LEFT)
self.delete_button=Button(right_frame,text="刪除",command=self.delete)
self.delete_button.pack(side=LEFT)
text_frame=Frame(left_frame,bg="white")
text_frame.pack(expand=YES,fill=BOTH)
self.chatmessage_text=Text(text_frame,bg="lightblue")
self.chatmessage_text.pack(expand=YES,fill=BOTH,side=LEFT)
text_scroll_bar=Scrollbar(text_frame,command=self.chatmessage_text.yview,bg="lightblue")
text_scroll_bar.pack(fill=Y,side=RIGHT)
self.chatmessage_text.configure(yscrollcommand=text_scroll_bar.set)
self.chatmessage_text.tag_config("header",foreground="green",font=("Arial",15))
self.chatmessage_text.tag_config("information",foreground="red",font=("Arial",10))
self.chatmessage_text.tag_config("file",foreground="yellow",font=("Arial",18))
self.chatmessage_text.tag_config("body",foreground="gray",font=("Arial",18))
self.inputmessage_string=StringVar()
self.inputmessage_entry=Entry(left_frame,bg="lightblue",textvariable=self.inputmessage_string)
self.inputmessage_entry.pack(fill=X)
self.inputmessage_entry.bind("<Return>",self.send)
self.send_button=Button(left_frame,text="傳送",command=self.send,bg="lightblue")
self.send_button.pack(side=LEFT)
self.send_file_button=Button(left_frame,text="傳送檔案",command=self.sendfile)
self.send_file_button.pack(side=LEFT)
self.bottom_frame=Frame(self)
self.bottom_frame.pack(side=TOP,fill=X)
#self.usersname_label=Label(self.bottom_frame,text="使用者名稱:")
#self.usersname_label.pack(side=LEFT)
#新增關閉視窗的事件處理
self.protocol("WM_DELETE_WINDOW",self.destroy)
def select_friend(self,event=None):
if len(event.widget.curselection()):
chatwith=event.widget.get(event.widget.curselection()[0])
if chatwith!="":
self.chatwith=chatwith
self.setTitle(self.chatwith)
#使用chatclietn傳送資料
def __send(self,From,To,Date,Type,Length,content,Name=None):
if self.chatclient==None:
self.info("未連線伺服器")
return -1
r=self.chatclient.send("From: "+From+"\r\n")
if r==-1:
return -1
r=self.chatclient.send("To: "+To+"\r\n")
if r==-1:
return -1
r=self.chatclient.send("Date: "+Date+"\r\n")
if r==-1:
return -1
r=self.chatclient.send("Type: "+Type+"\r\n")
if r==-1:
return -1
r=self.chatclient.send("Length: "+str(Length)+"\r\n")
if r==-1:
return -1
if Name!=None:
r=self.chatclient.send("Name: "+Name+"\r\n")
if r==-1:
return -1
r=self.chatclient.send("\r\n")
if r==-1:
return -1
r=self.chatclient.send(content)
if r==-1:
return -1
return 0
#重新整理列表按鈕事件處理
def flush(self,event=None):
cur_time=time.localtime()
text="".encode()
self.__send(self.username,"pchatsvr","%d:%d:%d"%(cur_time.tm_hour,cur_time.tm_min,cur_time.tm_sec),"List",len(text),text)
def add(self,event=None):
friend_name=self.friend_entry.get().strip()
if friend_name!="":
cur_time=time.localtime()
text=friend_name.encode()
self.__send(self.username,"pchatsvr","%d:%d:%d"%(cur_time.tm_hour,cur_time.tm_min,cur_time.tm_sec),"Add",len(text),text)
def delete(self,event=None):
friend_name=self.friend_entry.get().strip()
if friend_name!="":
cur_time=time.localtime()
text=friend_name.encode()
self.__send(self.username,"pchatsvr","%d:%d:%d"%(cur_time.tm_hour,cur_time.tm_min,cur_time.tm_sec),"Delete",len(text),text)
#傳送資訊按鈕事件處理
def send(self,text=None):
if self.chatwith==None:
self.info("請選擇聊天物件")
return
if self.inputmessage_string.get().strip()=="":
return
cur_time=time.localtime()
self.chatmessage_text.insert(END,"%s %d:%d:%d\n"%(self.username,cur_time.tm_hour,cur_time.tm_min,cur_time.tm_sec),"header")
self.chatmessage_text.insert(END,self.inputmessage_string.get()+"\n","body")
text=(self.inputmessage_string.get()).encode()
self.__send(self.username,self.chatwith,"%d:%d:%d"%(cur_time.tm_hour,cur_time.tm_min,cur_time.tm_sec),"Plain",len(text),text)
#傳送檔案按鈕響應事件
def sendfile(self):
filename=askopenfilename()
if filename!="":
self.info("將傳送檔案:"+filename)
f=open(filename,"rb")
filecontent=f.read()
f.close()
cur_time=time.localtime()
self.__send(self.username,self.chatwith,"%d:%d:%d"%(cur_time.tm_hour,cur_time.tm_min,cur_time.tm_sec),"File",len(filecontent),filecontent,os.path.basename(filename))
else:
self.info("請選擇檔案")
#系統配置
def clientConfigure(self):
print("配置客戶端")
#登陸
def login(self):
cur_time=time.localtime()
text=(self.username+"&"+self.password).encode()
self.__send(self.username,"pchatsvr","%d:%d:%d"%(cur_time.tm_hour,cur_time.tm_min,cur_time.tm_sec),"Login",len(text),text)
#註冊
def register(self):
cur_time=time.localtime()
text=(self.username+"&"+self.password).encode()
self.__send(self.username,"pchatsvr","%d:%d:%d"%(cur_time.tm_hour,cur_time.tm_min,cur_time.tm_sec),"Register",len(text),text)
#登出
def outlogin(self):
cur_time=time.localtime()
text=("").encode()
self.__send(self.username,"pchatsvr","%d:%d:%d"%(cur_time.tm_hour,cur_time.tm_min,cur_time.tm_sec),"Outlogin",len(text),text)
#結束
def destroy(self):
cur_time=time.localtime()
text=("").encode()
r=self.__send(self.username,"pchatsvr","%d:%d:%d"%(cur_time.tm_hour,cur_time.tm_min,cur_time.tm_sec),"Quit",len(text),text)
if r==-1:
Tk.destroy(self)
#開啟檔案事件處理
def open(self,event):
#os.system("xdg-open %s"%("./recvfiles/"+event.widget["text"]))
process.system("/usr/bin/xdg-open %s"%("./recvfiles/"+event.widget["text"]))
#解析伺服器響應
def parse(self,recv_msg):
if recv_msg["Type"]=="Plain":
self.chatmessage_text.insert(END,"%s %s\n"%(recv_msg["From"],recv_msg["Date"]),"header")
self.chatmessage_text.insert(END,recv_msg["Content"].decode()+"\n","body")
elif recv_msg["Type"]=="File":
#建立目錄
try:
os.mkdir("./recvfiles")
except FileExistsError as e:
pass
f=open("./recvfiles/"+recv_msg["Name"],"wb")
f.write(recv_msg["Content"])
f.close()
filelabel=Label(self.chatmessage_text,fg="yellow",bg="lightblue",text=recv_msg["Name"],font=("宋體",15))
filelabel.bind("<Double-Button-1>",self.open)
self.chatmessage_text.insert(END,"%s %s\n"%(recv_msg["From"],recv_msg["Date"]),"header")
self.chatmessage_text.window_create(END,window=filelabel)
self.chatmessage_text.insert(END,"\n")
elif recv_msg["Type"]=="Status":
status_code=int(recv_msg["Content"].decode())
if status_code==100:
self.info("登陸成功")
elif status_code==101:
self.info("登陸失敗:可能使用者名稱或密碼錯誤")
elif status_code==102:
self.info("沒有登陸")
elif status_code==103:
self.info("已經存在登陸")
elif status_code==200:
self.info("註冊成功")
elif status_code==201:
self.info("註冊失敗")
elif status_code==300:
self.info("傳送成功")
elif status_code==301:
self.info(self.chatwith+"不線上")
elif status_code==302:
self.info("型別錯誤")
elif status_code==303:
self.info("沒有檔名")
elif status_code==400:
self.info("登出成功")
elif status_code==500:
self.chatclient.disconnserver()
self.chatclient=None
elif status_code==600:
self.info("獲取好友列表失敗")
elif status_code==601:
self.info("增加好友成功")
elif status_code==602:
self.info("增加好友失敗")
elif status_code==603:
self.info("刪除好友成功")
elif status_code==604:
self.info("刪除好友失敗")
elif recv_msg["Type"]=="List":
#print("好友數目",recv_msg["Count"])
self.friends_list.delete(0,END)
for friend in recv_msg["Content"].decode().split("\r\n"):
#print("好友:",friend)
self.friends_list.insert(END,friend)
#chatclient info_event 事件處理函式
def info(self,text):
self.chatmessage_text.insert(END,text+"\n","information")
#chatclient out_event事件處理函式
def out(self,recv_msg):
if recv_msg!=None:
#顯示接受資料在終端
#print(recv_msg)
self.parse(recv_msg)
if __name__=="__main__":
MainWindow(sys.argv[1],sys.argv[2]).mainloop()
#! /usr/bin/python3.4
'''
利用Tkinter,Socket,完成一個聊天軟體開發
主要目的作為Tkinter學習的實戰訓練
自定義 chat 協議:
From: 來自 伺服器名為pchatsvr
To: 目標
Date: 時間 eg(20:11:11)
Type: 傳送內容型別:可選["Plain","File","Login","Outlogin","Register","Quit","Status","List","Add","Delete"]
Length: [可選]內容長度, 好友數目時將使用Count,不適用Length
Name:[可選]檔名
Count:[可選]好友數
//空行
...... 主體內容
狀態碼:
100 登陸成功
101 登陸失敗
102 沒有登陸
103 已經存在登陸
200 註冊成功
201 註冊失敗
300 傳送訊息成功
301 To出錯
302 Type出錯
303 Name出錯,當type為File時
400 登出成功
500 離開
600 例舉好友失敗
601 add好友成功
602 add好友失敗
603 delete好友成功
604 delete好友失敗
'''
import socket
import select
import time
import sqlite3
#chat服務類
class ChatServer():
def __init__(self):
self.servername="pchatsvr"
self.serverSock=socket.socket()
self.serverSock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
self.usersdbname="users.db" #使用者資料庫
self.users={} #使用者字典 只有登陸後才會新增 key使用者名稱,value套接字
self.sockets=[] #套接字列表
self.init_db() #初始化資料庫
def init_db(self):
self.conn=sqlite3.connect(database=self.usersdbname)
#使用者表
try:
self.conn.execute("CREATE TABLE USERS(name VARCHAR(20) PRIMARY KEY,password VARCHAR(30) not null)")
except BaseException as e:
#print(e)
pass
#好友表
try:
self.conn.execute("CREATE TABLE FRIENDS(name_1 VARCHAR(20), name_2 VARCHAR(20),FOREIGN KEY(name_1) REFERENCES USERS(name),FOREIGN KEY(name_2) REFERENCES USERS(name))")
except BaseException as e:
#print(e)
pass
#關閉資料庫
def close_db(self):
self.conn.close()
self.conn=None
#判斷使用者知否存在
def has_user_db(self,name,pwd):
try:
r=self.conn.execute("SELECT COUNT(*) FROM USERS WHERE name='%s' AND password='%s'"%(name,pwd))
for row in r:
if row[0]>0:
return True
else:
return False
except BaseException as e:
print(e)
def add_user_db(self,name,pwd):
if self.has_user_db(name,pwd):
return False
else:
try:
self.conn.execute("INSERT INTO USERS VALUES('%s','%s')"%(name,pwd))
self.conn.commit()
return True
except:
return False
def friends_list_db(self,name):
friends=[]
try:
res=self.conn.execute("SELECT name_2 FROM FRIENDS WHERE name_1='%s'"%(name))
for row in res:
friends.append(row[0])
return friends
except BaseException as e:
#print(e)
return None
#增加好友
def friend_add_db(self,name_1,name_2):
try:
self.conn.execute("INSERT INTO FRIENDS VALUES('%s','%s')"%(name_1,name_2))
self.conn.commit()
return True
except:
return False
#刪除好友
def friend_delete_db(self,name_1,name_2):
try:
self.conn.execute("DELETE FROM FRIENDS WHERE name_1='%s' AND name_2='%s'"%(name_1,name_2))
return True
except:
return False
def start(self,hostname="",port=1234,listen_count=2):
self.serverSock.bind((hostname,port))
self.serverSock.listen(listen_count)
self.sockets.append(self.serverSock)
print("啟動pchat服務監聽")
self.__run()
def __select(self):
#作出響應
r_sockets=select.select(self.sockets,[],[])[0]
for sock in r_sockets:
#伺服器套接字
if sock==self.serverSock:
newsock,addr=self.serverSock.accept()
print("accept:",addr)
self.sockets.append(newsock)
else:
recv_msg={}
fileobj=sock.makefile("rb",0)
while True:
try:
line=fileobj.readline()
except:
self.sockets.remove(sock)
sock.close()
return
if not len(line):
self.sockets.remove(sock)
sock.close()
return
if line==b"\r\n":
break
key,value=line.decode().strip().split(": ")
recv_msg[key]=value
length=int(recv_msg["Length"])
recv_msg["Content"]=b""
while length>0:
r=fileobj.read(min(length,1024))
if not len(r):
break
length-=len(r)
recv_msg["Content"]+=r
#print(recv_msg)
fileobj.close()
if recv_msg["Type"]=="Plain" or recv_msg["Type"]=="File":
if recv_msg["From"] not in self.users:
sock.send(("From: "+self.servername+"\r\n").encode())
sock.send(("To: "+recv_msg["From"]+"\r\n").encode())
t=time.localtime()
sock.send(("Date: "+"%d:%d:%d"%(t.tm_hour,t.tm_min,t.tm_sec)+"\r\n").encode())
sock.send("Type: Status\r\n".encode())
sock.send("Length: 3\r\n".encode())
sock.send("\r\n".encode())
sock.send(b"102")
elif recv_msg["To"] not in self.users:
sock.send(("From: "+self.servername+"\r\n").encode())
sock.send(("To: "+recv_msg["From"]+"\r\n").encode())
t=time.localtime()
sock.send(("Date: "+"%d:%d:%d"%(t.tm_hour,t.tm_min,t.tm_sec)+"\r\n").encode())
sock.send("Type: Status\r\n".encode())
sock.send("Length: 3\r\n".encode())
sock.send("\r\n".encode())
sock.send(b"301")
elif self.users[recv_msg["From"]]==sock:
if recv_msg["Type"]=="File" and "Name" not in recv_msg:
sock.send(("From: "+self.servername+"\r\n").encode())
sock.send(("To: "+recv_msg["From"]+"\r\n").encode())
t=time.localtime()
sock.send(("Date: "+"%d:%d:%d"%(t.tm_hour,t.tm_min,t.tm_sec)+"\r\n").encode())
sock.send("Type: Status\r\n".encode())
sock.send("Length: 3\r\n".encode())
sock.send("\r\n".encode())
sock.send(b"303")
else:
sock.send(("From: "+self.servername+"\r\n").encode())
sock.send(("To: "+recv_msg["From"]+"\r\n").encode())
t=time.localtime()
sock.send(("Date: "+"%d:%d:%d"%(t.tm_hour,t.tm_min,t.tm_sec)+"\r\n").encode())
sock.send("Type: Status\r\n".encode())
sock.send("Length: 3\r\n".encode())
sock.send("\r\n".encode())
sock.send(b"300")
#傳送給聊天物件
chatwith_socket=self.users[recv_msg["To"]]
chatwith_socket.send(("From: "+recv_msg["From"]+"\r\n").encode())
chatwith_socket.send(("To: "+recv_msg["To"]+"\r\n").encode())
t=time.localtime()
chatwith_socket.send(("Date: "+"%d:%d:%d"%(t.tm_hour,t.tm_min,t.tm_sec)+"\r\n").encode())
chatwith_socket.send(("Type: "+recv_msg["Type"]+"\r\n").encode())
chatwith_socket.send(("Length: "+recv_msg["Length"]+"\r\n").encode())
if "Name" in recv_msg:
chatwith_socket.send(("Name: "+recv_msg["Name"]+"\r\n").encode())
chatwith_socket.send("\r\n".encode())
chatwith_socket.send(recv_msg["Content"])
else:
sock.send(("From: "+self.servername+"\r\n").encode())
sock.send(("To: "+recv_msg["From"]+"\r\n").encode())
t=time.localtime()
sock.send(("Date: "+"%d:%d:%d"%(t.tm_hour,t.tm_min,t.tm_sec)+"\r\n").encode())
sock.send("Type: Status\r\n".encode())
sock.send("Length: 3\r\n".encode())
sock.send("\r\n".encode())
sock.send(b"103")
elif recv_msg["Type"]=="Login":
name,pwd=recv_msg["Content"].decode().split("&")
if self.has_user_db(name,pwd):
#將使用者加入users中
if name not in self.users:
self.users[name]=sock
sock.send(("From: "+self.servername+"\r\n").encode())
sock.send(("To: "+recv_msg["From"]+"\r\n").encode())
t=time.localtime()
sock.send(("Date: "+"%d:%d:%d"%(t.tm_hour,t.tm_min,t.tm_sec)+"\r\n").encode())
sock.send("Type: Status\r\n".encode())
sock.send("Length: 3\r\n".encode())
sock.send("\r\n".encode())
sock.send(b"100")
else:
sock.send(("From: "+self.servername+"\r\n").encode())
sock.send(("To: "+recv_msg["From"]+"\r\n").encode())
t=time.localtime()
sock.send(("Date: "+"%d:%d:%d"%(t.tm_hour,t.tm_min,t.tm_sec)+"\r\n").encode())
sock.send("Type: Status\r\n".encode())
sock.send("Length: 3\r\n".encode())
sock.send("\r\n".encode())
sock.send(b"103")
else:
sock.send(("From: "+self.servername+"\r\n").encode())
sock.send(("To: "+recv_msg["From"]+"\r\n").encode())
t=time.localtime()
sock.send(("Date: "+"%d:%d:%d"%(t.tm_hour,t.tm_min,t.tm_sec)+"\r\n").encode())
sock.send("Type: Status\r\n".encode())
sock.send("Length: 3\r\n".encode())
sock.send("\r\n".encode())
sock.send(b"101")
elif recv_msg["Type"]=="Register":
name,pwd=name,pwd=recv_msg["Content"].decode().split("&")
if self.add_user_db(name,pwd):
sock.send(("From: "+self.servername+"\r\n").encode())
sock.send(("To: "+recv_msg["From"]+"\r\n").encode())
t=time.localtime()
sock.send(("Date: "+"%d:%d:%d"%(t.tm_hour,t.tm_min,t.tm_sec)+"\r\n").encode())
sock.send("Type: Status\r\n".encode())
sock.send("Length: 3\r\n".encode())
sock.send("\r\n".encode())
sock.send(b"200")
else:
sock.send(("From: "+self.servername+"\r\n").encode())
sock.send(("To: "+recv_msg["From"]+"\r\n").encode())
t=time.localtime()
sock.send(("Date: "+"%d:%d:%d"%(t.tm_hour,t.tm_min,t.tm_sec)+"\r\n").encode())
sock.send("Type: Status\r\n".encode())
sock.send("Length: 3\r\n".encode())
sock.send("\r\n".encode())
sock.send(b"201")
elif recv_msg["Type"]=="Outlogin":
if recv_msg["From"] not in self.users:
#沒有登陸
sock.send(("From: "+self.servername+"\r\n").encode())
sock.send(("To: "+recv_msg["From"]+"\r\n").encode())
t=time.localtime()
sock.send(("Date: "+"%d:%d:%d"%(t.tm_hour,t.tm_min,t.tm_sec)+"\r\n").encode())
sock.send("Type: Status\r\n".encode())
sock.send("Length: 3\r\n".encode())
sock.send("\r\n".encode())
sock.send(b"102")
elif self.users[recv_msg["From"]]==sock:
self.users.pop(recv_msg["From"])
sock.send(("From: "+self.servername+"\r\n").encode())
sock.send(("To: "+recv_msg["From"]+"\r\n").encode())
t=time.localtime()
sock.send(("Date: "+"%d:%d:%d"%(t.tm_hour,t.tm_min,t.tm_sec)+"\r\n").encode())
sock.send("Type: Status\r\n".encode())
sock.send("Length: 3\r\n".encode())
sock.send("\r\n".encode())
sock.send(b"400")
else:
sock.send(("From: "+self.servername+"\r\n").encode())
sock.send(("To: "+recv_msg["From"]+"\r\n").encode())
t=time.localtime()
sock.send(("Date: "+"%d:%d:%d"%(t.tm_hour,t.tm_min,t.tm_sec)+"\r\n").encode())
sock.send("Type: Status\r\n".encode())
sock.send("Length: 3\r\n".encode())
sock.send("\r\n".encode())
sock.send(b"103")
elif recv_msg["Type"]=="Quit":
if recv_msg["From"] in self.users and self.users[recv_msg["From"]]==sock:
self.users.pop(recv_msg["From"])
sock.send(("From: "+self.servername+"\r\n").encode())
sock.send(("To: "+recv_msg["From"]+"\r\n").encode())
t=time.localtime()
sock.send(("Date: "+"%d:%d:%d"%(t.tm_hour,t.tm_min,t.tm_sec)+"\r\n").encode())
sock.send("Type: Status\r\n".encode())
sock.send("Length: 3\r\n".encode())
sock.send("\r\n".encode())
sock.send(b"500")
self.sockets.remove(sock)
sock.close()
elif recv_msg["Type"]=="List":
if not(recv_msg["From"] in self.users):
#沒有登陸
sock.send(("From: "+self.servername+"\r\n").encode())
sock.send(("To: "+recv_msg["From"]+"\r\n").encode())
t=time.localtime()
sock.send(("Date: "+"%d:%d:%d"%(t.tm_hour,t.tm_min,t.tm_sec)+"\r\n").encode())
sock.send("Type: Status\r\n".encode())
sock.send("Length: 3\r\n".encode())
sock.send("\r\n".encode())
sock.send(b"102")
elif sock!=self.users[recv_msg["From"]]:
sock.send(("From: "+self.servername+"\r\n").encode())
sock.send(("To: "+recv_msg["From"]+"\r\n").encode())
t=time.localtime()
sock.send(("Date: "+"%d:%d:%d"%(t.tm_hour,t.tm_min,t.tm_sec)+"\r\n").encode())
sock.send("Type: Status\r\n".encode())
sock.send("Length: 3\r\n".encode())
sock.send("\r\n".encode())
sock.send(b"103")
else:
friends=self.friends_list_db(recv_msg["From"])
if friends==None:
sock.send(("From: "+self.servername+"\r\n").encode())
sock.send(("To: "+recv_msg["From"]+"\r\n").encode())
t=time.localtime()
sock.send(("Date: "+"%d:%d:%d"%(t.tm_hour,t.tm_min,t.tm_sec)+"\r\n").encode())
sock.send("Type: Status\r\n".encode())
sock.send("Length: 3\r\n".encode())
sock.send("\r\n".encode())
sock.send(b"600")
else:
sock.send(("From: "+self.servername+"\r\n").encode())
sock.send(("To: "+recv_msg["From"]+"\r\n").encode())
t=time.localtime()
sock.send(("Date: "+"%d:%d:%d"%(t.tm_hour,t.tm_min,t.tm_sec)+"\r\n").encode())
sock.send("Type: List\r\n".encode())
#sock.send("Length: \r\n".encode())
sock.send(("Count: "+str(len(friends))+"\r\n").encode())
sock.send("\r\n".encode())
for friend in friends:
sock.send((friend+"\r\n").encode())
elif recv_msg["Type"]=="Add":
if not (recv_msg["From"] in self.users):
#沒有登陸
sock.send(("From: "+self.servername+"\r\n").encode())
sock.send(("To: "+recv_msg["From"]+"\r\n").encode())
t=time.localtime()
sock.send(("Date: "+"%d:%d:%d"%(t.tm_hour,t.tm_min,t.tm_sec)+"\r\n").encode())
sock.send("Type: Status\r\n".encode())
sock.send("Length: 3\r\n".encode())
sock.send("\r\n".encode())
sock.send(b"102")
elif sock!=self.users[recv_msg["From"]]:
sock.send(("From: "+self.servername+"\r\n").encode())
sock.send(("To: "+recv_msg["From"]+"\r\n").encode())
t=time.localtime()
sock.send(("Date: "+"%d:%d:%d"%(t.tm_hour,t.tm_min,t.tm_sec)+"\r\n").encode())
sock.send("Type: Status\r\n".encode())
sock.send("Length: 3\r\n".encode())
sock.send("\r\n".encode())
sock.send(b"103")
else:
friend_name=recv_msg["Content"].decode()
if self.friend_add_db(recv_msg["From"],friend_name):
sock.send(("From: "+self.servername+"\r\n").encode())
sock.send(("To: "+recv_msg["From"]+"\r\n").encode())
t=time.localtime()
sock.send(("Date: "+"%d:%d:%d"%(t.tm_hour,t.tm_min,t.tm_sec)+"\r\n").encode())
sock.send("Type: Status\r\n".encode())
sock.send("Length: 3\r\n".encode())
sock.send("\r\n".encode())
sock.send(b"601")
else:
sock.send(("From: "+self.servername+"\r\n").encode())
sock.send(("To: "+recv_msg["From"]+"\r\n").encode())
t=time.localtime()
sock.send(("Date: "+"%d:%d:%d"%(t.tm_hour,t.tm_min,t.tm_sec)+"\r\n").encode())
sock.send("Type: Status\r\n".encode())
sock.send("Length: 3\r\n".encode())
sock.send("\r\n".encode())
sock.send(b"602")
elif recv_msg["Type"]=="Delete":
if not(recv_msg["From"] in self.users):
#沒有登陸
sock.send(("From: "+self.servername+"\r\n").encode())
sock.send(("To: "+recv_msg["From"]+"\r\n").encode())
t=time.localtime()
sock.send(("Date: "+"%d:%d:%d"%(t.tm_hour,t.tm_min,t.tm_sec)+"\r\n").encode())
sock.send("Type: Status\r\n".encode())
sock.send("Length: 3\r\n".encode())
sock.send("\r\n".encode())
sock.send(b"102")
elif sock!=self.users[recv_msg["From"]]:
sock.send(("From: "+self.servername+"\r\n").encode())
sock.send(("To: "+recv_msg["From"]+"\r\n").encode())
t=time.localtime()
sock.send(("Date: "+"%d:%d:%d"%(t.tm_hour,t.tm_min,t.tm_sec)+"\r\n").encode())
sock.send("Type: Status\r\n".encode())
sock.send("Length: 3\r\n".encode())
sock.send("\r\n".encode())
sock.send(b"103")
else:
friend_name=recv_msg["Content"].decode()
if self.friend_delete_db(recv_msg["From"],friend_name):
sock.send(("From: "+self.servername+"\r\n").encode())
sock.send(("To: "+recv_msg["From"]+"\r\n").encode())
t=time.localtime()
sock.send(("Date: "+"%d:%d:%d"%(t.tm_hour,t.tm_min,t.tm_sec)+"\r\n").encode())
sock.sezhaond("Type: Status\r\n".encode())
sock.send("Length: 3\r\n".encode())
sock.send("\r\n".encode())
sock.send(b"603")
else:
sock.send(("From: "+self.servername+"\r\n").encode())
sock.send(("To: "+recv_msg["From"]+"\r\n").encode())
t=time.localtime()
sock.send(("Date: "+"%d:%d:%d"%(t.tm_hour,t.tm_min,t.tm_sec)+"\r\n").encode())
sock.send("Type: Status\r\n".encode())
sock.send("Length: 3\r\n".encode())
sock.send("\r\n".encode())
sock.send(b"604")
def __run(self):
while True:
try:
self.__select()
except KeyboardInterrupt as e:
self.close_db()
print("關閉pchat服務")
break
if __name__=="__main__":
ChatServer().start()
'''
自己實現popen和system,學習fork dup pipe exec 等等內容。
'''
import os
#採用雙管道實現popen:dopen 這是HTTP中CGI的核心內容
def dopen(command):
f_read,s_write=os.pipe()
s_read,f_write=os.pipe()
spid=os.fork()
if spid<0:
return -1,-1
elif spid==0:
os.close(f_read)
os.close(f_write)
os.dup2(s_read,0)
os.dup2(s_write,1)
command_list=command.split(" ")
os.execv(command_list[0],command_list)
else:
os.close(s_read)
os.close(s_write)
return f_read,f_write
#模擬os.popen
def popen(command):
#建立管道
read_p,write_p=os.pipe()
spid=os.fork()
if spid<0:
return -1
elif spid==0:
#子程序
#關閉讀埠
os.close(read_p)
os.dup2(write_p,1)
command_list=command.split(" ")
#替換子程序
os.execv(command_list[0],command_list)
else:
#父程序
os.close(write_p)
#返回管道讀端
return read_p
#模擬os.system
def system(command):
spid=os.fork()
if spid<0:
return -1
elif spid==0:
command_list=command.split(" ")
os.execv(command_list[0],command_list)
else:
pass
if __name__=="__main__":
#dopen測試
r,w=dopen("/usr/bin/python3.4 test.py")
os.write(w,"hello world\n".encode())
while r>0:
content=os.read(r,1024)
if not len(content):
break
print(content.decode(),end="")
os.close(r)
#system測試#system("/usr/bin/xdg-open /home/qin/Documents/chat/chatclient.py")