socket通訊
socket 套接字
**socket :一組簡化的便於操做的接口**
應用層經過socket接口傳給傳輸層後面的操做交給操做系統去完成
是處於應用層與T傳輸層(TCP/IP)協議通訊的抽象層,是一組操做起來很是簡單的接口(接收數據)
此接口接收數據後,交由操做系統
**爲何存在socket抽象層:**
直接與操做系統數據交互很是麻煩,繁瑣,socket對這些繁瑣的操做高度的封裝簡化
socket 在Python中就是一個模塊,提供的功能:
找到ip地址Mac地址端口號就能獲取到計算機軟件的位置
獲取ip地址和端口號就能判斷mac地址
socket 通訊先啓動服務端,再啓動客戶端
基於TCP協議的socket簡單通訊
服務端
# 導入socket模塊
import socket # socket 一組接口
# 買電話 實例化一個phone對象 socket.socket方法
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# socket.socket()方法 默承認以不寫 默認就是基於TCP協議的socket 基於網絡的是tcp 基於文件的是upd
# socket.AF_INET,socket.SOCK_STREAM 是基於TCP協議的socket
# 綁定電話卡 bind方法 綁定本地IP地址和端口
phone.bind(('127.0.0.1',8848)) # 元組的形式
# 127.0.0.1本地迴環地址,只能本身連,別的都不能連
# 開機監聽 listen方法
phone.listen(5)
# 參數能夠默認不寫 寫了以後容許鏈接有限制 多餘的會進行等待
# listen:容許5我的同時鏈接,先跟一我的聊,聊完了再跟另外一我的聊 剩下的連接能夠連接也能夠等待
# 等待鏈接
print('等待鏈接')
# 阻塞accept方法 等待鏈接 有人鏈接後再繼續走
# phone.accept()
# 阻塞 等待客戶端連接服務端,阻塞狀態中 accent方法
conn,addr = phone.accept()
# conn 雙向通訊管理,鏈接做用
# addr 客戶端的ip地址和端口號
# conn,addr返回一個元組,有兩個參數
print(conn) # 通訊管理
print(addr) # ip地址和端口號
# from_client_data 來自客戶端的問題
# 接收到客戶端的消息 recv方法 緩存區
from_client_data = conn.recv(1024)
# conn.recv(1024) 通道里面的緩衝區最多接收1024個字節
# 1024 最多接收1024個字節
# 輸出接收到的客戶端的消息
print(f'來自客戶端{addr[0]}的消息:{from_client_data.decode("utf-8")}')
# addr[0] 取IP地址
# from_client_data.decode將字節解碼成utf-8
# to_client_data 給客戶端發消息
to_client_data = input('服務器輸入').strip().encode('utf-8')
# strip() 把首位的空格切掉
# encode('utf-8')將字節編碼成字節型
# send方法 服務端向客戶端
conn.send(to_client_data.upper())
# upper()發送出的數據是大寫的
# 關閉雙向通訊鏈接
conn.close()
# 掛斷電話 關閉鏈接
phone.close()
客戶端
# 導入socket模塊
import socket # 一組接口
# 買電話 實例化一個phone對象
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 默認就是基於TCP協議的socket AF_INET,socket.SOCK_STREAM基於網絡的
# 撥打電話 connect方法 鏈接服務器ip地址
phone.connect(('127.0.0.1',8848))
# 127.0.0.1 服務端的ip地址
# 8848 端口是客戶端隨機分配的
# to_server_data 給服務端的消息
to_server_data = input('客戶端輸入')
# send方法 發送消息
phone.send(to_server_data.encode('utf-8'))
# to_server_data.encode('utf-8') 給服務端的消息encode將字節編碼成字節型
# from_server_data 來自服務端的消息 recv緩存區
from_server_data = phone.recv(1024)
# recv(1024) 緩存區最多1024個字節
# 打印
print(f'來自服務器{from_server_data.decode("utf-8")}')
# from_server_data.decode("utf-8") 來自服務端的消息decode將字節轉碼成utf-8
# 關閉電話 關閉鏈接
phone.close()
純代碼
服務端:
import socket
phone = socket.socket()
phone.bind(('127.0.0.1',8848))
phone.listen(2)
conn,addr = phone.accept()
print(conn)
print(addr)
from_client_data = conn.recv(1024)
print(f'來自客戶端{addr}消息:{from_client_data.decode("utf-8")}')
to_client_data = input('>>>').strip().encode('utf-8')
conn.send(to_client_data)
conn.close()
phone.close()
客戶端:
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1',8848))
data = input('請輸入>>>')
phone.send(data.encode('utf-8'))
from_server_data = phone.recv(1024)
print(f'來自服務端的消息:{from_server_data}')
phone.close()
循環通訊
服務端
# 一個聊完了繼續往下接客戶
# 導入socket模塊
import socket # socket 一組接口
# 買電話 實例化一個phone對象 socket.socket方法
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# socket.socket()方法 默承認以不寫 默認就是基於TCP協議的socket 基於網絡的是tcp 基於文件的是upd
# socket.AF_INET,socket.SOCK_STREAM 是基於TCP協議的socket
# 綁定電話卡 bind方法 綁定本地IP地址和端口
phone.bind(('127.0.0.1',8848)) # 元組的形式
# 127.0.0.1本地迴環地址,只能本身連,別的都不能連
# 開機監聽 listen方法
phone.listen(2)
# 參數能夠默認不寫 寫了以後容許鏈接有限制 多餘的會進行等待
# listen:容許2我的同時鏈接,先跟一我的聊,聊完了再跟另外一我的聊 剩下的連接能夠連接也能夠等待
# 實際有3個,有一個在於服務端創建連接
print('等待鏈接')
# while 循環接收連接
# 阻塞 等待客戶端連接服務端,阻塞狀態中 accent方法
conn,addr = phone.accept()
# conn 雙向通訊管理,鏈接做用
# addr 客戶端的ip地址和端口號
# 輸出 conn通道信息和addrIP地址和端口
print(f'連接來了:{conn,addr}')
# while 循環輸入鏈接
while 1:# 1比True好用 循環收消息,循環發消息
# try exception 異常處理
# try 正常狀況的代碼
try:
# from_client_data 來自客戶端的消息
# 接收到客戶端的消息 recv方法 緩存區
from_client_data = conn.recv(1024)
# conn.recv(1024) 通道里面的緩衝區最多接收1024個字節
# 1024 最多接收1024個字節
# if判斷 來自客戶端的信息是Q
if from_client_data.upper() == b'Q':
# upper() 給服務端的消息轉化成大寫
# b'Q' 經過b方法將Q轉成字節型
# 輸出正常退出
print('客戶端正常退出聊天了')
# 終止循環
break
# 輸出接收到的客戶端的消息
print(f'來自客戶端{addr[0]}的消息:{from_client_data.decode("utf-8")}')
# addr[0] 取IP地址
# from_client_data.decode將字節解碼成utf-8
# to_client_data 給客戶端發消息
to_client_data = input('服務器輸入').strip().encode('utf-8')
# strip() 把首位的空格切掉
# encode('utf-8')將字節編碼成字節型
# send方法 服務端向客戶端
conn.send(to_client_data.upper())
# upper()發送出的數據是大寫的
# except 異常處理
except ConnectionAbortedError:
# ConnectionAbortedError 錯誤類型
# 輸出 客戶端斷了
print('客戶端連接中斷了')
# 終止while輸入循環
break
# 退出循環連接 關閉雙向通訊鏈接
conn.close()
# 掛斷電話 關閉鏈接
phone.close()
純代碼
服務端:
import socket
phone = socket.socket()
phone.bind(('127.0.0.1',8848))
phone.listen(2)
conn,addr = phone.accept()
print(conn)
print(addr)
from_client_data = conn.recv(1024)
print(f'來自客戶端{addr}消息:{from_client_data.decode("utf-8")}')
to_client_data = input('>>>').strip().encode('utf-8')
conn.send(to_client_data)
conn.close()
phone.close()
客戶端:
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1',8848))
data = input('請輸入>>>')
phone.send(data.encode('utf-8'))
from_server_data = phone.recv(1024)
print(f'來自服務端的消息:{from_server_data}')
phone.close()
循環連接通訊
服務端
# 一個聊完了繼續往下接客戶
# 導入socket模塊
import socket # socket 一組接口
# 買電話 實例化一個phone對象 socket.socket方法
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# socket.socket()方法 默承認以不寫 默認就是基於TCP協議的socket 基於網絡的是tcp 基於文件的是upd
# socket.AF_INET,socket.SOCK_STREAM 是基於TCP協議的socket
# 綁定電話卡 bind方法 綁定本地IP地址和端口
phone.bind(('127.0.0.1',8848)) # 元組的形式
# 127.0.0.1本地迴環地址,只能本身連,別的都不能連
# 開機監聽 listen方法
phone.listen(2)
# 參數能夠默認不寫 寫了以後容許鏈接有限制 多餘的會進行等待
# listen:容許2我的同時鏈接,先跟一我的聊,聊完了再跟另外一我的聊 剩下的連接能夠連接也能夠等待
# 實際有3個,有一個在於服務端創建連接
print('等待鏈接')
# while 循環接收連接
while 1: # while 1 比 while True的好處:效率高,不用在底層把True翻譯成1
# 開啓循環連接模式,同時開3個,先鏈接第一我的,第一個結束後,去找下一我的
# 3我的同時發送消息,先接受第一我的的,等第一個退出後,直接連接下一我的
# 阻塞 等待客戶端連接服務端,阻塞狀態中 accent方法
conn,addr = phone.accept()
# conn 雙向通訊管理,鏈接做用
# addr 客戶端的ip地址和端口號
# 輸出 conn通道信息和addrIP地址和端口
print(f'連接來了:{conn,addr}')
# while 循環輸入鏈接
while 1:
# try exception 異常處理
# try 正常狀況的代碼
try:
# from_client_data 來自客戶端的消息
# 接收到客戶端的消息 recv方法 緩存區
from_client_data = conn.recv(1024)
# conn.recv(1024) 通道里面的緩衝區最多接收1024個字節
# 1024 最多接收1024個字節
# if判斷 來自客戶端的信息是Q
if from_client_data.upper() == b'Q':
# upper() 給服務端的消息轉化成大寫
# b'Q' 經過b方法將Q轉成字節型
# 輸出正常退出
print('客戶端正常退出聊天了')
# 終止循環
break
# 輸出接收到的客戶端的消息
print(f'來自客戶端{addr[0]}的消息:{from_client_data.decode("utf-8")}')
# addr[0] 取IP地址
# from_client_data.decode將字節解碼成utf-8
# to_client_data 給客戶端發消息
to_client_data = input('服務器輸入').strip().encode('utf-8')
# strip() 把首位的空格切掉
# encode('utf-8')將字節編碼成字節型
# send方法 服務端向客戶端
conn.send(to_client_data.upper())
# upper()發送出的數據是大寫的
# except 異常處理
except ConnectionAbortedError:
# ConnectionAbortedError 錯誤類型
# 輸出 客戶端斷了
print('客戶端連接中斷了')
# 終止while輸入循環
break
# 退出循環連接 關閉雙向通訊鏈接
conn.close()
# 掛斷電話 關閉鏈接
phone.close()
客戶端
# 客戶端發一個q能夠正常退出,且不能輸入空
# 導入socket模塊
import socket # 一組接口
# 買電話 實例化一個phone對象
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 默認就是基於TCP協議的socket AF_INET,socket.SOCK_STREAM基於網絡的
# 撥打電話 connect方法 鏈接服務器ip地址
phone.connect(('127.0.0.1', 8848))
# 127.0.0.1 服務端的ip地址
# 8848 端口是客戶端隨機分配的
# 循環接收,發送消息
while 1:
# to_server_data 給服務端的消息
to_server_data = input('客戶端輸入(輸入q或者Q退出):').strip().encode('utf-8')
# 發送空字符串服務端會阻塞 加個if判斷,不能爲空
# 同時開多個,提示'輸入'表示已經連接
# if 判讀 發給服務端的消息不爲空
if not to_server_data:
# 服務端若是接受到了空的內容,服務端就會一直阻塞中,不管哪一方發送消息時,都不能爲空
# 必須一個recv 一個send
# 輸出提示
print('輸入的內容不能爲空')
# 繼續判斷是否是爲空
continue
# send方法 發送消息
phone.send(to_server_data)
# if 判讀發送給服務端的消息是否是q
if to_server_data.upper() == b'Q':
# upper() 給服務端的消息轉化成大寫
# b'Q' 經過b方法將Q轉成字節型
# 是Q就終止循環
break
# from_server_data 來自服務端的消息 recv緩存區
from_server_data = phone.recv(1024)
# recv(1024) 緩存區最多1024個字節
# 打印
print(f'來自服務器{from_server_data.decode("utf-8")}')
# from_server_data.decode("utf-8") 來自服務端的消息decode將字節轉碼成utf-8
# 關閉電話 關閉鏈接
phone.close()
純代碼
服務端:
import socket
phone = socket.socket()
phone.bind(('127.0.0.1',8848))
phone.listen(2)
# listen: 2 容許有兩個客戶端加到半連接池,超過兩個則會報錯
while 1:
conn,addr = phone.accept() # 等待客戶端連接我,阻塞狀態中
print(f'連接來了: {conn,addr}')
while 1:
try:
from_client_data = conn.recv(1024) # 最多接受1024字節
if from_client_data.upper() == b'Q':
print('客戶端正常退出聊天了')
break
print(f'來自客戶端{addr}消息:{from_client_data.decode("utf-8")}')
to_client_data = input('>>>').strip().encode('utf-8')
conn.send(to_client_data)
except ConnectionResetError:
print('客戶端連接中斷了')
break
conn.close()
phone.close()
客戶端:
import socket
phone = socket.socket()
phone.connect(('127.0.0.1',8848))
while 1:
to_server_data = input('>>>輸入q或者Q退出').strip().encode('utf-8')
if not to_server_data:
# 服務端若是接受到了空的內容,服務端就會一直阻塞中,因此不管哪一端發送內容時,都不能爲空發送
print('發送內容不能爲空')
continue
phone.send(to_server_data)
if to_server_data.upper() == b'Q':
break
from_server_data = phone.recv(1024) # 最多接受1024字節
print(f'來自服務端消息:{from_server_data.decode("utf-8")}')
phone.close()
執行遠程命令
服務端
# 輸入命令,錯誤的提示非命令,正確的打印出執行的命令
# help是正確的命令
# 命令後最好不要加空格
# 導入socket模塊
import socket # socket 一組接口
# 導入subprocess模塊
import subprocess # subprocess 遠程命令
# 買電話 實例化一個phone對象 socket.socket方法
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# socket.socket()方法 默承認以不寫 默認就是基於TCP協議的socket 基於網絡的是tcp 基於文件的是upd
# socket.AF_INET,socket.SOCK_STREAM 是基於TCP協議的socket
# 綁定電話卡 bind方法 綁定本地IP地址和端口
phone.bind(('127.0.0.1',8847)) # 元組的形式
# 127.0.0.1本地迴環地址,只能本身連,別的都不能連
# 開機監聽 listen方法
phone.listen(2)
# 參數能夠默認不寫 寫了以後容許鏈接有限制 多餘的會進行等待
# listen:容許2我的同時鏈接,先跟一我的聊,聊完了再跟另外一我的聊 剩下的連接能夠連接也能夠等待
# 實際有3個,有一個在於服務端創建連接
print('等待鏈接')
# while 循環接收連接
while 1:
# 開啓循環連接模式,同時開3個,先鏈接第一我的,第一個結束後,去找下一我的
# 3我的同時發送消息,先接受第一我的的,等第一個退出後,直接連接下一我的
# 阻塞 等待客戶端連接服務端,阻塞狀態中 accent方法
conn,addr = phone.accept()
# conn 雙向通訊管理,鏈接做用
# addr 客戶端的ip地址和端口號
# 輸出 conn通道信息和addrIP地址和端口
print(f'連接來了:{conn,addr}')
# while 循環輸入鏈接
while 1:
# try exception 異常處理
# try 正常狀況的代碼
try:
# from_client_data 來自客戶端的消息
# 接收到客戶端的消息 recv方法 緩存區
from_client_data = conn.recv(1024)
# conn.recv(1024) 通道里面的緩衝區最多接收1024個字節
# 1024 最多接收1024個字節
# if判斷 來自客戶端的信息是Q
if from_client_data.upper() == b'Q':
# upper() 給服務端的消息轉化成大寫
# b'Q' 經過b方法將Q轉成字節型
# 輸出正常退出
print('客戶端正常退出聊天了')
# 終止循環
break
obj = subprocess.Popen(from_client_data.decode('utf-8'),
shell = True, # shell 命令解釋器,至關於調用cmd 執行指定的命令
stdout = subprocess.PIPE, # 正確的命令 丟到管道中
stderr = subprocess.PIPE, # 錯誤的命令 丟到另外一個管道中
)
# obj = subprocess.Popen() obj對象 = subprocess模塊.Popen方法
# from_client_data 來自客戶端的信息
# decode('utf-8') 解碼成utf-8類型
# windows操做系統默認編碼是gbk編碼
print(obj) # <subprocess.Popen object at 0x1030de2e8> 獲得對象的地址
# result 同時輸入正確的方法和錯誤的方法
result = obj.stdout.read() + obj.stderr.read()
# obj.stdout.read() 正確的管道
# obj.stderr.read() 錯誤的管道
print(result) # 獲得全部管道的信息
# send方法 服務端向客戶端
conn.send(result)
# except 異常處理
except ConnectionAbortedError:
# ConnectionAbortedError 錯誤類型
# 輸出 客戶端斷了
print('客戶端連接中斷了')
# 終止while輸入循環
break
# 退出連接循環 關閉雙向通訊鏈接
conn.close()
# 掛斷電話 關閉鏈接
phone.close()
客戶端
# 客戶端發一個q能夠正常退出,且不能輸入空
# 導入socket模塊
import socket # 一組接口
# 買電話 實例化一個phone對象
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 默認就是基於TCP協議的socket AF_INET,socket.SOCK_STREAM基於網絡的
# 撥打電話 connect方法 鏈接服務器ip地址
phone.connect(('127.0.0.1', 8847))
# 127.0.0.1 服務端的ip地址
# 8848 端口是客戶端隨機分配的
# 循環接收,發送消息
while 1:
# to_server_data 給服務端的消息
to_server_data = input('客戶端輸入(輸入q或者Q退出):').strip().encode('utf-8')
# 發送空字符串服務端會阻塞 加個if判斷,不能爲空
# 同時開多個,提示'輸入'表示已經連接
# if 判讀 發給服務端的消息不爲空
if not to_server_data:
# 服務端若是接受到了空的內容,服務端就會一直阻塞中,不管哪一方發送消息時,都不能爲空
# 必須一個recv 一個send
# 輸出提示
print('輸入的內容不能爲空')
# 繼續判斷是否是爲空
continue
# send方法 發送消息
phone.send(to_server_data)
# if 判讀發送給服務端的消息是否是q
if to_server_data.upper() == b'Q':
# upper() 給服務端的消息轉化成大寫
# b'Q' 經過b方法將Q轉成字節型
# 是Q就終止循環
break
# from_server_data 來自服務端的消息 recv緩存區
from_server_data = phone.recv(1024)
# recv(1024) 緩存區最多1024個字節
# 打印
print(f'來自服務器{from_server_data.decode("utf-8")}')
# from_server_data.decode("utf-8") 來自服務端的消息decode將字節轉碼成utf-8
# 關閉電話 關閉鏈接
phone.close()
純代碼
服務端:
import socket
import subprocess
phone = socket.socket()
phone.bind(('127.0.0.1',8867))
phone.listen(3)
while 1:
conn,addr = phone.accept()
print(f'連接來自:{conn,addr}')
while 1:
try:
from_client_data = conn.recv(1024)
obj = subprocess.Popen(from_client_data.decode("utf8"),
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
result = obj.stdout.read() + obj.stderr.read()
conn.send(result)
except ConnectionError:
print('客戶端連接中斷了')
break
conn.close()
phone.close()
客戶端:
import socket
import subprocess
phone = socket.socket()
phone.connect(('127.0.0.1', 8867))
while 1:
to_server_data = input('>>>請輸入cmd命令,輸入Q或q退出').strip().encode('utf8')
if not to_server_data:
print('發送內容不能爲空!')
continue
phone.send(to_server_data)
if to_server_data.upper() == b'Q':
break
from_server_data = phone.recv(1024)
print(f'來自服務端的消息:{from_server_data.decode("utf8")}')
phone.close()