日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

PythonDay8

發布時間:2024/1/17 python 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 PythonDay8 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本章知識點:

1.Socket語法及相關

2.Socket單線程

3.Socket多線程

4.分分鐘教你做個FTP

?

什么是socket?

Socket是網絡編程的一個抽象概念。通常我們用一個Socket表示“打開了一個網絡鏈接”,而打開一個Socket需要知道目標計算機的IP地址和端口號,再指定協議類型即可。

?

Socket 方法

socket.socket(family=AF_INET,?type=SOCK_STREAM,?proto=0,?fileno=None)

Create a new socket using the given address family, socket type and protocol number. The address family should be?AF_INET?(the default),?AF_INET6,?AF_UNIX,?AF_CAN?or?AF_RDS. The socket type should beSOCK_STREAM?(the default),?SOCK_DGRAM,?SOCK_RAW?or perhaps one of the other?SOCK_?constants. The protocol number is usually zero and may be omitted or in the case where the address family is?AF_CAN?the protocol should be one of?CAN_RAW?or?CAN_BCM. If?fileno?is specified, the other arguments are ignored, causing the socket with the specified file descriptor to return. Unlike?socket.fromfd(),?fileno?will return the same socket and not a duplicate. This may help close a detached socket using?socket.close().

socket.socketpair([family[,?type[,?proto]]])

Build a pair of connected socket objects using the given address family, socket type, and protocol number. Address family, socket type, and protocol number are as for the?socket()?function above. The default family is?AF_UNIX?if defined on the platform; otherwise, the default is?AF_INET.

socket.create_connection(address[,?timeout[,?source_address]])

Connect to a TCP service listening on the Internet?address?(a 2-tuple?(host,?port)), and return the socket object. This is a higher-level function than?socket.connect(): if?host?is a non-numeric hostname, it will try to resolve it for both?AF_INET?and?AF_INET6, and then try to connect to all possible addresses in turn until a connection succeeds. This makes it easy to write clients that are compatible to both IPv4 and IPv6.

Passing the optional?timeout?parameter will set the timeout on the socket instance before attempting to connect. If no?timeout?is supplied, the global default timeout setting returned by?getdefaulttimeout()?is used.

If supplied,?source_address?must be a 2-tuple?(host,?port)?for the socket to bind to as its source address before connecting. If host or port are ‘’ or 0 respectively the OS default behavior will be used.

socket.getaddrinfo(host,?port,?family=0,?type=0,?proto=0,?flags=0) #獲取要連接的對端主機地址

sk.bind(address)

  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()

  套接字的文件描述符

socket.sendfile(file,?offset=0,?count=None)

? ? ?發送文件 ,但目前多數情況下并無什么卵用。

?

?

客戶端

大多數連接都是可靠的TCP連接。創建TCP連接時,主動發起連接的叫客戶端,被動響應連接的叫服務器。

舉個例子,當我們在瀏覽器中訪問新浪時,我們自己的計算機就是客戶端,瀏覽器會主動向新浪的服務器發起連接。如果一切順利,新浪的服務器接受了我們的連接,一個TCP連接就建立起來的,后面的通信就是發送網頁內容了。

?

服務器

和客戶端編程相比,服務器編程就要復雜一些。

服務器進程首先要綁定一個端口并監聽來自其他客戶端的連接。如果某個客戶端連接過來了,服務器就與該客戶端建立Socket連接,隨后的通信就靠這個Socket連接了。

所以,服務器會打開固定端口(比如80)監聽,每來一個客戶端連接,就創建該Socket連接。由于服務器會有大量來自客戶端的連接,所以,服務器要能夠區分一個Socket連接是和哪個客戶端綁定的。一個Socket依賴4項:服務器地址、服務器端口、客戶端地址、客戶端端口來唯一確定一個Socket。

但是服務器還需要同時響應多個客戶端的請求,所以,每個連接都需要一個新的進程或者新的線程來處理,否則,服務器一次就只能服務一個客戶端了。

?

OK,那我們先來寫一個入門簡單的一個socket:

server:

1 import socket 2 server=socket.socket()#定義個socket實例 3 server.bind(("localhost",9999))#綁定端口 4 server.listen()#監聽端口 5 print("開始監聽") 6 conn,addr=server.accept()#conn代表傳入類型,addr代表地址 接收連接并返回 7 print("新的連接",addr) 8 data=conn.recv(1024)#接收客戶端發送的字節 9 print("收到消息",data) 10 server.close()

client:

1 import socket 2 client=socket.socket()#定義socket類型 3 client.connect(("localhost",9999))#連接服務器地址 4 client.send(b'hello')#發送消息 5 client.close()

?

OK,這就是一個簡單的一socket,那么問題來了,我這個服務在收到客戶端一個消息后就斷開了,那么怎么讓他不斷開呢,怎么讓他一直持續呢?

?

多次數據交互怎么實現呢?

server:

