python 之 網絡編程(基於TCP協議的套接字通信操作)

第八章網絡編程

8.1 基於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()        創建一個與該套接字相關的文件

8.2 客戶端與服務端操作( 基於TCP )

tcp是基於鏈接的,必須先啟動服務端,然後再啟動客戶端去鏈接服務端

socket是位於應用層與傳輸層之間的一個抽象層,專門把傳輸層以下的協議封裝成接口提供給應用層使用,應用只需要調用socket的接口或者說按照socket的標準編寫程序,寫出的程序自然是遵循TCP/IP協議

tcp的協議數據不會丟,沒有收完包,下次接收,會繼續上次繼續接收,己端總是在收到ack時才會清除緩衝區內容。數據是可靠的,但是會粘包

客戶端:

import socket
                  #地址家族,基於網絡    TCP協議
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)    # 創建客戶套接字
phone.connect(('127.0.0.1',8080))#服務端ip和端口    # 嘗試連接服務器
​
phone.send('你好'.encode('utf-8'))                       # 發消息b'hello'
data=phone.recv(1024)                                   #收消息
print(data.decode('utf-8'))
​
phone.close()                                          # 關閉客戶套接字

服務端:

import socket
​
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 創建服務器套接字
phone.bind(('127.0.0.1',8080)                        #地址綁定到套接字(0-65535) 0-1024給系統用的
phone.listen(5)                                     # 監聽鏈接
print('start...')
conn,client_addr=phone.accept()         # 接受客戶端鏈接
print('連接來了:',conn,client_addr)     #conn: 連接對象   client_addr: 客戶端的ip和端口 
# 收發消息
msg=conn.recv(1024)                    #收消息,1024是一個最大的限制
print('客戶端的消息: ',msg)
conn.send(msg+b'SB')
​
# 掛電話
conn.close()    #關閉客戶端套接字
# 關機
phone.close()   #關閉服務器套接字(可選)

8.21 加上通信循環與連接循環

服務端:

import socket
​
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.bind(('127.0.0.1',8081))
phone.listen(5)
​
print('start...')
while True:                         # 連接循環
    conn,client_addr=phone.accept()
    print('客戶端 ',client_addr)
​
    while True:                      # 通信循環
        try:
            msg=conn.recv(1024)
            print('客戶端的消息: ',msg)
            conn.send(msg+b'SB')
        except ConnectionResetError:   #只有在當前客戶端停止向服務端發送信息時,下一個客戶端才能發送
            break                   
    conn.close()
phone.close()

客戶端:

import socket
​
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 買電話
phone.connect(('127.0.0.1',8081)) # 嘗試連接服務器 地址為服務端的ip和端口
while True:
    msg=input('>>>: ').strip()
    phone.send(msg.encode('utf-8')) # 發消息b'hello'
    data=phone.recv(1024) #收消息
    print(data.decode('utf-8'))
​
phone.close()

8.3 遠程執行命令的程序

注意:

res=subprocess.Popen(cmd.decode('utf-8'),
shell=True,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE)

的結果的編碼是以當前所在的系統為準的,如果是windows,那麼res.stdout.read()讀出的就是GBK編碼的,在接收端需要用GBK解碼,且只能從管道里讀一次結果

客戶端:

from socket import *
client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080))
​
while True:
    cmd=input('>>>: ').strip()
    if not cmd:
        continue
    client.send(cmd.encode('utf-8'))
    res=client.recv(14744)
    print(res.decode('gbk'))#subprocess返回byte類型,需要gbk解碼
client.close()

服務端:

from socket import *
import subprocess
​
server=socket(AF_INET,SOCK_STREAM)
server.bind(('127.0.0.1',8080))
server.listen(5)
​
while True:
    conn,client_addr=server.accept() #(連接對象,客戶端的ip和端口)
    print(client_addr)
    while True:
        try:
            cmd=conn.recv(1024)
            obj=subprocess.Popen(cmd.decode('utf-8'),#subprocess返回byte類型,可直接傳輸但需要gbk解碼
                                 shell=True,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE
                                 )
            stdout=obj.stdout.read()
            stderr=obj.stderr.read()
        
            total=stdout + stderr# 發送真實的數據
            conn.send(total)
        except ConnectionResetError:
            break
    conn.close()
server.close()
点赞

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *