單進程-非阻塞服務器
阿新 • • 發佈:2017-07-16
imp conn while blog cnblogs 發生 n) client drl
from socket import * #1.創建socket serSocket = socket(AF_INET, SOCK_STREAM) #2. 綁定本地ip以及port localAddr = (‘‘, 7788) serSocket.bind(localAddr) #3. 讓這個socket 變為非堵塞 serSocket.setblocking(False) #4. 將socket變為監聽(被動)套接字 serSocket.listen(100) # 用來保存所有已經連接的客戶端的信息 clientAddrList = [] while True: #等待一個新的客戶端的到來(即完成3次握手的客戶端)try: clientSocket,clientAddr = serSocket.accept() except: pass else: print("一個新的客戶端到來:%s"%str(clientAddr)) clientSocket.setblocking(False) clientAddrList.append((clientSocket,clientAddr)) for clientSocket,clientAddr in clientAddrList:try: recvData = clientSocket.recv(1024) except: pass else: if len(recvData)>0: print("%s:%s"%(str(clientAddr), recvData)) else: clientSocket.close() clientAddrList.remove((clientSocket, clientAddr))print("%s 已經下線"%str(clientAddr))
select,輪詢最多可監聽1024個人,poll無默認值,但是也是輪詢
import select import socket import sys server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind((‘‘, 7788)) server.listen(5) inputs = [server, sys.stdin] running = True while True: # 調用 select 函數,阻塞等待 readable, writeable, exceptional = select.select(inputs, [], []) # 數據抵達,循環 for sock in readable: # 監聽到有新的連接 if sock == server: conn, addr = server.accept() # select 監聽的socket inputs.append(conn) # 監聽到鍵盤有輸入 elif sock == sys.stdin: cmd = sys.stdin.readline() running = False break # 有數據到達 else: # 讀取客戶端連接發送的數據 data = sock.recv(1024) if data: sock.send(data) else: # 移除select監聽的socket inputs.remove(sock) sock.close() # 如果檢測到用戶輸入敲擊鍵盤,那麽就退出 if not running: break server.close()
epoll非輪詢,無限制,事件通知機制
- EPOLLIN (可讀)
- EPOLLOUT (可寫)
- EPOLLET (ET模式)
epoll對文件描述符的操作有兩種模式:LT(level trigger)和ET(edge trigger)。LT模式是默認模式,LT模式與ET模式的區別如下:
LT模式:當epoll檢測到描述符事件發生並將此事件通知應用程序,應用程序可以不立即處理該事件。下次調用epoll時,會再次響應應用程序並通知此事件。
ET模式:當epoll檢測到描述符事件發生並將此事件通知應用程序,應用程序必須立即處理該事件。如果不處理,下次調用epoll時,不會再次響應應用程序並通知此事件。
import socket import select # 創建套接字 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 設置可以重復使用綁定的信息 s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) # 綁定本機信息 s.bind(("",7788)) # 變為被動 s.listen(10) # 創建一個epoll對象 epoll=select.epoll() # 測試,用來打印套接字對應的文件描述符 # print s.fileno() # print select.EPOLLIN|select.EPOLLET # 註冊事件到epoll中 # epoll.register(fd[, eventmask]) # 註意,如果fd已經註冊過,則會發生異常 # 將創建的套接字添加到epoll的事件監聽中 epoll.register(s.fileno(),select.EPOLLIN|select.EPOLLET) connections = {} addresses = {} # 循環等待客戶端的到來或者對方發送數據 while True: # epoll 進行 fd 掃描的地方 -- 未指定超時時間則為阻塞等待 epoll_list=epoll.poll() # 對事件進行判斷 for fd,events in epoll_list: # print fd # print events # 如果是socket創建的套接字被激活 if fd == s.fileno(): conn,addr=s.accept() print(‘有新的客戶端到來%s‘%str(addr)) # 將 conn 和 addr 信息分別保存起來 connections[conn.fileno()] = conn addresses[conn.fileno()] = addr # 向 epoll 中註冊 連接 socket 的 可讀 事件 epoll.register(conn.fileno(), select.EPOLLIN | select.EPOLLET) elif events == select.EPOLLIN: # 從激活 fd 上接收 recvData = connections[fd].recv(1024) if len(recvData)>0: print(‘recv:%s‘%recvData) else: # 從 epoll 中移除該 連接 fd epoll.unregister(fd) # server 側主動關閉該 連接 fd connections[fd].close() print("%s---offline---"%str(addresses[fd]))
單進程-非阻塞服務器