1. 程式人生 > >socket編程

socket編程

文件 ces accep imp com linux操作 簡單 linux col

一、CS架構

server端要求:

1、力求一直提供服務

2、綁定到一個唯一的地址,讓客戶端找到

二、socket

socket就是為了完成C/S架構軟件的開發,但是如果是C/S架構的軟件就一定需要解決雙方通信問題。

基於網絡通信就需要了解復雜的網絡協議 TCP/IP協議,於是socket出現了;

1、什麽是sock?

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

所以,我們無需深入理解tcp/udp協議,socket已經為我們封裝好了,我們只需要遵循socket的規定去編程,寫出的程序自然就是遵循tcp/udp標準的

2、socket分類

(1)基於文件類型的套接字家族

套接字家族的名字:AF_UNIX

unix一切皆文件,基於文件的套接字調用的就是底層的文件系統來取數據,兩個套接字進程運行在同一機器,可以通過訪問同一個文件系統間接完成通信(Linux操作系統)

(2)基於網絡類型的套接字家族 AF_INET

(還有AF_INET6被用於ipv6,還有一些其他的地址家族,不過,他們要麽是只用於某個平臺,要麽就是已經被廢棄,或者是很少被使用,或者是根本沒有實現,所有地址家族中,AF_INET是使用最廣泛的一個,python支持很多種地址家族,但是由於我們只關心網絡編程,所以大部分時候我麽只使用AF_INET)(ssh,nginx,mysql)

3、soket套接字的工作流程

技術分享

服務端:得到Socket對象,然後與端口綁定(bind),對端口進行監聽(listen),調用accept阻塞,等待客戶端連接。

客戶端:客戶端初始化一個Socket,然後連接服務器(connect),如果連接成功,這時客戶端與服務器端的連接就建立了。

C/S交換階段:客戶端發送數據請求,服務器端接收請求並處理請求,然後把回應數據發送給客戶端,客戶端讀取數據,最後關閉連接,一次交互結束

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

客戶端套接字函數

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

4、基於TCP協議的套接字

(1)實現一個簡單的套接字

import socket
phon=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #創建一個基於網絡的(socket.AF_INET)tcp協議傳輸的sock(socket.SOCK_STREAM)
phon.bind(("127.0.0.1",8090)) #把創建好的套接字,綁定在 唯一的IP和端口上。
phon.listen(80)            #開始監聽
conn,addr=phon.accept()   #等待客戶端通過TCP三次握手發起 連接  (把某個連接,和連接的對象分解賦值給 conn,和addr)
data=conn.recv(1024)      #接收 連接進來的某一個客戶端,發送過來的消息
print("接受到來自客戶端發來的消息",data)
conn.send(data.upper())    #發送接受的消息 給某一個客戶端

執行結果

服務端:

技術分享

客戶端:

技術分享

(2)循環通信的套接字

雖然上述已經實現了一個簡單的套接字,但服務端的 socket 只能接受一次客戶端的連接,所以可以利用while..Ture構建一個通信循環

服務端:

import socket
phon=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #創建一個基於網絡的(socket.AF_INET)tcp協議傳輸的sock(socket.SOCK_STREAM
phon.bind(("127.0.0.1",8090)) #把創建好的套接字,綁定在 唯一的IP和端口上。
phon.listen(80)                 #開始監聽
conn,addr=phon.accept()   #等待客戶端通過TCP三次握手發起 連接  (把某個連接,和連接的對象分解賦值給 conn,和addr)
while True:              #循環通信----------------------------------------------------------------------->
    data=conn.recv(1024)      #接收 連接進來的某一個客戶端,發送過來的消息
    print("接受到來自客戶端發來的消息",data)
    conn.send(data.upper())    #發送接受的消息 給某一個客戶端
conn.close()
phon.close()

客戶端:

import socket
phon=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phon.connect((127.0.0.1,8090))     #客戶端的phon.connect正好對於服務端的phon1.accept()
while True: #循環通信----------------------------------------------------------------------------------->>
    mes=input(---->: .strip())
    if not mes:
        continue
    res=phon.send(mes.encode(utf-8))  #發消息
    data=phon.recv(1024)             #收消息
    print(data.decode(gbk))

phon.close()

tcp服務端

import socket
import subprocess
iphon=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #(建立一個socket對象)
iphon.bind((127.0.0.1,8080))  #綁定到 IP+端口上 成為唯一的socket
iphon.listen(5)                   #設置連接池的個數
print(starting........)
while True:  #連接循環
    conn,addr=iphon.accept()  #等待電話連接
    print(電話線路是,conn)
    print(客戶手機號:,addr)
    while True: #通信循環 發送和接收
        try:
            data=conn.recv(1024) #接受消息 最大從內存裏接受1024MB數據
            print(客戶端發來的消息是%s%data)
            data=data.decode(utf-8) #從客戶端發來的數據是經過編碼的字節數據 所以需要解碼 成Unicode
            res=subprocess.Popen( data, shell=True, stdout=subprocess.PIPE)  #解碼後傳進subprocess.Popen去cmd執行
            data1 = res.stdout.read().decode(gbk)      #cmd是gbk編碼所以需要gbk解碼
            print(data1)                                  #打印解碼後的結果
            data1=data1.encode(gbk)                   #編碼
            conn.send(data1)  #發送消息                  #編碼後再傳輸給客戶端
        except Exception:
            break
    conn.close()
iphon.close()
#

TCP客戶端

import socket
phon=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phon.connect((127.0.0.1,8080))     #客戶端的phon.connect正好對於服務端的phon1.accept()
while True: #循環通信
    mes=input(---->: .strip())
    if not mes:
        continue
    res=phon.send(mes.encode(utf-8))  #發消息
    data=phon.recv(1024)             #收消息
    print(data.decode(gbk))


phon.close()

socket編程