什麼是 Socket?
Socket又稱"套接字",應用程式通常通過"套接字"向網絡送出請求或者應答網絡請求,使主機間或者一台計算機上的程序間可以通訊。
TCP可靠性的實作:
(1)校驗碼
(2)接收方回報
(3)資訊包附帶序号
UDP:(1)快 不需要花費時間建立和關閉連接配接
(2)快 偶爾丢失一兩個消息包無所謂,但是TCP會嚴格檢查
(3)快 UDP的限制是一個資訊包不超過64KB的資料
TCP和UDP差別就是UDP不建立連接配接,隻保證資料的完整性,資料傳輸快,但是不保證資料是否真的被收到,也不保證資料是夠隻接收一次,也不保證次序。
服務端是用來給一個或者多個用戶端提供服務的,當用戶端發起請求,開始等待服務端的傳回結果,服務端接受完請求以後,根據自己的邏輯進行處理請求,并傳回給用戶端,用戶端接收到傳回結果以後,關閉和服務端的連接配接。
最常用個用戶端和服務端有兩種模式C/S(mysql)模式和B/S模式(網站)
socket()函數
Python 中,我們用 socket()函數來建立套接字,文法格式如下:
socket.socket([family[, type[, proto]]])
參數
family: 套接字家族可以使AF_UNIX或者AF_INET
type: 套接字類型可以根據是面向連接配接的還是非連接配接分為SOCK_STREAM或SOCK_DGRAM
protocol: 一般不填預設為0.
TCP
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
綁定位址
bind(address)
address = (‘0.0.0.0’, 8009)
s.bind(address) 或者s.bind((‘0.0.0.0’, 8009))
address 必須是一個元組,容易錯誤,address = (host,port)
host:服務端ip,字元串類型, 如果為0.0.0.0 代表本機的任意一個ip
port:服務端提供的端口, 整型, 0-1024為系統保留
監聽消息
s.listen(badklog)
backlog代表可以同時接受多少個socket連接配接
接受連接配接
conn, addr = s.accept()
接受連接配接并傳回元組(conn, addr), 其中conn是新的套接字對象,每一個新的連接配接就建立一個新的對象。可以用來接受和發送資料,addr是用戶端的位址。包含host和port
發送資料
s.send(string) 發送字元串到連接配接的套接字,可能未将指定内容全部發送
s.sendall(string) 内部遞歸調用send,将所有内容發送出去,建議使用。
接收資料
data = s.recv(bufsize)
接收套接字資料,資料以字元串形式傳回,bufsize指定最多接收的資料量,可以使用1024, 2048
如果不知道接收的數量有多少,可能幾個位元組,可能幾M,一般通過循環接收
UDP
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.sendto(string)
data, address = s.recvfrom(bufsize)
用戶端
用戶端首先也要建立socket套接字
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
用戶端連接配接服務端函數:
s.connect(address) 連接配接到address的套接字
result = connect_ex(address) 成功傳回0,失敗傳回錯誤碼(推薦使用)
通用
s.close() 關閉socket套接字
s.getsocketname() 擷取套接字的名字
s.settimeout(timeout) 設定套接字逾時時間,timeout為float類型,機關為秒。
s.gettimeout() 獲得套接字逾時時間
s.setblocking(flag)
flage為bool值
setblocking(True) is equivalent to settimeout(None); 相當于不設定逾時時間,一直阻塞在那裡
setblocking(False) is equivalent to settimeout(0.0). 相當于設定逾時時間為0, 如果設定False,那麼accept和recv時一旦無資料,則報錯。
s.fileno()
傳回套接字的檔案描述符(一個小整數)。這對于select.select()是有用的。
簡單例子
用戶端向服務端發送一個消息。
服務端
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time : 2018-6-1 17:52
# @Author: yangjian
# @File : Client.py
'''
python3 socket收發消息都是隻能使用bytes類型,而python2.7則可以使用str類型
'''
'''
sock = 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 ,則系統就會根據位址格式和套接類别,自動選擇一個合适的協定
'''
import socket
#建立socket對象
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0) #建立socket對象
#綁定
ip_port = ('127.0.0.1',8087) #定義ip、端口号
s.bind(ip_port) #socket對象綁定ip、端口号(ip、端口号一定是元組形式)
s.getsockname() #服務端使用,傳回服務端自身的套接字位址(ip、端口号)
#監聽,并設定最大挂起連接配接數
s.listen(5) #監聽,除了正在連接配接的用戶端,最多還能能挂起5個連接配接,超過之後就拒絕連接配接
#擷取用戶端連接配接
conn, addr = s.accept() #擷取用戶端的scoket對象conn和用戶端的位址address(ip、端口号)
#收發消息
recv_data = conn.recv(1024) #socket擷取的用戶端對象(conn)用來接收消息
print(str(recv_data,encoding='utf-8'))
send_data = '你好'
conn.send(bytes(send_data,encoding='utf-8')) #socket擷取的用戶端對象(conn)用來發送消息-----python3隻能發送位元組類型(bytes),python2.7可以直接發送字元串
#關閉用戶端對象
conn.close()
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time : 2018-6-1 17:51
# @Author: yangjian
# @File : Server.py
'''
python3 socket收發消息都是隻能使用bytes類型,而python2.7則可以使用str類型
'''
import socket
#建立socket對象
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #建立socket對象
s.settimeout(5) #設定逾時時間
#s.getpeername() #用戶端使用,傳回服務端的套接字位址(ip、端口号)
#連接配接服務端
#ip_port = ('127.0.0.1',9999) #定義ip、端口号
s.connect(('127.0.0.1',8087)) #socket對象連接配接服務端。(ip、端口号一定是元組形式) ----連接配接失敗會報錯
#s.connect_ex(ip_port) #功能同上,不過如果連接配接失敗會傳回一個錯誤編碼(不報錯)
#發消息
send_data = '你好'
s.send(bytes(send_data,encoding='utf-8')) #發送消息,成功傳回發送的位元組數-----python3隻能發送位元組類型(bytes),python2.7可以直接發送字元串
#s.sendall(bytes(send_data,encoding='utf-8')) #發送所有資料,成功傳回None,失敗報錯
#收消息
recv_data = s.recv(1024)
#關閉
s.close()
ssh互動
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time : 2018-6-1 18:15
# @Author: yangjian
# @File : ssh_test.py
import paramiko
client = paramiko.SSHClient()
# 允許連結不在know_host檔案中的主機
client.set_missing_host_key_policy(paramiko.AutoAddPolicy)
client.connect('100.106.106.220', 22, username='root', password='123456', timeout=5)
while 1:
cmd = input('[root@localhost ~]#')
stdin, stdout, stderr = client.exec_command(cmd)
for std in stdout.readlines():
print(std)
client.close()
結果:
D:\pycharmproject\venv\Scripts\python.exe D:/pycharmproject/0531/ssh_test.py
[root@localhost ~]#ls -ll
total 8
-rw-r--r-- 1 root root 1361 May 31 10:11 yangjian.his
-rw-r--r-- 1 root root 924 May 31 10:11 yangjian.time