1、Socket介紹html
網絡上的兩個程序經過一個雙向的通訊鏈接實現數據的交換,這個鏈接的一端稱爲一個socket。python
socket一般也稱做"套接字",用於描述IP地址和端口,是一個通訊鏈的句柄,應用程序一般經過"套接字"向網絡發出請求或者應答網絡請求。web
socket起源於Unix,而Unix/Linux基本哲學之一就是「一切皆文件」,對於文件用【打開】【讀寫】【關閉】模式來操做。socket就是該模式的一個實現,socket便是一種特殊的文件,一些socket函數就是對其進行的操做(讀/寫IO、打開、關閉)瀏覽器
socket和file的區別:bash
1 #! /usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 import socket 5 6 ip_port = ('127.0.0.1', 9998) 7 8 sk = socket.socket() # 生成一個socket句柄,默認tcp/ip 9 sk.bind(ip_port) # 綁定IP和端口 10 sk.listen(5) # 最多容許5個鏈接 11 12 while True: 13 print('server waiting...') 14 conn, address = sk.accept() # 等待鏈接進來,若是沒有就一直等着(阻塞狀態) 15 # conn是客戶端實例 16 17 client_data = conn.recv(1024) 18 print(str(client_data, 'utf8')) 19 conn.sendall(bytes("不要回答,不要回答,不要回答", 'utf8')) 20 21 conn.close()
1 #! /usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 import socket 5 ip_port = ('127.0.0.1', 9998) 6 7 sk = socket.socket() # 生成一個socket句柄,默認tcp/ip 8 sk.connect(ip_port) # 鏈接服務器 9 10 sk.sendall(bytes("請求佔領地球", 'utf8')) 11 12 server_reply = sk.recv(1024) # 接收1024個字節 13 print(str(server_reply, 'utf8')) 14 15 sk.close()
基於socket的web服務器服務器
網絡通訊的三要素是IP地址、端口號和傳輸協議,IP地址用來標識網絡上一臺獨立的主機,端口號用來標識進程的邏輯地址,傳輸協議定義通信的規則。咱們能夠利用ip地址+協議+端口號惟一標示網絡中的一個進程。可以惟一標示網絡中的進程後,它們就能夠利用socket進行通訊了。Web應用的本質其實就是一個socket服務端,用戶的瀏覽器就是一個socket客戶端。 網絡
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 import socket 5 6 def handle_request(client): 7 buf = client.recv(1024) 8 client.send(bytes("HTTP/1.1 200 OK\r\n\r\n", 'utf8')) 9 client.send(bytes("Hello, World", 'utf8')) 10 11 def main(): 12 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 13 sock.bind(('localhost', 8080)) 14 sock.listen(5) 15 16 while True: 17 print('server waiting...') 18 connection, address = sock.accept() 19 handle_request(connection) 20 connection.close() 21 22 if __name__ == '__main__': 23 main()
更多功能多線程
sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)併發
參數一:地址簇 socket.AF_INET IPv4(默認) socket.AF_INET6 IPv6 socket.AF_UNIX 只可以用於單一的Unix系統進程間通訊 參數二:類型 socket.SOCK_STREAM 流式socket , for TCP (默認) socket.SOCK_DGRAM 數據報式socket , for UDP socket.SOCK_RAW 原始套接字,普通的套接字沒法處理ICMP、IGMP等網絡報文,而SOCK_RAW能夠;其次,SOCK_RAW也能夠處理特殊的IPv4報文;此外,利用原始套接字,能夠經過IP_HDRINCL套接字選項由用戶構造IP頭。 socket.SOCK_RDM 是一種可靠的UDP形式,即保證交付數據報但不保證順序。SOCK_RAM用來提供對原始協議的低級訪問,在須要執行某些特殊操做時使用,如發送ICMP報文。SOCK_RAM一般僅限於高級用戶或管理員運行的程序使用。 socket.SOCK_SEQPACKET 可靠的連續數據包服務 參數三:協議 0 (默認)與特定的地址家族相關的協議,若是是 0 ,則系統就會根據地址格式和套接類別,自動選擇一個合適的協議
sk.bind(address)app
s.bind(address) 將套接字綁定到地址。address地址的格式取決於地址族。在AF_INET下,以元組(host,port)的形式表示地址。
sk.listen(backlog)
開始監聽傳入鏈接。backlog指定在拒絕鏈接以前,能夠掛起的最大鏈接數量。
backlog等於5,表示內核已經接到了鏈接請求,但服務器尚未調用accept進行處理的鏈接個數最大爲5
這個值不能無限大,由於要在內核中維護鏈接隊列
sk.setblocking(bool)
是否阻塞(默認True),若是設置False,那麼accept和recv時一旦無數據,則報錯。
sk.accept()
接受鏈接並返回(conn,address),其中conn是新的套接字對象,能夠用來接收和發送數據。address是鏈接客戶端的地址。
接收TCP 客戶的鏈接(阻塞式)等待鏈接的到來
sk.connect(address)
鏈接到address處的套接字。通常,address的格式爲元組(hostname,port),若是鏈接出錯,返回socket.error錯誤。
sk.connect_ex(address)
同上,只不過會有返回值,鏈接成功時返回 0 ,鏈接失敗時候返回編碼,例如:10061
sk.close()
關閉套接字
sk.recv(bufsize[,flag])
接受套接字的數據。數據以字符串形式返回,bufsize指定最多能夠接收的數量。flag提供有關消息的其餘信息,一般能夠忽略。
sk.recvfrom(bufsize[.flag])
與recv()相似,但返回值是(data,address)。其中data是包含接收數據的字符串,address是發送數據的套接字地址。
sk.send(string[,flag])
將string中的數據發送到鏈接的套接字。返回值是要發送的字節數量,該數量可能小於string的字節大小。即:可能未將指定內容所有發送。
sk.sendall(string[,flag])
將string中的數據發送到鏈接的套接字,但在返回以前會嘗試發送全部數據。成功返回None,失敗則拋出異常。
內部經過遞歸調用send,將全部內容發送出去。
sk.sendto(string[,flag],address)
將數據發送到套接字,address是形式爲(ipaddr,port)的元組,指定遠程地址。返回值是發送的字節數。該函數主要用於UDP協議。
sk.settimeout(timeout)
設置套接字操做的超時期,timeout是一個浮點數,單位是秒。值爲None表示沒有超時期。通常,超時期應該在剛建立套接字時設置,由於它們可能用於鏈接的操做(如 client 鏈接最多等待5s )
sk.getpeername()
返回鏈接套接字的遠程地址。返回值一般是元組(ipaddr,port)。
sk.getsockname()
返回套接字本身的地址。一般是一個元組(ipaddr,port)
sk.fileno()
套接字的文件描述符
2、socketserver模塊
socketserver內部使用 IO多路複用 以及 「多線程」 或 「多進程」 ,從而實現併發處理多個客戶端請求的Socket服務端。即:每一個客戶端請求鏈接到服務器時,Socket服務端都會在服務器是建立一個「線程」或者「進程」 專門負責處理當前客戶端的全部請求。
There are five classes in an inheritance diagram, four of which represent synchronous servers of four types: +------------+ | BaseServer | +------------+ | v +-----------+ +------------------+ | TCPServer |------->| UnixStreamServer | +-----------+ +------------------+ | v +-----------+ +--------------------+ | UDPServer |------->| UnixDatagramServer | +-----------+ +--------------------+ Note that UnixDatagramServer derives from UDPServer, not from UnixStreamServer — the only difference between an IP and a Unix stream server is the address family, which is simply repeated in both Unix server classes. class socketserver.ForkingMixIn class socketserver.ThreadingMixIn Forking and threading versions of each type of server can be created using these mix-in classes. For instance, ThreadingUDPServer is created as follows: class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass The mix-in class comes first, since it overrides a method defined in UDPServer. Setting the various attributes also changes the behavior of the underlying server mechanism. class socketserver.ForkingTCPServer class socketserver.ForkingUDPServer class socketserver.ThreadingTCPServer class socketserver.ThreadingUDPServer These classes are pre-defined using the mix-in classes.
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 import socketserver 5 class MyTCPHandler(socketserver.BaseRequestHandler): 6 def setup(self): 7 print("Building secure connection chanel...") 8 def handle(self): 9 print("New Conn:", self.client_address) 10 while True: 11 12 data = self.request.recv(1024) 13 if not data: 14 break 15 print("Client Says:", data.decode()) 16 self.request.send(data) 17 def finish(self): 18 print("client conn is done...") 19 if __name__ == '__main__': 20 HOST, PORT = "localhost", 50007 21 # 把剛纔寫的類看成一個參數傳給ThreadingTCPServer這個類,下面的代碼就建立了一個多線程socket server 22 server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler) 23 # 啓動這個server,這個server會一直運行,除非按ctrl-C中止 24 server.serve_forever()
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import socket 4 ip_port = ('127.0.0.1', 50007) 5 6 sk = socket.socket() 7 sk.connect(ip_port) 8 while True: 9 msg = input(">>:").strip() 10 sk.sendall(bytes(msg, 'utf8')) 11 server_reply = sk.recv(1024) 12 print("Server Reply:", str(server_reply, 'utf8')) 13 sk.close()
ThreadTCPServer
ThreadingTCPServer實現的Soket服務器內部會爲每一個client建立一個 「線程」,該線程用來和客戶端進行交互。
一、ThreadTCPServer基礎
使用ThreadTCPServer:
二、ThreadingTCPServer源碼剖析
ThreadingTCPServer的類圖關係以下:
內部調用流程爲:
ThreadingTCPServer相關源碼:
1 class BaseServer: 2 3 """Base class for server classes. 4 5 Methods for the caller: 6 7 - __init__(server_address, RequestHandlerClass) 8 - serve_forever(poll_interval=0.5) 9 - shutdown() 10 - handle_request() # if you do not use serve_forever() 11 - fileno() -> int # for select() 12 13 Methods that may be overridden: 14 15 - server_bind() 16 - server_activate() 17 - get_request() -> request, client_address 18 - handle_timeout() 19 - verify_request(request, client_address) 20 - server_close() 21 - process_request(request, client_address) 22 - shutdown_request(request) 23 - close_request(request) 24 - handle_error() 25 26 Methods for derived classes: 27 28 - finish_request(request, client_address) 29 30 Class variables that may be overridden by derived classes or 31 instances: 32 33 - timeout 34 - address_family 35 - socket_type 36 - allow_reuse_address 37 38 Instance variables: 39 40 - RequestHandlerClass 41 - socket 42 43 """ 44 45 timeout = None 46 47 def __init__(self, server_address, RequestHandlerClass): 48 """Constructor. May be extended, do not override.""" 49 self.server_address = server_address 50 self.RequestHandlerClass = RequestHandlerClass 51 self.__is_shut_down = threading.Event() 52 self.__shutdown_request = False 53 54 def server_activate(self): 55 """Called by constructor to activate the server. 56 57 May be overridden. 58 59 """ 60 pass 61 62 def serve_forever(self, poll_interval=0.5): 63 """Handle one request at a time until shutdown. 64 65 Polls for shutdown every poll_interval seconds. Ignores 66 self.timeout. If you need to do periodic tasks, do them in 67 another thread. 68 """ 69 self.__is_shut_down.clear() 70 try: 71 while not self.__shutdown_request: 72 # XXX: Consider using another file descriptor or 73 # connecting to the socket to wake this up instead of 74 # polling. Polling reduces our responsiveness to a 75 # shutdown request and wastes cpu at all other times. 76 r, w, e = _eintr_retry(select.select, [self], [], [], 77 poll_interval) 78 if self in r: 79 self._handle_request_noblock() 80 finally: 81 self.__shutdown_request = False 82 self.__is_shut_down.set() 83 84 def shutdown(self): 85 """Stops the serve_forever loop. 86 87 Blocks until the loop has finished. This must be called while 88 serve_forever() is running in another thread, or it will 89 deadlock. 90 """ 91 self.__shutdown_request = True 92 self.__is_shut_down.wait() 93 94 # The distinction between handling, getting, processing and 95 # finishing a request is fairly arbitrary. Remember: 96 # 97 # - handle_request() is the top-level call. It calls 98 # select, get_request(), verify_request() and process_request() 99 # - get_request() is different for stream or datagram sockets 100 # - process_request() is the place that may fork a new process 101 # or create a new thread to finish the request 102 # - finish_request() instantiates the request handler class; 103 # this constructor will handle the request all by itself 104 105 def handle_request(self): 106 """Handle one request, possibly blocking. 107 108 Respects self.timeout. 109 """ 110 # Support people who used socket.settimeout() to escape 111 # handle_request before self.timeout was available. 112 timeout = self.socket.gettimeout() 113 if timeout is None: 114 timeout = self.timeout 115 elif self.timeout is not None: 116 timeout = min(timeout, self.timeout) 117 fd_sets = _eintr_retry(select.select, [self], [], [], timeout) 118 if not fd_sets[0]: 119 self.handle_timeout() 120 return 121 self._handle_request_noblock() 122 123 def _handle_request_noblock(self): 124 """Handle one request, without blocking. 125 126 I assume that select.select has returned that the socket is 127 readable before this function was called, so there should be 128 no risk of blocking in get_request(). 129 """ 130 try: 131 request, client_address = self.get_request() 132 except socket.error: 133 return 134 if self.verify_request(request, client_address): 135 try: 136 self.process_request(request, client_address) 137 except: 138 self.handle_error(request, client_address) 139 self.shutdown_request(request) 140 141 def handle_timeout(self): 142 """Called if no new request arrives within self.timeout. 143 144 Overridden by ForkingMixIn. 145 """ 146 pass 147 148 def verify_request(self, request, client_address): 149 """Verify the request. May be overridden. 150 151 Return True if we should proceed with this request. 152 153 """ 154 return True 155 156 def process_request(self, request, client_address): 157 """Call finish_request. 158 159 Overridden by ForkingMixIn and ThreadingMixIn. 160 161 """ 162 self.finish_request(request, client_address) 163 self.shutdown_request(request) 164 165 def server_close(self): 166 """Called to clean-up the server. 167 168 May be overridden. 169 170 """ 171 pass 172 173 def finish_request(self, request, client_address): 174 """Finish one request by instantiating RequestHandlerClass.""" 175 self.RequestHandlerClass(request, client_address, self) 176 177 def shutdown_request(self, request): 178 """Called to shutdown and close an individual request.""" 179 self.close_request(request) 180 181 def close_request(self, request): 182 """Called to clean up an individual request.""" 183 pass 184 185 def handle_error(self, request, client_address): 186 """Handle an error gracefully. May be overridden. 187 188 The default is to print a traceback and continue. 189 190 """ 191 print '-'*40 192 print 'Exception happened during processing of request from', 193 print client_address 194 import traceback 195 traceback.print_exc() # XXX But this goes to stderr! 196 print '-'*40
1 class TCPServer(BaseServer): 2 3 """Base class for various socket-based server classes. 4 5 Defaults to synchronous IP stream (i.e., TCP). 6 7 Methods for the caller: 8 9 - __init__(server_address, RequestHandlerClass, bind_and_activate=True) 10 - serve_forever(poll_interval=0.5) 11 - shutdown() 12 - handle_request() # if you don't use serve_forever() 13 - fileno() -> int # for select() 14 15 Methods that may be overridden: 16 17 - server_bind() 18 - server_activate() 19 - get_request() -> request, client_address 20 - handle_timeout() 21 - verify_request(request, client_address) 22 - process_request(request, client_address) 23 - shutdown_request(request) 24 - close_request(request) 25 - handle_error() 26 27 Methods for derived classes: 28 29 - finish_request(request, client_address) 30 31 Class variables that may be overridden by derived classes or 32 instances: 33 34 - timeout 35 - address_family 36 - socket_type 37 - request_queue_size (only for stream sockets) 38 - allow_reuse_address 39 40 Instance variables: 41 42 - server_address 43 - RequestHandlerClass 44 - socket 45 46 """ 47 48 address_family = socket.AF_INET 49 50 socket_type = socket.SOCK_STREAM 51 52 request_queue_size = 5 53 54 allow_reuse_address = False 55 56 def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True): 57 """Constructor. May be extended, do not override.""" 58 BaseServer.__init__(self, server_address, RequestHandlerClass) 59 self.socket = socket.socket(self.address_family, 60 self.socket_type) 61 if bind_and_activate: 62 try: 63 self.server_bind() 64 self.server_activate() 65 except: 66 self.server_close() 67 raise 68 69 def server_bind(self): 70 """Called by constructor to bind the socket. 71 72 May be overridden. 73 74 """ 75 if self.allow_reuse_address: 76 self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 77 self.socket.bind(self.server_address) 78 self.server_address = self.socket.getsockname() 79 80 def server_activate(self): 81 """Called by constructor to activate the server. 82 83 May be overridden. 84 85 """ 86 self.socket.listen(self.request_queue_size) 87 88 def server_close(self): 89 """Called to clean-up the server. 90 91 May be overridden. 92 93 """ 94 self.socket.close() 95 96 def fileno(self): 97 """Return socket file number. 98 99 Interface required by select(). 100 101 """ 102 return self.socket.fileno() 103 104 def get_request(self): 105 """Get the request and client address from the socket. 106 107 May be overridden. 108 109 """ 110 return self.socket.accept() 111 112 def shutdown_request(self, request): 113 """Called to shutdown and close an individual request.""" 114 try: 115 #explicitly shutdown. socket.close() merely releases 116 #the socket and waits for GC to perform the actual close. 117 request.shutdown(socket.SHUT_WR) 118 except socket.error: 119 pass #some platforms may raise ENOTCONN here 120 self.close_request(request) 121 122 def close_request(self, request): 123 """Called to clean up an individual request.""" 124 request.close()
1 class ThreadingMixIn: 2 """Mix-in class to handle each request in a new thread.""" 3 4 # Decides how threads will act upon termination of the 5 # main process 6 daemon_threads = False 7 8 def process_request_thread(self, request, client_address): 9 """Same as in BaseServer but as a thread. 10 11 In addition, exception handling is done here. 12 13 """ 14 try: 15 self.finish_request(request, client_address) 16 self.shutdown_request(request) 17 except: 18 self.handle_error(request, client_address) 19 self.shutdown_request(request) 20 21 def process_request(self, request, client_address): 22 """Start a new thread to process the request.""" 23 t = threading.Thread(target = self.process_request_thread, 24 args = (request, client_address)) 25 t.daemon = self.daemon_threads 26 t.start()
1 class ThreadingTCPServer(ThreadingMixIn, TCPServer): 2 pass
BaseRequestHandle源碼
1 class BaseRequestHandler: 2 3 """Base class for request handler classes. 4 5 This class is instantiated for each request to be handled. The 6 constructor sets the instance variables request, client_address 7 and server, and then calls the handle() method. To implement a 8 specific service, all you need to do is to derive a class which 9 defines a handle() method. 10 11 The handle() method can find the request as self.request, the 12 client address as self.client_address, and the server (in case it 13 needs access to per-server information) as self.server. Since a 14 separate instance is created for each request, the handle() method 15 can define arbitrary other instance variariables. 16 17 """ 18 19 def __init__(self, request, client_address, server): 20 self.request = request 21 self.client_address = client_address 22 self.server = server 23 self.setup() 24 try: 25 self.handle() 26 finally: 27 self.finish() 28 29 def setup(self): 30 pass 31 32 def handle(self): 33 pass 34 35 def finish(self): 36 pass
參考:
http://www.cnblogs.com/wupeiqi/articles/5040823.html