天天看點

python socket程式設計

什麼是 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