[Python 網絡編程] TCP Client (四)
阿新 • • 發佈:2017-12-24
utf8 config readn ogg enum target 一個 net t對象
TCP Client
- 客戶端編程步驟:
- 創建socket對象
- 連接到服務端的ip和port,connect()方法
- 傳輸數據
- 使用send、recv方法發送、接收數據
- 關閉連接,釋放資源
最簡單的客戶端:
#TCP Client客戶端 import socket client = socket.socket() client.connect((‘127.0.0.1‘,9999)) client.send("Hi, I‘m client1.".encode()) client.close() #運行
服務端狀態:
[16:08:25] [showthreads,1796] [<_MainThread(MainThread, started 9816)>, <Thread(show_client, started daemon 9344)>, <Thread(accept, started daemon 5908)>, <Thread(showthreads, started 1796)>] [16:08:26] [accept,5908] <socket.socket fd=424, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=(‘127.0.0.1‘, 9999), raddr=(‘127.0.0.1‘, 5287)>-(‘127.0.0.1‘, 5287) [16:08:26] [show_client,9344] {(‘127.0.0.1‘, 5287): <_io.TextIOWrapper mode=‘rw‘ encoding=‘utf8‘>} 2017/12/24 16:08:26 127.0.0.1:5287 Hi, I‘m client1. [16:08:26] [recv,980] 2017/12/24 16:08:26 127.0.0.1:5287 Hi, I‘m client1. [16:08:26] [recv,980] (‘127.0.0.1‘, 5287) quit [16:08:28] [showthreads,1796] [<_MainThread(MainThread, started 9816)>, <Thread(show_client, started daemon 9344)>, <Thread(accept, started daemon 5908)>, <Thread(showthreads, started 1796)>]
將上面的TCP Client封裝成類:
1)搭架子
#TCP Client客戶端 封裝成類 import socket class ChatClient: def __init__(self): pass def start(self): pass def _recv(self): pass def send(self): pass def stop(self): pass
2)基礎功能
客戶端:
#TCP Client客戶端 封裝成類 import socket,threading,logging,datetime DATEFMT="%H:%M:%S" FORMAT = "[%(asctime)s]\t [%(threadName)s,%(thread)d] %(message)s" logging.basicConfig(level=logging.INFO,format=FORMAT,datefmt=DATEFMT) class ChatClient: def __init__(self,ip=‘127.0.0.1‘,port=9999): self.sock = socket.socket() self.addr = (ip,port) self.event = threading.Event() self.start() def start(self): self.sock.connect(self.addr) # 準備接收數據,recv是阻塞的,啟動新的線程 threading.Thread(target=self._recv,name=‘recv‘).start() def _recv(self): while not self.event.is_set(): try: data = self.sock.recv(1024) #阻塞 except Exception as e: logging.info(e) #有任何異常保證退出 break msg = "{:%H:%M:%S} {}:{}\n{}\n".format(datetime.datetime.now(),*self.addr,data.decode().strip()) # print(type(msg),msg) logging.info("{}".format(data.decode())) def send(self,msg:str): data = "{}\n".format(msg.strip()).encode() self.sock.send(data) def stop(self): logging.info("{} broken".format(self.addr)) self.sock.close() self.event.wait(3) self.event.set() logging.info("byebye") def main(): e = threading.Event() cc = ChatClient() while True: msg = input(">>> ") if msg.strip() == ‘quit‘: cc.stop() break cc.send(msg) if __name__ == ‘__main__‘: main()
服務端:
#TCP Server 改裝成makefile import threading,logging,time,random,datetime,socket DATEFMT="%H:%M:%S" FORMAT = "[%(asctime)s]\t [%(threadName)s,%(thread)d] %(message)s" logging.basicConfig(level=logging.INFO,format=FORMAT,datefmt=DATEFMT) class ChatServer: def __init__(self,ip=‘127.0.0.1‘,port=9999): #啟動服務 self.addr = (ip,port) self.sock = socket.socket() self.event = threading.Event() self.clients = {} #客戶端 def show_client(self): while not self.event.is_set(): if len(self.clients) > 0: logging.info(self.clients) self.event.wait(3) def start(self): self.sock.bind(self.addr) self.sock.listen() # accept會阻塞主線程,所以開一個新線程 threading.Thread(target=self._accept,name=‘accept‘,daemon=True).start() threading.Thread(target=self.show_client,name=‘show_client‘,daemon=True).start() def stop(self): for c in self.clients.values(): c.close() self.sock.close() self.event.wait(3) self.event.set() def _accept(self): while not self.event.is_set(): #多人連接 conn,client = self.sock.accept() #阻塞 f = conn.makefile(mode=‘rw‘) self.clients[client] = f logging.info("{}-{}".format(conn,client)) # recv 默認阻塞,每一個連接單獨起一個recv線程準備接收數據 threading.Thread(target=self._recv, args=(f, client), name=‘recv‘,daemon=True).start() def _recv(self, f, client): #接收客戶端數據 while not self.event.is_set(): try: data = f.readline() except Exception: data = ‘quit‘ finally: msg = data.strip() # Client通知退出機制 if msg == ‘quit‘: f.close() self.clients.pop(client) logging.info(‘{} quit‘.format(client)) break msg = "{:%Y/%m/%d %H:%M:%S} {}:{}\n{}\n".format(datetime.datetime.now(),*client,data) # msg = data print(msg) logging.info(msg) for c in self.clients.values(): # print(type(msg)) c.writelines(msg) c.flush() cs = ChatServer() print(‘!!!!!!!!!!!‘) cs.start() print(‘~~~~~~~~~~~~~~~~~~~~‘) e = threading.Event() def showthreads(e:threading.Event): while not e.wait(3): logging.info(threading.enumerate()) threading.Thread(target=showthreads,name=‘showthreads‘,args=(e,)).start() while not e.wait(1): # Sever控制臺退出方式 cmd = input(‘>>> ‘).strip() if cmd == ‘quit‘: cs.stop() e.wait(3) break
運行結果:
#服務端 ~~~~~~~~~~~~~~~~~~~~ >>> [17:26:14] [show_client,7824] {(‘127.0.0.1‘, 7517): <_io.TextIOWrapper mode=‘rw‘ encoding=‘cp936‘>} [17:26:14] [accept,3832] <socket.socket fd=400, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=(‘127.0.0.1‘, 9999), raddr=(‘127.0.0.1‘, 7517)>-(‘127.0.0.1‘, 7517) [17:26:15] [showthreads,5928] [<Thread(accept, started daemon 3832)>, <Thread(show_client, started daemon 7824)>, <Thread(recv, started daemon 2112)>, <_MainThread(MainThread, started 7412)>, <Thread(showthreads, started 5928)>] [17:26:17] [show_client,7824] {(‘127.0.0.1‘, 7517): <_io.TextIOWrapper mode=‘rw‘ encoding=‘cp936‘>} [17:26:18] [showthreads,5928] [<Thread(accept, started daemon 3832)>, <Thread(show_client, started daemon 7824)>, <Thread(recv, started daemon 2112)>, <_MainThread(MainThread, started 7412)>, <Thread(showthreads, started 5928)>] [17:26:19] [recv,2112] 2017/12/24 17:26:19 127.0.0.1:7517 hello1 2017/12/24 17:26:19 127.0.0.1:7517 hello1 [17:26:20] [show_client,7824] {(‘127.0.0.1‘, 7517): <_io.TextIOWrapper mode=‘rw‘ encoding=‘cp936‘>} [17:26:21] [showthreads,5928] [<Thread(accept, started daemon 3832)>, <Thread(show_client, started daemon 7824)>, <Thread(recv, started daemon 2112)>, <_MainThread(MainThread, started 7412)>, <Thread(showthreads, started 5928)>] [17:26:23] [show_client,7824] {(‘127.0.0.1‘, 7517): <_io.TextIOWrapper mode=‘rw‘ encoding=‘cp936‘>} [17:26:23] [accept,3832] <socket.socket fd=436, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=(‘127.0.0.1‘, 9999), raddr=(‘127.0.0.1‘, 7539)>-(‘127.0.0.1‘, 7539) [17:26:24] [showthreads,5928] [<Thread(show_client, started daemon 7824)>, <Thread(recv, started daemon 2112)>, <_MainThread(MainThread, started 7412)>, <Thread(accept, started daemon 3832)>, <Thread(recv, started daemon 6748)>, <Thread(showthreads, started 5928)>] 2017/12/24 17:26:25 127.0.0.1:7539 [17:26:25] [recv,6748] 2017/12/24 17:26:25 127.0.0.1:7539 hello2 hello2 [17:26:26] [show_client,7824] {(‘127.0.0.1‘, 7517): <_io.TextIOWrapper mode=‘rw‘ encoding=‘cp936‘>, (‘127.0.0.1‘, 7539): <_io.TextIOWrapper mode=‘rw‘ encoding=‘cp936‘>} [17:26:27] [showthreads,5928] [<Thread(show_client, started daemon 7824)>, <Thread(recv, started daemon 2112)>, <_MainThread(MainThread, started 7412)>, <Thread(accept, started daemon 3832)>, <Thread(recv, started daemon 6748)>, <Thread(showthreads, started 5928)>] [17:26:29] [show_client,7824] {(‘127.0.0.1‘, 7517): <_io.TextIOWrapper mode=‘rw‘ encoding=‘cp936‘>, (‘127.0.0.1‘, 7539): <_io.TextIOWrapper mode=‘rw‘ encoding=‘cp936‘>} [17:26:30] [showthreads,5928] [<Thread(show_client, started daemon 7824)>, <Thread(recv, started daemon 2112)>, <_MainThread(MainThread, started 7412)>, <Thread(accept, started daemon 3832)>, <Thread(recv, started daemon 6748)>, <Thread(showthreads, started 5928)>] [17:26:32] [show_client,7824] {(‘127.0.0.1‘, 7517): <_io.TextIOWrapper mode=‘rw‘ encoding=‘cp936‘>, (‘127.0.0.1‘, 7539): <_io.TextIOWrapper mode=‘rw‘ encoding=‘cp936‘>} [17:26:33] [showthreads,5928] [<Thread(show_client, started daemon 7824)>, <Thread(recv, started daemon 2112)>, <_MainThread(MainThread, started 7412)>, <Thread(accept, started daemon 3832)>, <Thread(recv, started daemon 6748)>, <Thread(showthreads, started 5928)>] [17:26:35] [show_client,7824] {(‘127.0.0.1‘, 7517): <_io.TextIOWrapper mode=‘rw‘ encoding=‘cp936‘>, (‘127.0.0.1‘, 7539): <_io.TextIOWrapper mode=‘rw‘ encoding=‘cp936‘>} [17:26:36] [showthreads,5928] [<Thread(show_client, started daemon 7824)>, <Thread(recv, started daemon 2112)>, <_MainThread(MainThread, started 7412)>, <Thread(accept, started daemon 3832)>, <Thread(recv, started daemon 6748)>, <Thread(showthreads, started 5928)>]
#客戶端1 >>> hello1 [17:26:19] [recv,2604] 2017/12/24 17:26:19 127.0.0.1:7517 hello1 >>> [17:26:25] [recv,2604] 2017/12/24 17:26:25 127.0.0.1:7539 hello2 [17:26:37] [recv,2604] [WinError 10054] 遠程主機強迫關閉了一個現有的連接。
#客戶端2 >>> hello2 >>> [17:26:25] [recv,4044] 2017/12/24 17:26:25 127.0.0.1:7539 hello2 [17:26:37] [recv,4044] [WinError 10054] 遠程主機強迫關閉了一個現有的連接。
以上例子在客戶端,如果服務端主動斷開,客戶端需要異常處理。
[Python 網絡編程] TCP Client (四)