Python Socket實現簡單的聊天室


通過參考其他牛人的文章和代碼,  再根據自己的理解總結得出,  說明已經加在注釋中, FYI

主要參考文章: http://blog.csdn.net/dk_zhe/article/details/37820965

        http://www.cnblogs.com/coser/archive/2012/01/06/2315216.html

        https://docs.python.org/2.7/library/select.html?highlight=select#module-select

        http://www.cnblogs.com/devinzhang/archive/2012/01/13/2321826.html

        http://blog.chinaunix.net/uid-23146151-id-3084687.html

 

server.py    和   client.py

#coding=utf-8
# 通過socket建立網絡連接的步驟:
# 至少需要2個套接字, server和client
# 需要建立socket之間的連接, 通過連接來進行收發data
# client 和 server連接的過程:
# 1. 建立server的套接字,綁定主機和端口,並監聽client的連接請求
# 2. client套接字根據server的地址發出連接請求, 連接到server的socket上; client socket需要提供自己的 socket fd,以便server socket回應
# 3. 當server監聽到client連接請求時, 響應請求, 建立一個新的線程, 把server fd 發送給client
# 而后, server繼續監聽其他client請求, 而client和server通過socket連接互發data通信
import socket,select,thread

host = socket.gethostname()
port = 5963
server_addr = (host,port)

# waitable的read list, 表示異步通信中可讀socket對象的列表
inputs = []
# 連接進入server的client的名稱
fd_name = {}

# 創建並初始化server socket
def serverInit():
    ss = socket.socket()  # 創建server socket
    ss.bind(server_addr)  # 綁定到server addr
    ss.listen(10)          # 監聽端口號, 設置最大監聽數10
    return ss             # 返回初始化后的server socket

# 創建一個新的socket連接
def newConnection(ss):
    client_conn,client_addr = ss.accept()  # 響應一個client的連接請求, 建立一個連接,可以用來傳輸數據
    try:
        # 向client端發送歡迎信息
        client_conn.send("welcome to chatroom,pls set up your nick name!")
        client_name = client_conn.recv(1024) #接收client發來的昵稱,最大接收字符為1024
        inputs.append(client_conn)
        fd_name[client_conn] = client_name  # 將連接/連接名 加入鍵值對
        client_conn.send("current members in chatroom are: %s" % fd_name.values())
        # 向所有連接發送新成員加入信息
        for other in fd_name.keys():
            if other != client_conn and other != ss:
                other.send(fd_name[client_conn]+" joined the chatroom!")
    except Exception as e:
        print e

def closeConnection():
    pass

def run():
    ss = serverInit()
    inputs.append(ss)
    print "server is running..."
    while True:
        # rlist,wlist,elist = select.select(inputs, [], inputs,100)   # 如果只是服務器開啟,100s之內沒有client連接,則也會超時關閉
        rlist,wlist,elist = select.select(inputs, [], [])
        # 當沒有可讀fd時, 表示server錯誤,退出服務器
        if not rlist:
            print "timeout..."
            ss.close()  # 關閉 server socket
            break
        for r in rlist:
            if r is ss:  # server socket, 表示有新的client連接請求
                newConnection(ss)
            else:          # 表示一個client連接上有數據到達服務器
                disconnect = False
                try:
                    data = r.recv(1024)  #接收data
                    data = fd_name[r] + " : "+ data  # 確定客戶端昵稱
                except socket.error:
                    data = fd_name[r] + " leaved the room"
                    disconnect = True
                else:
                    pass
                if disconnect:
                    inputs.remove(r)
                    print data
                    for other in inputs:
                        if other != ss and other != r:  #不發生到服務器和已經斷開的連接
                            try:
                                other.send(data)
                            except Exception as e:
                                print e
                            else:
                                pass
                    # 除名
                    del fd_name[r]
                else:
                    print data  # 在服務器顯示client發送的數據
                    # 向其他成員(連接)發送相同的信息
                    for other in inputs:
                        if other != ss and other != r:
                            try:
                                other.send(data)
                            except Exception as e:
                                print e
if __name__ == "__main__":
    run()
#coding=utf-8
# 由於實驗都在本機上運行, 所以server addr == client addr
import socket,select,threading,sys
host = socket.gethostname()
client_addr = (host,5963)  # equals server_addr()

# 傾聽其他成員談話
def listening(cs):
    inputs = [cs]
    while True:
        rlist,wlist,elist = select.select(inputs, [], [])
        # client socket就是用來收發數據的, 由於只有這個waitable 對象, 所以不必迭代
        if cs in rlist:
            try:
                # 打印從服務器收到的數據
                print cs.recv(1024)
            except socket.error:
                print "socket is error"
                exit()

# 發言
def speak(cs):
    while True:
        try:
            data = raw_input()
        except Exception as e:
            print r"can't input"
            exit()
        # if data == "exit":
        #     cs.close()
        #     break
        try:
            cs.send(data)
        except Exception as e:
            exit()


def main():
    # client socket
    cs = socket.socket()
    cs.connect(client_addr)
    # 分別啟動聽和說線程
    t = threading.Thread(target=listening,args=(cs,))  # 注意當元組中只有一個元素的時候需要這樣寫, 否則會被認為是其原來的類型
    t.start()

    t1 = threading.Thread(target=speak,args=(cs,))
    t1.start()

if __name__ == "__main__":
    main()

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM