socket網絡編程

一,什麼是sockepython

  Socket是應用層與TCP/IP協議族通訊的中間軟件抽象層,它是一組接口。在設計模式中,Socket其實就是一個門面模式,它把複雜的TCP/IP協議族隱藏在Socket接口後面,對用戶來講,一組簡單的接口就是所有,讓Socket去組織數據,以符合指定的協議。shell

 

  也有人將socket說成ip+port,ip是用來標識互聯網中的一臺主機的位置,而port是用來標識這臺機器上的一個應用程序,ip地址是配置到網卡上
的,而port是應用程序開啓的,ip與port的綁定就標識了互聯網中獨一無二的一個應用程序而程序的pid是同一臺機器上不一樣進程或者線程的標識

二,套接字發展史及分類編程

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

 

基於文件類型的套接字家族緩存

 

套接字家族的名字:AF_UNIX服務器

 

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

基於網絡類型的套接字家族ssh

套接字家族的名字:AF_INETsocket

 

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

 

三,套接字經常使用函數

 

服務端套接字函數
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的套接字

tcp服務端

 

import socket
import subprocess

phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.bind(('127.0.0.1',2224))
phone.listen(5)
while True:
    print('Starting........')
    conn,client_addr=phone.accept()
    print(conn,client_addr)
    while True:
        try:
            cmd=conn.recv((1024))
            res=subprocess.Popen(cmd.decode('utf-8'),shell=True,stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
            stdout=res.stdout.read()
            stderr=res.stderr.read()
            conn.send(stdout+stderr)
        except Exception:
            break
    conn.close()
phone.close()

tcp客戶端

import socket

phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1',2224))

while True:
    cmd=input('>>>>').strip()
    if not cmd: continue
    phone.send(cmd.encode('utf-8'))
    cmd_res=phone.recv(1024)
    print(cmd_res.decode('gbk'))
phone.close()

 五,粘包(TCP)

什麼是粘包:

  粘包問題主要仍是由於接收方不知道消息之間的界限,不知道一次性提取多少字節的數據所形成的。

粘包現象:

  粘包是指發送方發送的若干包數據到接收方接收時粘成一包,從接收緩衝區看,後一包數據的頭緊接着前一包數據的尾。

解決粘包:

  在發送數據以前,先發送一個帶有數據長度的報頭過去,從而就知道了接受消息的界限。

 

import socket
import subprocess
import struct

phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.bind(('127.0.0.1',2224))
phone.listen(5)
while True:
    print('Starting........')
    conn,client_addr=phone.accept()
    print(conn,client_addr)
    while True:
        try:
            cmd=conn.recv((1024))
            res=subprocess.Popen(cmd.decode('utf-8'),shell=True,stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
            stdout=res.stdout.read()
            stderr=res.stderr.read()

            header=struct.pack('i',len(stdout)+len(stderr))
            conn.send(header)
            conn.send(stdout)
            conn.send(stderr)
        except Exception:
            break
    conn.close()
phone.close()
解決粘包後的ssh服務端

 

import socket
import struct

phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1',2224))

while True:
    cmd=input('>>>>').strip()
    if not cmd: continue
    phone.send(cmd.encode('utf-8'))
    head_res=phone.recv(4)
    len_res=struct.unpack('i',head_res)[0]
    len_size=0
    res=b''
    while len_size < len_res:
        data=phone.recv(1024)
        len_size+=len(data)
        res+=data
    print(res.decode('gbk'))
phone.close()
解決粘包後的ssh客戶端
相關文章
相關標籤/搜索