Python 第二十九章 socket通訊

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()
相關文章
相關標籤/搜索