import socket server=socket.socket()#定義個socket實例 server.bind(("localhost",9999))#綁定端口 server.listen()#監聽端口 print("開始監聽") conn,addr=server.accept()#conn代表傳入類型,addr代表地址 接收連接并返回 print("新的連接",addr) while True:data=conn.recv(1024)#接收客戶端發送的字節print("收到消息",data)conn.send(data.upper())#將收到的消息返回客戶端 server.close()

client:

import socket client=socket.socket()#定義socket類型 client.connect(("localhost",9999))#連接服務器地址 while True:date=input("-->:").strip()client.send(date.encode("utf-8"))#發送消息data=client.recv(1024)#接收服務端消息print("來自服務器",data) client.close()

?

實現了多次交互, 棒棒的, 但你會發現一個小問題, 就是客戶端輸入為空,就會卡著不動,為啥呢?

因為服務器默認是不接受為空的。

ok知道了原因,那我們來解決下:

1 import socket 2 client=socket.socket()#定義socket類型 3 client.connect(("localhost",9999))#連接服務器地址 4 while True: 5 date=input("-->:").strip() 6 if len(date)==0:continue;#做個判斷,為空直接跳出當前循環 7 client.send(date.encode("utf-8"))#發送消息 8 data=client.recv(1024)#接收服務端消息 9 print("來自服務器",data) 10 client.close()

?

那么咱們到目前為止單線程的小程序就完成了,但是,如何將用戶作為多線程進行操作呢?藥不能停,對吧

比如,你正在通話中,你一個電話進來了,那你是不是可以掛斷當前去接聽另一個電話是吧,ok這就是多線程

?

socket多線程

ok,那我們先來回顧下這段代碼:

conn,addr=server.accept()#

這段代碼代表的是接入一個新的類型,那么我們可不可以給他做個循環,讓他結束當前循環后,繼續下一個循環,這樣,多線程是不是就有頭緒了?

?

通過socket實現簡單的socket功能

那么,光是簡單的收發消息就沒意思了,那我們來做個ssh吧。

server:

1 import socket 2 import os 3 server=socket.socket()#獲取socket實例 4 server.bind(("localhost",8888))#綁定端口 5 server.listen()#監聽端口 6 while True:#第一層 7 print("等待客戶端連接") 8 conn,addr=server.accept()#接收客戶端請求,程序在這里開始阻塞,等待客戶連接進來 9 print("新連接",addr) 10 while True: 11 data=conn.recv(1024)#接收數據大小 12 if not data: 13 print("客戶端斷開") 14 break 15 print("收到指令",data) 16 res=os.popen(data.decode()).read()#py3 里socket發送的只有bytes,os.popen又只能接受str,所以要decode一下 17 print(len(res)) 18 conn.send(res.encode("utf-8"))#返回客戶端信息 19 server.close()

client:

1 import socket 2 import os 3 client=socket.socket() 4 client.connect(("localhost",8888)) 5 while True: 6 msg=input("-->:") 7 if len(msg)==0:continue 8 client.send(msg.encode("utf-8")) 9 data=client.recv(1024)#接收客戶端返回的消息 10 print(data.decode()) 11 client.close()

?

