1. 程式人生 > >python版 聊天軟體

python版 聊天軟體

#! /usr/bin/python3.4

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