<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ## 一、什么是Socket   網絡上的兩個程序通過一個雙向的通信連接實現數據的交換,這個連接的一端稱為一個socket。 建立網絡通信連接至少要一對端口號(socket)。socket本質是編程接口(API),對TCP/IP的封裝,TCP/IP也要提供可供程序員做網絡開發所用的接口,這就是Socket編程接口;HTTP是轎車,提供了封裝或者顯示數據的具體形式;Socket是發動機,提供了網絡通信的能力。   Socket的英文原義是“孔”或“插座”。作為BSD UNIX的進程通信機制,取后一種意思。通常也稱作"套接字",用于描述IP地址和端口,是一個通信鏈的句柄,可以用來實現不同虛擬機或不同計算機之間的通信。在Internet上的主機一般運行了多個服務軟件,同時提供幾種服務。每種服務都打開一個Socket,并綁定到一個端口上,不同的端口對應于不同的服務。Socket正如其英文原義那樣,像一個多孔插座。一臺主機猶如布滿各種插座的房間,每個插座有一個編號,有的插座提供220伏交流電, 有的提供110伏交流電,有的則提供有線電視節目。 客戶軟件將插頭插到不同編號的插座,就可以得到不同的服務。 ## 二、Socket參數介紹   在python中,實例化一個socket連接對象后,需要傳入的參數有以下幾項(括號中是默認參數):               **`socket.``socket`(*family=AF\_INET*,?*type=SOCK\_STREAM*,?*proto=0*,?*fileno=None*)?** #### Socket Families(地址簇) `socket.``AF_UNIX unix本機進程間通信?` `socket.``AF_INET IPV4 ` `socket.``AF_INET6 ?IPV6` #### Socket Types `socket.``SOCK_STREAM ?#for tcp` `socket.``SOCK_DGRAM ? #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 #廢棄了` 剩下的參數proto,fileno一般我們不用管。 ## 三、socket實例 最簡單的socket實例 ``` import socket client = socket.socket() client.connect(('localhost',9999)) client.send(b'hello world') data = client.recv(1024) print('recv',data) client.close() socket_client ``` ``` import socket server = socket.socket() server.bind(('localhost',9999)) server.listen() conn,addr = server.accept() data = conn.recv(1024) print('recv:',data) conn.send(data.upper()) server.close() socket_server ```   上面的代碼的有一個問題, 就是SocketServer.py運行起來后, 接收了一次客戶端的data就退出了。。。, 但實際場景中,一個連接建立起來后,可能要進行多次往返的通信。 ``` import socket client = socket.socket() client.connect(('localhost',8888)) while True: data = input('>>請輸入要發送的內容:') if len(data) == 0: continue client.send(data.encode('utf-8')) res = client.recv(1024) print(res.decode()) client.close() socket_client 支持多次交互 ``` ``` import socket server = socket.socket() server.bind(('localhost',8888)) server.listen(5) print('我要開始等電話了') conn,addr = server.accept() print('電話來了') while True: data = conn.recv(1024) print(data) if not data: print('client has lost') break conn.send(data.upper()) conn.close() socket_server 支持多次交互 ```   那么知道了socket的實現原理之后,我們可以通過socket實現一個極簡版的ssh工具,就是客戶端連接上服務器后,讓服務器執行命令,并返回結果給客戶端。 ``` import socket client = socket.socket() client.connect(('localhost',8888)) while True: data = input('>>請輸入要發送的內容:') if len(data) == 0: continue client.send(data.encode('utf-8')) res_size = client.recv(1024) print(res_size) res_data = b'' recv_size = 0 while recv_size < int(res_size.decode()): data = client.recv(1024) recv_size += len(data) res_data += data else: print(recv_size) print(res_data.decode()) print(res_data) client.close() socket_client_ssh ``` ``` import socket import os server = socket.socket() server.bind(('localhost',8888)) server.listen(5) print('我要開始等電話了') while True: conn,addr = server.accept() print('電話來了') while True: data = conn.recv(1024) if not data: print('client has lost') break res = os.popen(data.decode()).read() conn.send(str(len(res.encode())).encode()) conn.send(res.encode()) print('send done') conn.close() socket_server_ssh ``` 輸出結果: ![](https://img.kancloud.cn/45/07/450769cb35a6dbbf85968fe0ca3375a5_950x373.png)   看程序執行報錯了, 我在客戶端本想只接服務器端命令的執行結果大小,但實際上卻連命令結果也跟著接收了一部分。   這里就引入了一個重要的概念,“粘包”, 即服務器端你調用時send 2次,但你send調用時,數據其實并沒有立刻被發送給客戶端,而是放到了系統的socket發送緩沖區里,等緩沖區滿了、或者數據等待超時了,數據才會被send到客戶端,這樣就把好幾次的小數據拼成一個大數據,統一發送到客戶端了,這么做的目地是為了提高io利用效率,一次性發送總比連發好幾次效率高。 但也帶來一個問題,就是“粘包”,即2次或多次的數據粘在了一起統一發送了。就是我們上面看到的情況 。?   我們在這里必須要想辦法把粘包分開, 因為不分開,你就沒辦法取出來服務器端返回的命令執行結果的大小。首先你是沒辦法讓緩沖區強制刷新把數據發給客戶端的。 你能做的,只有一個。就是讓緩沖區超時,超時了,系統就不會等緩沖區滿了,會直接把數據發走,那么如何讓緩沖區超時呢? 答案就是: 1. time.sleep(0.5),經多次測試,讓服務器程序sleep 至少0.5就會造成緩沖區超時。雖然我們覺得0.5s不多,但是對數據實時要求高的業務場景,比如股票交易等用這種方法肯定是不行的。 2. ?不用sleep,服務器端每發送一個數據給客戶端,就立刻等待客戶端進行回應,即調用 conn.recv(1024), 由于recv在接收不到數據時是阻塞的,這樣就會造成,服務器端接收不到客戶端的響應,就不會執行后面的conn.sendall(命令結果)的指令,收到客戶端響應后,再發送命令結果時,緩沖區就已經被清空了,因為上一次的數據已經被強制發到客戶端了。看下面代碼實現。   ``` import socket client = socket.socket() client.connect(('localhost',8888)) while True: data = input('>>請輸入要發送的內容:') if len(data) == 0: continue client.send(data.encode('utf-8')) res_size = client.recv(1024) client.send(b'ok') print(res_size) res_data = b'' recv_size = 0 while recv_size < int(res_size.decode()): data = client.recv(1024) recv_size += len(data) res_data += data else: print(recv_size) print(res_data.decode()) client.close() socket_client_ssh ``` ``` import socket import os server = socket.socket() server.bind(('localhost',8888)) server.listen(5) print('我要開始等電話了') while True: conn,addr = server.accept() print('電話來了') while True: data = conn.recv(1024) if not data: print('client has lost') break res = os.popen(data.decode()).read() conn.send(str(len(res.encode())).encode()) conn.recv(1024) conn.sendall(res.encode()) print('send done') conn.close() socket_serevr_ssh ``` **SocketServer** socketserver一共有這么幾種類型 1class&nbsp;socketserver.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True) This uses the Internet TCP protocol, which provides for continuous streams of data between the client and server.? 1class&nbsp;socketserver.UDPServer(server_address, RequestHandlerClass, bind_and_activate=True) This uses datagrams, which are discrete packets of information that may arrive out of order or be lost while in transit. The parameters are the same as forTCPServer 12class&nbsp;socketserver.UnixStreamServer(server_address, RequestHandlerClass, bind_and_activate=True)class&nbsp;socketserver.UnixDatagramServer(server_address, RequestHandlerClass,bind_and_activate=True) **There are five classes in an inheritance diagram, four of which represent synchronous servers of four types:** ~~~ +------------+ | BaseServer | +------------+ | v +-----------+ +------------------+ | TCPServer |------->| UnixStreamServer | +-----------+ +------------------+ | v +-----------+ +--------------------+ | UDPServer |------->| UnixDatagramServer | +-----------+ +--------------------+ ~~~ 創建一個socketserver 至少分以下幾步: 1. First, you must create a request handler class by subclassing the BaseRequestHandler class and overriding its handle()?method; this method will process incoming requests.?   2. Second, you must instantiate one of the server classes, passing it the server’s address and the request handler class. 3. Then call the handle\_request()?or serve\_forever()?method of the server object to process one or many requests. 4. Finally, call server\_close()?to close the socket. 最基本的socketserver代碼實現 ~~~ import socketserver class MyTCPHandler(socketserver.BaseRequestHandler): def handle(self): while True: try: self.data = self.request.recv(1024).strip() print(self.data) self.request.send(self.data.upper()) except Exception as e: print('鏈接斷開',e) break if __name__ == "__main__": HOST, PORT = "localhost", 9999 server = socketserver.TCPServer((HOST, PORT), MyTCPHandler) server.serve_forever() ~~~ 讓你的socketserver并發起來, 必須選擇使用以下一個多并發的類 ***class?*`socketserver.``ForkingTCPServer`** ***class?*`socketserver.``ForkingUDPServer`** ***class?*`socketserver.``ThreadingTCPServer`** ***class?*`socketserver.``ThreadingUDPServer`** so 只需要把下面這句 ~~~ server = socketserver.TCPServer((HOST, PORT), MyTCPHandler) ~~~ 換成下面這個,就可以多并發了,這樣,客戶端每連進一個來,服務器端就會分配一個新的線程來處理這個客戶端的請求 ~~~ server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler) ~~~   當然,知道了socket的實現原理之后,我們還可以使用socket來完成很多事情,比如說用socket來完成一個FTP文件上傳下載的功能也都可以。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看