very cool , 這樣我們就做了一個簡單的ssh , 但多試幾條命令你就會發現,上面的程序有以下2個問題。?

  • 不能執行top等類似的 會持續輸出的命令,這是因為,服務器端在收到客戶端指令后,會一次性通過os.popen執行,并得到結果后返回給客戶,但top這樣的命令用os.popen執行你會發現永遠都不會結束,所以客戶端也永遠拿不到返回。(真正的ssh是通過select 異步等模塊實現的,我們以后會涉及)
  • 不能執行像cd這種沒有返回的指令, 因為客戶端每發送一條指令,就會通過client.recv(1024)等待接收服務器端的返回結果,但是cd命令沒有結果 ,服務器端調用conn.send(data)時是不會發送數據給客戶端的。 所以客戶端就會一直等著,等到天荒地老,結果就卡死了。解決的辦法是,在服務器端判斷命令的執行返回結果的長度,如果結果為空,就自己加個結果返回給客戶端,如寫上"cmd exec success, has no output."
  • 如果執行的命令返回結果的數據量比較大,會發現,結果返回不全,在客戶端上再執行一條命令,結果返回的還是上一條命令的后半段的執行結果,這是為什么呢?這是因為,我們的客戶寫client.recv(1024), 即客戶端一次最多只接收1024個字節,如果服務器端返回的數據是2000字節,那有至少9百多字節是客戶端第一次接收不了的,那怎么辦呢,服務器端此時不能把數據直接扔了呀,so它會暫時存在服務器的io發送緩沖區里,等客戶端下次再接收數據的時候再發送給客戶端。 這就是為什么客戶端執行第2條命令時,卻接收到了第一條命令的結果的原因。 這時有同學說了, 那我直接在客戶端把client.recv(1024)改大一點不就好了么, 改成一次接收個100mb,哈哈,這是不行的,因為socket每次接收和發送都有最大數據量限制的,畢竟網絡帶寬也是有限的呀,不能一次發太多,發送的數據最大量的限制 就是緩沖區能緩存的數據的最大量,這個緩沖區的最大值在不同的系統上是不一樣的, 我實在查不到一個具體的數字,但測試的結果是,在linux上最大一次可接收10mb左右的數據,不過官方的建議是不超過8k,也就是8192,并且數據要可以被2整除,不要問為什么 。anyway , 如果一次只能接收最多不超過8192的數據 ,那服務端返回的數據超過了這個數字怎么辦呢?比如讓服務器端打開一個5mb的文件并返回,客戶端怎么才能完整的接受到呢?那就只能循環收取啦。?
  • ?

    在開始解決上面問題3之前,我們要考慮,客戶端要循環接收服務器端的大量數據返回直到一條命令的結果全部返回為止, 但問題是客戶端知道服務器端返回的數據有多大么?答案是不知道,那既然不知道服務器的要返回多大的數據,那客戶端怎么知道要循環接收多少次呢?答案是不知道,擦,那咋辦? 總不能靠猜吧?呵呵。。。 當然不能,那只能讓服務器在發送數據之前主動告訴客戶端,要發送多少數據給客戶端,然后再開始發送數據,yes, 機智如我,搞起。

    server:

    1 import socket 2 import os 3 server=socket.socket()#獲取socket實例 4 server.bind(("localhost",8888))#綁定端口 5 server.listen()#監聽端口 6 while True:#第一層 7 print("等待客戶端連接") 8 conn,addr=server.accept()#接收客戶端請求,程序在這里開始阻塞,等待客戶連接進來 9 print("新連接",addr) 10 while True: 11 data=conn.recv(1024)#接收數據大小 12 if not data: 13 print("客戶端斷開") 14 break 15 print("收到指令",data) 16 res=os.popen(data.decode()).read()#py3 里socket發送的只有bytes,os.popen又只能接受str,所以要decode一下 17 print(len(res)) 18 conn.send(str(len(res.encode())).encode("utf-8"))#先發字節 19 conn.send(res.encode("utf-8"))#再發數據 20 print("send done") 21 server.close()

    ?

    client:

    1 import socket 2 import os 3 client=socket.socket() 4 client.connect(("localhost",8888)) 5 while True: 6 msg=input("-->:") 7 if len(msg)==0:continue 8 client.send(msg.encode("utf-8")) 9 cmd_res_size=client.recv(1024)#接收結果的長度 10 print("命令返回長度",cmd_res_size) 11 received_size=0 12 #received_data=b''#接收返回的數據 13 while received_size <int(cmd_res_size.decode()): 14 data=client.recv(1024)#接收客戶端返回的消息 15 received_size+=len(data)#每次收到的數據大小相加 16 print(data.decode())#打印數據 17 else: 18 print("cmd res recevise done",received_size) 19 #data=data.decode("utf-8") 20 #print(data.decode()) 21 client.close()

    ?

    當然,咱們現在處理的任務還是單用戶,如果有多用戶呢?怎么弄,就用到socketserver了、

    二、socketserver?

      socketserver內部使用 IO多路復用 以及 “多線程” 和 “多進程” ,從而實現并發處理多個客戶端請求的Socket服務端。即:每個客戶端請求連接到服務器時,Socket服務端都會在服務器是創建一個“線程”或者“進程” 專門負責處理當前客戶端的所有請求

    ?

    1、ThreadingTCPServer

    使用ThreadingTCPServer:

    • 創建一個繼承自 SocketServer.BaseRequestHandler 的類
    • 類中必須定義一個名稱為 handle 的方法
    • 啟動ThreadingTCPServer
    • socketserver基本代碼:
    • 1 import socketserver 2 3 class MyTCPHandler(socketserver.BaseRequestHandler): 4 """ 5 The request handler class for our server. 6 7 It is instantiated once per connection to the server, and must 8 override the handle() method to implement communication to the 9 client. 10 """ 11 12 def handle(self): 13 # self.request is the TCP socket connected to the client 14 self.data = self.request.recv(1024).strip() 15 print("{} wrote:".format(self.client_address[0])) 16 print(self.data) 17 # just send back the same data, but upper-cased 18 self.request.sendall(self.data.upper()) 19 20 if __name__ == "__main__": 21 HOST, PORT = "localhost", 9999 22 23 # Create the server, binding to localhost on port 9999 24 server = socketserver.TCPServer((HOST, PORT), MyTCPHandler) 25 26 # Activate the server; this will keep running until you 27 # interrupt the program with Ctrl-C 28 server.serve_forever()

    用socketserver對ssh程序做修改,實現多用戶同時操作互不影響

    ?

    轉載于:https://www.cnblogs.com/AbeoHu/p/5866803.html

    總結

    以上是生活随笔為你收集整理的PythonDay8的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。