Unix/Linux操做系統提供了一個
fork()
系統調用,它很是特殊。普通的函數調用,調用一次,返回一次,服務器可是
fork()
調用一次,返回兩次,由於操做系統自動把當前進程(稱爲父進程)複製了一份(稱爲子進程),而後,分別在父進程和子進程內返回。網絡子進程永遠返回
0
,而父進程返回子進程的ID。這樣作的理由是,一個父進程能夠fork出不少子進程,因此,socket父進程要記下每一個子進程的ID,而子進程只須要調用
getppid()
就能夠拿到父進程的ID。函數Python的
os
模塊封裝了常見的系統調用,其中就包括fork
,能夠在Python程序中輕鬆建立子進程ui
1.須要 將要作的事情封裝 爲函數2.使用multiprocessing提供的 process 建立進程對象3.經過進程對象和process初始化進程進行 進程的設置, 綁定函數4. 啓動進程,會 自動執行綁定的函數5 .完成進程的回收
from socket import * import os, sys # 發送管理員消息 def do_child(s, addr): while True: msg = input("管理員消息:") msg = "C 管理員 " + msg s.sendto(msg.encode(), addr) # 用戶登陸 def do_login(s, user, name, addr): if (name in user) or name == "管理員": s.sendto("該用戶已存在".encode(), addr) return s.sendto(b'OK', addr) # 通知全部人 msg = "\n歡迎 %s 進入聊天室" % name for i in user: s.sendto(msg.encode(), user[i]) # 插入user user[name] = addr def do_chat(s, user, name, data): msg = "\n{} 說: {}".format(name, data) for i in user: if i != name: s.sendto(msg.encode(), user[i]) def do_quit(s, user, name): msg = "\n%s 離開了聊天室" % name for i in user: if i == name: s.sendto(b'EXIT', user[i]) else: s.sendto(msg.encode(), user[i]) del user[name] # 刪除離開的用戶 # 接收客戶端請求並處理 def do_parent(s): # 用於存儲用戶 {'Alex':('127.0.0.1',8888)} user = {} while True: msg, addr = s.recvfrom(1024) msgList = msg.decode().split(' ') if msgList[0] == 'L': do_login(s, user, msgList[1], addr) elif msgList[0] == 'C': # "C Levi [I miss you]" data = ' '.join(msgList[2:]) do_chat(s, user, msgList[1], data) elif msgList[0] == 'Q': do_quit(s, user, msgList[1]) # 建立套接字,網絡鏈接,建立父子進程 def main(): # server address ADDR = ('0.0.0.0', 8888) # 建立套接字 s = socket(AF_INET, SOCK_DGRAM) s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) s.bind(ADDR) # 建立父子進程 pid = os.fork() if pid < 0: sys.exit("建立進程失敗") elif pid == 0: do_child(s, ADDR) else: do_parent(s) if __name__ == "__main__": main()
from socket import * import sys, os def login(s, ADDR): while True: name = input("請輸入用戶名:") msg = "L " + name s.sendto(msg.encode(), ADDR) # 接收登陸結果 data, addr = s.recvfrom(1024) if data.decode() == 'OK': print("@進入聊天室@") return name else: print(data.decode()) # 發送消息 def do_child(s, name, addr): while True: text = input("發言(quit退出):") # 退出 if text.strip() == "quit": msg = "Q " + name s.sendto(msg.encode(), addr) sys.exit("退出聊天室") msg = "C %s %s" % (name, text) s.sendto(msg.encode(), addr) # 接收消息 def do_parent(s): while True: msg, addr = s.recvfrom(1024) if msg.decode() == 'EXIT': sys.exit(0) print(msg.decode() + "\n發言(quit退出):",end="") # main控制套接字的建立 def main(): if len(sys.argv) < 3: print("argv is error") return HOST = sys.argv[1] PORT = int(sys.argv[2]) ADDR = (HOST, PORT) s = socket(AF_INET, SOCK_DGRAM) name = login(s, ADDR) if name: pid = os.fork() if pid < 0: sys.exit("建立子進程失敗") elif pid == 0: do_child(s, name, ADDR) else: do_parent(s) else: return if __name__ == "__main__": main()