Python進階----SOCKET套接字基礎, 客戶端與服務端通訊, 執行遠端命令.

Python進階----SOCKET套接字基礎, 客戶端與服務端通訊, 執行遠端命令.

一丶socket套接字

什麼是socket套接字:

​ ​  ​ 專業理解: socket是應用層與TCP/IP協議族通訊的中間軟件抽象層,它是一組接口,Socket其實就是使用一個門面模式(門面模式要求一個子系統的外部與其內部的通訊必須經過一個統一的門面(Facade)對象進行。門面模式提供一個高層次的接口,使得子系統更易於使用), 它把複雜的TCP/IP協議族隱藏在Socket接口後面,對用戶來講,一組簡單的接口就是所有.讓socket去組織數據.python

 ​  ​ 簡易理解:socket就是一個模塊,封裝了網絡通訊所須要的全部東西.經過調用socket模塊實現兩個進程之間的鏈接和通信.(也可稱爲:IP+Port , IP用於表示互聯網中的一臺主機的位置,而port則是定位到這個機器上的某個程序.)shell

socket套接字的History

 ​  ​ 套接字起源於 20 世紀 70 年代加利福尼亞大學伯克利分校版本的 Unix,即人們所說的 BSD Unix。 所以,有時人們也把套接字稱爲「伯克利套接字」或「BSD 套接字」。一開始,套接字被設計用在同 一臺主機上多個應用程序之間的通信。這也被稱進程間通信,或 IPC。套接字有兩種(或者稱爲有兩個種族),分別是基於文件型的和基於網絡型的。編程

 ​  ​ 兩個種族:緩存

 ​  ​  ​ 1.基於網絡類型的套接字:AF_INET服務器

 ​  ​  ​ (還有AF_INET6被用於ipv6,還有一些其餘的地址家族,不過,他們要麼是隻用於某個平臺,要麼就是已經被廢棄,或者是不多被使用,或者是根本沒有實現,全部地址家族中,AF_INET是使用最普遍的一個,python支持不少種地址家族,可是因爲咱們只關心網絡編程,因此大部分時候我麼只使用AF_INET)網絡

 ​  ​  ​ 2.基於文件類型的套接字:AF_UNIXsocket

 ​  ​  ​ unix一切皆文件,基於文件的套接字調用的就是底層的文件系統來取數據,兩個套接字進程運行在同一機器,能夠經過訪問同一個文件系統間接完成通訊tcp

二丶基於TCP協議的socket通訊

img

socket函數具體使用代碼以下:👇

import  socket

socket.socket(socket_family,socket_type,protocal=0)
#socket_family 地址簇 : 能夠是 AF_UNIX 或 AF_INET。
#socket_type    : 能夠是 SOCK_STREAM 或 SOCK_DGRAM。
# protocol      :  通常不填,默認值爲 0。



### 獲取tcp/ip套接字
# socket.AF_INET:  IPV4  IP協議
# socket.SOCK_STREAM : 提供面向鏈接的穩定數據傳輸  TCP是流傳輸
tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)



### 獲取udp/ip套接字
# socket.AF_INET:  IPV4  IP協議
# socket.SOCK_DGRAM   使用不連續不可靠的數據包鏈接  , 數據包
udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

服務端套接字函數

 ​ s.bind() 綁定(主機,端口號)到套接字
 ​ s.listen() 開始TCP監聽
 ​ s.accept() 被動接受TCP客戶的鏈接,(阻塞式)等待鏈接的到來函數

客戶端套接字函數

 ​ s.connect() 主動初始化TCP服務器鏈接
 ​ s.connect_ex() connect()函數的擴展版本,出錯時返回出錯碼,而不是拋出異常設計

公共用途的套接字函數

 ​ s.recv() 接收TCP數據
 ​ s.send() 發送TCP數據(send在待發送數據量大於己端緩存區剩餘空間時,數據丟失,不會發完)
 ​ s.sendall() 發送完整的TCP數據(本質就是循環調用send,sendall在待發送數據量大於己端緩存區剩餘空間時,數據不丟失,循環調用send直到發完)
 ​ s.recvfrom() 接收UDP數據
 ​ s.sendto() 發送UDP數據
 ​ s.getpeername() 鏈接到當前套接字的遠端的地址
 ​ s.getsockname() 當前套接字的地址
 ​ s.getsockopt() 返回指定套接字的參數
 ​ s.setsockopt() 設置指定套接字的參數
 ​ s.close() 關閉套接字

面向鎖的套接字方法

 ​ s.setblocking() 設置套接字的阻塞與非阻塞模式
 ​ s.settimeout() 設置阻塞套接字操做的超時時間
 ​ s.gettimeout() 獲得阻塞套接字操做的超時時間

面向文件的套接字的函數

 ​ s.fileno() 套接字的文件描述符
 ​ s.makefile() 建立一個與該套接字相關的文件

三丶單個客戶與服務端通訊

tcp是基於連接的,必須先啓動服務端,而後再啓動客戶端去連接服務端

### Client 客戶端
import socket
client=socket.socket()      # 建立 socket對象

client.connect(('127.0.0.1',8848)) # 鏈接服務端地址,端口號8848

# 發送數據
client.send('abcd'.encode('utf-8'))  # 客戶端 發送字節類型數據
from_server_data=client.recv(1024)   # 客戶端接收服務端響應的數據 
print(from_server_data)             

