socket

1、Socket介紹html

網絡上的兩個程序經過一個雙向的通訊鏈接實現數據的交換,這個鏈接的一端稱爲一個socket。python

socket一般也稱做"套接字",用於描述IP地址和端口,是一個通訊鏈的句柄,應用程序一般經過"套接字"向網絡發出請求或者應答網絡請求。web

socket起源於Unix,而Unix/Linux基本哲學之一就是「一切皆文件」,對於文件用【打開】【讀寫】【關閉】模式來操做。socket就是該模式的一個實現,socket便是一種特殊的文件,一些socket函數就是對其進行的操做(讀/寫IO、打開、關閉)瀏覽器

socket和file的區別:bash

    • file模塊是針對某個指定文件進行【打開】【讀寫】【關閉】
    • socket模塊是針對 服務器端 和 客戶端Socket 進行【打開】【讀寫】【關閉】


 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()
socket server
 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 client

  基於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()
socketserver
 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()
Client

 ThreadTCPServer

 ThreadingTCPServer實現的Soket服務器內部會爲每一個client建立一個 「線程」,該線程用來和客戶端進行交互。

  一、ThreadTCPServer基礎

  使用ThreadTCPServer:

  • 建立一個繼承自 SocketServer.BaseRequestHandler 的類
  • 類中必須定義一個名稱爲 handle 的方法
  • 啓動ThreadingTCPServer

  二、ThreadingTCPServer源碼剖析

  ThreadingTCPServer的類圖關係以下:

  

 

內部調用流程爲:

  • 啓動服務端程序
  • 執行 TCPServer.__init__ 方法,建立服務端Socket對象並綁定 IP 和 端口
  • 執行 BaseServer.__init__ 方法,將自定義的繼承自SocketServer.BaseRequestHandler 的類 MyRequestHandle賦值給 self.RequestHandlerClass
  • 執行 BaseServer.server_forever 方法,While 循環一直監聽是否有客戶端請求到達 ...
  • 當客戶端鏈接到達服務器
  • 執行 ThreadingMixIn.process_request 方法,建立一個 「線程」 用來處理請求
  • 執行 ThreadingMixIn.process_request_thread 方法
  • 執行 BaseServer.finish_request 方法,執行 self.RequestHandlerClass()  即:執行 自定義 MyRequestHandler 的構造方法(自動調用基類BaseRequestHandler的構造方法,在該構造方法中又會調用 MyRequestHandler的handle方法)

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
BaseServer
  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()
TCPServer
 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()
ThreadingMixIn
1 class ThreadingTCPServer(ThreadingMixIn, TCPServer):
2     pass
ThreadingTCPServer

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
BaseRequestHandler

 

 

 

參考:

  http://www.cnblogs.com/wupeiqi/articles/5040823.html

相關文章
相關標籤/搜索