client.close()          # 關閉客戶端鏈接
### server服務端

import  socket
server=socket.socket()  #  1 .  建立 socket的server對象

server.bind(('127.0.0.1',8848))  # 2 . 綁定IP 和端口

#  3. 監聽
server.listen(5)

# 4. 接受鏈接
conn,addr=server.accept() # 程序等待
print(conn,addr)        # 打印 conn 鏈接信息 ,和addr地址信息

data=conn.recv(1024)  #  接收客戶端發送的數據  最多接收1024字節

conn.send(data.upper()) # 發送給客戶端數據

conn.close()    # 關閉鏈接
server.close()  #關閉服務

四丶通訊循環

###  client
import socket
client=socket.socket()

client.connect(('127.0.0.1',8848))# 鏈接

# 發送數據
while 1:
    user_input=input('>>').strip().encode('utf-8')  # 用戶輸入的字符串數據,轉換成字節格式
    
    client.send(user_input)     # 客戶端 發送字節數據
    
    from_server_data=client.recv(1024)  # 接收服務端 返回的數據 ,每次接收1024字節
    
    print(f'來自服務端的信息:{from_server_data.decode("utf8")}')

client.close()
### server服務端

import  socket
server=socket.socket()  #  1 .  建立 server對象

server.bind(('127.0.0.1',8848))  # 2 . 綁定IP 和端口

#  3. 監聽
server.listen(5)

# 4. 接受鏈接
conn,addr=server.accept() # 程序等待
print(conn,addr)

while 1 :       # 循環去
    data=conn.recv(1024)  #  接收數據  最多接收1024字節
    print(f'來自客戶端{addr}的信息{data.decode("utf-8")}')
    to_client=input('>>>').strip().encode('utf-8')
    conn.send(to_client) # 發送數據

conn.close() # 關閉鏈接
server.close()  #關閉服務

五丶通訊,鏈接循環

### 客戶端 client   , 
# 啓動多個客戶端, 依次排隊, 當第一個鏈接斷開時,第二個鏈接就會鏈接服務端

import  socket
client =socket.socket()

client.connect(('127.0.0.1',9999))

while 1:
    try:
        user_input=input('請輸入信息:>>>').strip().encode('utf-8')
        if user_input.upper()==b'Q':
            client.send(user_input)
            break
        client.send(user_input)
        ser_data=client.recv(1024)
        print(f'來自服務端的信息:{ser_data.decode("utf-8")}')
    except ConnectionResetError:
        break
client.close()
### server 服務端
import  socket
server=socket.socket()

server.bind(('127.0.0.1',9999))
server.listen(2)

while 1:
    conn,addr=server.accept()
    print(conn,addr)
    while 1:
        try:
            cli_data=conn.recv(1024)
            print(f'來自客戶端:{addr}消息: {cli_data.decode("utf-8")}')
            if cli_data.upper()==b'Q':
                break
            response=input('回覆消息:>>').strip().encode('utf-8')
            conn.send(response)
        except ConnectionResetError:
            break
    conn.close()        # 當上一個conn 鏈接已經關閉或斷開時,進入下一次循環,等待新的鏈接
server.close()

六丶利用socket完成獲取遠端命令的示例

subprocess模塊的使用

# -*-coding:utf-8-*-
import subprocess
while 1:
    user_input=input('請輸入指令:').strip()
    obj=subprocess.Popen(user_input,
                         shell=True,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE,
                         )
    if obj.stdout:
        print(f'正確信息: {obj.stdout.read().decode("gbk")}')
    else:
        print(f'錯誤信息: {obj.stderr.read().decode("gbk")}')

利用socket獲取遠端命令(產生粘包現象)

 ​ 什麼是粘包:

​ ​  ​ 客戶端不能一次性接收完服務器返回的信息.這些沒有接收完的信息會保存在一個緩衝區內. 等下次鏈接再來時,先把上一次沒有收完的數據給接收了.

### server

import  socket
import subprocess
server =socket.socket()

server.bind(('127.0.0.1',8877))
server.listen(5)

while 1:
    conn , addr=server.accept()
    print(conn,addr)

    while 1:
        try:
            cmd=conn.recv(1024) # 接收客戶端發來的cmd 字節指令
            print(cmd)
            # 執行本機cmd命令
            obj=subprocess.Popen(cmd.decode('utf-8'),
                                 shell=True,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE)
            # 拼接返回信息
            msg_right=obj.stdout.read()
            msg_err=obj.stderr.read()
            result=(msg_right+msg_err).decode('gbk').encode('utf-8')
            print(result.decode('utf-8'))
            # 向客戶端發送結果
            conn.send(result)
        except ConnectionResetError:
            break

conn.close()
server.close()
### client

import  socket
client=socket.socket()
#鏈接服務器
client.connect(('127.0.0.1',8877))

while 1:

    user_input=input('請輸入指令:>>>').strip()
    # 發送指令 以字節形式
    client.send(user_input.encode('utf-8'))

    # 接收返回結果
    try:
        ser_data=client.recv(1024)
        print(ser_data.decode('utf-8'))
    except  UnicodeDecodeError as e:
        print(e)

client.close()
相關文章
相關標籤/搜索