最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python網(wǎng)絡(luò)編程之Python編寫(xiě)TCP協(xié)議程序的步驟

 更新時(shí)間:2022年11月10日 10:21:21   作者:廣龍宇  
這篇文章主要介紹了Python網(wǎng)絡(luò)編程編寫(xiě)TCP協(xié)議程序的開(kāi)發(fā)步驟,通過(guò)實(shí)例代碼介紹了TCP客戶端程序開(kāi)發(fā),案例講解多任務(wù)版TCP服務(wù)端程序開(kāi)發(fā),需要的朋友可以參考下

TCP客戶端程序開(kāi)發(fā)

1. 開(kāi)發(fā) TCP 客戶端程序開(kāi)發(fā)步驟回顧

  • 創(chuàng)建客戶端套接字對(duì)象
  • 和服務(wù)端套接字建立連接
  • 發(fā)送數(shù)據(jù)
  • 接收數(shù)據(jù)
  • 關(guān)閉客戶端套接字

2. socket 類(lèi)的介紹

導(dǎo)入 socket 模塊 import socket

創(chuàng)建客戶端 socket 對(duì)象 socket.socket(AddressFamily, Type)

參數(shù)說(shuō)明:

  • AddressFamily 表示IP地址類(lèi)型, 分為T(mén)Pv4和IPv6
  • Type 表示傳輸協(xié)議類(lèi)型

方法說(shuō)明:

  • connect((host, port)) 表示和服務(wù)端套接字建立連接, host是服務(wù)器ip地址,port是應(yīng)用程序的端口號(hào)
  • send(data) 表示發(fā)送數(shù)據(jù),data是二進(jìn)制數(shù)據(jù)
  • recv(buffersize) 表示接收數(shù)據(jù), buffersize是每次接收數(shù)據(jù)的長(zhǎng)度

3. TCP 客戶端程序開(kāi)發(fā)示例代碼

import socket
if __name__ == '__main__':
    # 創(chuàng)建tcp客戶端套接字
    # 1. AF_INET:表示ipv4
    # 2. SOCK_STREAM: tcp傳輸協(xié)議
    tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 和服務(wù)端應(yīng)用程序建立連接
    tcp_client_socket.connect(("192.168.131.62", 8080))
    # 代碼執(zhí)行到此,說(shuō)明連接建立成功
    # 準(zhǔn)備發(fā)送的數(shù)據(jù)
    send_data = "你好服務(wù)端,我是客戶端小黑!".encode("gbk")
    # 發(fā)送數(shù)據(jù)
    tcp_client_socket.send(send_data)
    # 接收數(shù)據(jù), 這次接收的數(shù)據(jù)最大字節(jié)數(shù)是1024
    recv_data = tcp_client_socket.recv(1024)
    # 返回的直接是服務(wù)端程序發(fā)送的二進(jìn)制數(shù)據(jù)
    print(recv_data)
    # 對(duì)數(shù)據(jù)進(jìn)行解碼
    recv_content = recv_data.decode("gbk")
    print("接收服務(wù)端的數(shù)據(jù)為:", recv_content)
    # 關(guān)閉套接字
    tcp_client_socket.close()

執(zhí)行結(jié)果:

b'hello'
接收服務(wù)端的數(shù)據(jù)為: hello

說(shuō)明

  • str.encode(編碼格式) 表示把字符串編碼成為二進(jìn)制
  • data.decode(編碼格式) 表示把二進(jìn)制解碼成為字符串

網(wǎng)絡(luò)調(diào)試助手充當(dāng)服務(wù)端程序:

TCP服務(wù)端程序開(kāi)發(fā)

1. 開(kāi)發(fā) TCP 服務(wù)端程序開(kāi)發(fā)步驟回顧

  • 創(chuàng)建服務(wù)端端套接字對(duì)象
  • 綁定端口號(hào)
  • 設(shè)置監(jiān)聽(tīng)
  • 等待接受客戶端的連接請(qǐng)求
  • 接收數(shù)據(jù)
  • 發(fā)送數(shù)據(jù)
  • 關(guān)閉套接字

2. socket 類(lèi)的介紹

導(dǎo)入 socket 模塊
import socket

創(chuàng)建服務(wù)端 socket 對(duì)象
socket.socket(AddressFamily, Type)

參數(shù)說(shuō)明:

  • AddressFamily 表示IP地址類(lèi)型, 分為T(mén)Pv4和IPv6
  • Type 表示傳輸協(xié)議類(lèi)型

方法說(shuō)明:

  • bind((host, port)) 表示綁定端口號(hào), host 是 ip 地址,port 是端口號(hào),ip 地址一般不指定,表示本機(jī)的任何一個(gè)ip地址都可以。
  • listen (backlog) 表示設(shè)置監(jiān)聽(tīng),backlog參數(shù)表示最大等待建立連接的個(gè)數(shù)。
  • accept() 表示等待接受客戶端的連接請(qǐng)求
  • send(data) 表示發(fā)送數(shù)據(jù),data 是二進(jìn)制數(shù)據(jù)
  • recv(buffersize) 表示接收數(shù)據(jù), buffersize 是每次接收數(shù)據(jù)的長(zhǎng)度

3. TCP 服務(wù)端程序開(kāi)發(fā)示例代碼

import socket
if __name__ == '__main__':
    # 創(chuàng)建tcp服務(wù)端套接字
    tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 設(shè)置端口號(hào)復(fù)用,讓程序退出端口號(hào)立即釋放
    tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) 
    # 給程序綁定端口號(hào)
    tcp_server_socket.bind(("", 8989))
    # 設(shè)置監(jiān)聽(tīng)
    # 128:最大等待建立連接的個(gè)數(shù), 提示: 目前是單任務(wù)的服務(wù)端,同一時(shí)刻只能服務(wù)與一個(gè)客戶端,后續(xù)使用多任務(wù)能夠讓服務(wù)端同時(shí)服務(wù)與多個(gè)客戶端,
    # 不需要讓客戶端進(jìn)行等待建立連接
    # listen后的這個(gè)套接字只負(fù)責(zé)接收客戶端連接請(qǐng)求,不能收發(fā)消息,收發(fā)消息使用返回的這個(gè)新套接字來(lái)完成
    tcp_server_socket.listen(128)
    # 等待客戶端建立連接的請(qǐng)求, 只有客戶端和服務(wù)端建立連接成功代碼才會(huì)解阻塞,代碼才能繼續(xù)往下執(zhí)行
    # 1. 專(zhuān)門(mén)和客戶端通信的套接字: service_client_socket
    # 2. 客戶端的ip地址和端口號(hào): ip_port
    service_client_socket, ip_port = tcp_server_socket.accept()
    # 代碼執(zhí)行到此說(shuō)明連接建立成功
    print("客戶端的ip地址和端口號(hào):", ip_port)
    # 接收客戶端發(fā)送的數(shù)據(jù), 這次接收數(shù)據(jù)的最大字節(jié)數(shù)是1024
    recv_data = service_client_socket.recv(1024)
    # 獲取數(shù)據(jù)的長(zhǎng)度
    recv_data_length = len(recv_data)
    print("接收數(shù)據(jù)的長(zhǎng)度為:", recv_data_length)
    # 對(duì)二進(jìn)制數(shù)據(jù)進(jìn)行解碼
    recv_content = recv_data.decode("gbk")
    print("接收客戶端的數(shù)據(jù)為:", recv_content)
    # 準(zhǔn)備發(fā)送的數(shù)據(jù)
    send_data = "ok, 問(wèn)題正在處理中...".encode("gbk")
    # 發(fā)送數(shù)據(jù)給客戶端
    service_client_socket.send(send_data)
    # 關(guān)閉服務(wù)與客戶端的套接字, 終止和客戶端通信的服務(wù)
    service_client_socket.close()
    # 關(guān)閉服務(wù)端的套接字, 終止和客戶端提供建立連接請(qǐng)求的服務(wù)
    tcp_server_socket.close()

執(zhí)行結(jié)果:

客戶端的ip地址和端口號(hào): ('172.16.47.209', 52472)
接收數(shù)據(jù)的長(zhǎng)度為: 5
接收客戶端的數(shù)據(jù)為: hello

說(shuō)明:

  • 更換服務(wù)端端口號(hào)
  • 設(shè)置端口號(hào)復(fù)用(推薦大家使用),也就是說(shuō)讓服務(wù)端程序退出后端口號(hào)立即釋放。

解決辦法有兩種:

更換服務(wù)端端口號(hào)設(shè)置端口號(hào)復(fù)用(推薦大家使用),也就是說(shuō)讓服務(wù)端程序退出后端口號(hào)立即釋放。

設(shè)置端口號(hào)復(fù)用的代碼如下:

# 參數(shù)1: 表示當(dāng)前套接字
# 參數(shù)2: 設(shè)置端口號(hào)復(fù)用選項(xiàng)
# 參數(shù)3: 設(shè)置端口號(hào)復(fù)用選項(xiàng)對(duì)應(yīng)的值
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)

網(wǎng)絡(luò)調(diào)試助手充當(dāng)客戶端程序:

TCP網(wǎng)絡(luò)應(yīng)用程序的注意點(diǎn)

  • 當(dāng) TCP 客戶端程序想要和 TCP 服務(wù)端程序進(jìn)行通信的時(shí)候必須要先建立連接
  • TCP 客戶端程序一般不需要綁定端口號(hào),因?yàn)榭蛻舳耸侵鲃?dòng)發(fā)起建立連接的。
  • TCP 服務(wù)端程序必須綁定端口號(hào),否則客戶端找不到這個(gè) TCP 服務(wù)端程序。
  • listen 后的套接字是被動(dòng)套接字,只負(fù)責(zé)接收新的客戶端的連接請(qǐng)求,不能收發(fā)消息。
  • 當(dāng) TCP 客戶端程序和 TCP 服務(wù)端程序連接成功后, TCP 服務(wù)器端程序會(huì)產(chǎn)生一個(gè)新的套接字,收發(fā)客戶端消息使用該套接字。
  • 關(guān)閉 accept 返回的套接字意味著和這個(gè)客戶端已經(jīng)通信完畢。
  • 關(guān)閉 listen 后的套接字意味著服務(wù)端的套接字關(guān)閉了,會(huì)導(dǎo)致新的客戶端不能連接服務(wù)端,但是之前已經(jīng)接成功的客戶端還能正常通信。
  • 當(dāng)客戶端的套接字調(diào)用 close 后,服務(wù)器端的 recv 會(huì)解阻塞,返回的數(shù)據(jù)長(zhǎng)度為0,服務(wù)端可以通過(guò)返回?cái)?shù)據(jù)的長(zhǎng)度來(lái)判斷客戶端是否已經(jīng)下線,反之服務(wù)端關(guān)閉套接字,客戶端的 recv 也會(huì)解阻塞,返回的數(shù)據(jù)長(zhǎng)度也為0。

案例:多任務(wù)版TCP服務(wù)端程序開(kāi)發(fā)

1. 需求

目前我們開(kāi)發(fā)的TCP服務(wù)端程序只能服務(wù)于一個(gè)客戶端,如何開(kāi)發(fā)一個(gè)多任務(wù)版的TCP服務(wù)端程序能夠服務(wù)于多個(gè)客戶端呢?

完成多任務(wù),可以使用線程,比進(jìn)程更加節(jié)省內(nèi)存資源。

2. 具體實(shí)現(xiàn)步驟

  • 編寫(xiě)一個(gè)TCP服務(wù)端程序,循環(huán)等待接受客戶端的連接請(qǐng)求
  • 當(dāng)客戶端和服務(wù)端建立連接成功,創(chuàng)建子線程,使用子線程專(zhuān)門(mén)處理客戶端的請(qǐng)求,防止主線程阻塞
  • 把創(chuàng)建的子線程設(shè)置成為守護(hù)主線程,防止主線程無(wú)法退出。

3. 多任務(wù)版TCP服務(wù)端程序的示例代碼:

import socket
import threading
 
 
# 處理客戶端的請(qǐng)求操作
def handle_client_request(service_client_socket, ip_port):
    # 循環(huán)接收客戶端發(fā)送的數(shù)據(jù)
    while True:
        # 接收客戶端發(fā)送的數(shù)據(jù)
        recv_data = service_client_socket.recv(1024)
        # 容器類(lèi)型判斷是否有數(shù)據(jù)可以直接使用if語(yǔ)句進(jìn)行判斷,如果容器類(lèi)型里面有數(shù)據(jù)表示條件成立,否則條件失敗
        # 容器類(lèi)型: 列表、字典、元組、字符串、set、range、二進(jìn)制數(shù)據(jù)
        if recv_data:
            print(recv_data.decode("gbk"), ip_port)
            # 回復(fù)
            service_client_socket.send("ok,問(wèn)題正在處理中...".encode("gbk"))
 
        else:
            print("客戶端下線了:", ip_port)
            break
    # 終止和客戶端進(jìn)行通信
    service_client_socket.close()
 
 
if __name__ == '__main__':
    # 創(chuàng)建tcp服務(wù)端套接字
    tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 設(shè)置端口號(hào)復(fù)用,讓程序退出端口號(hào)立即釋放
    tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
    # 綁定端口號(hào)
    tcp_server_socket.bind(("", 9090))
    # 設(shè)置監(jiān)聽(tīng), listen后的套接字是被動(dòng)套接字,只負(fù)責(zé)接收客戶端的連接請(qǐng)求
    tcp_server_socket.listen(128)
    # 循環(huán)等待接收客戶端的連接請(qǐng)求
    while True:
        # 等待接收客戶端的連接請(qǐng)求
        service_client_socket, ip_port = tcp_server_socket.accept()
        print("客戶端連接成功:", ip_port)
        # 當(dāng)客戶端和服務(wù)端建立連接成功以后,需要?jiǎng)?chuàng)建一個(gè)子線程,不同子線程負(fù)責(zé)接收不同客戶端的消息
        sub_thread = threading.Thread(target=handle_client_request, args=(service_client_socket, ip_port))
        # 設(shè)置守護(hù)主線程
        sub_thread.setDaemon(True)
        # 啟動(dòng)子線程
        sub_thread.start()
 
 
    # tcp服務(wù)端套接字可以不需要關(guān)閉,因?yàn)榉?wù)端程序需要一直運(yùn)行
    # tcp_server_socket.close()

執(zhí)行結(jié)果:

客戶端連接成功: ('172.16.47.209', 51528)
客戶端連接成功: ('172.16.47.209', 51714)
hello1 ('172.16.47.209', 51528)
hello2 ('172.16.47.209', 51714)

socket的send和recv原理剖析

1. 認(rèn)識(shí)TCP socket的發(fā)送和接收緩沖區(qū)

當(dāng)創(chuàng)建一個(gè)TCP socket對(duì)象的時(shí)候會(huì)有一個(gè)發(fā)送緩沖區(qū)和一個(gè)接收緩沖區(qū),這個(gè)發(fā)送和接收緩沖區(qū)指的就是內(nèi)存中的一片空間。

2. send原理剖析

send是不是直接把數(shù)據(jù)發(fā)給服務(wù)端?

不是,要想發(fā)數(shù)據(jù),必須得通過(guò)網(wǎng)卡發(fā)送數(shù)據(jù),應(yīng)用程序是無(wú)法直接通過(guò)網(wǎng)卡發(fā)送數(shù)據(jù)的,它需要調(diào)用操作系統(tǒng)接口,也就是說(shuō),應(yīng)用程序把發(fā)送的數(shù)據(jù)先寫(xiě)入到發(fā)送緩沖區(qū)(內(nèi)存中的一片空間),再由操作系統(tǒng)控制網(wǎng)卡把發(fā)送緩沖區(qū)的數(shù)據(jù)發(fā)送給服務(wù)端網(wǎng)卡 。

3. recv原理剖析

recv是不是直接從客戶端接收數(shù)據(jù)?

不是,應(yīng)用軟件是無(wú)法直接通過(guò)網(wǎng)卡接收數(shù)據(jù)的,它需要調(diào)用操作系統(tǒng)接口,由操作系統(tǒng)通過(guò)網(wǎng)卡接收數(shù)據(jù),把接收的數(shù)據(jù)寫(xiě)入到接收緩沖區(qū)(內(nèi)存中的一片空間),應(yīng)用程序再?gòu)慕邮站彺鎱^(qū)獲取客戶端發(fā)送的數(shù)據(jù)

4. send和recv原理剖析圖

說(shuō)明:

  • 發(fā)送數(shù)據(jù)是發(fā)送到發(fā)送緩沖區(qū)
  • 接收數(shù)據(jù)是從接收緩沖區(qū) 獲取

到此這篇關(guān)于Python網(wǎng)絡(luò)編程(二)編寫(xiě)TCP協(xié)議程序的文章就介紹到這了,更多相關(guān)Python TCP協(xié)議程序內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python階乘求和的代碼詳解

    Python階乘求和的代碼詳解

    在本篇文章里小編給大家整理的是關(guān)于Python階乘求和的代碼實(shí)例,有需要的朋友們可以跟著學(xué)習(xí)下。
    2020-02-02
  • python中os.remove()用法及注意事項(xiàng)

    python中os.remove()用法及注意事項(xiàng)

    在本篇內(nèi)容里小編給大家分享的是一篇關(guān)于python中os.remove()用法及注意事項(xiàng),有需要的朋友們可以跟著學(xué)習(xí)下。
    2021-01-01
  • Python讀取ZIP和TAR格式壓縮包的實(shí)現(xiàn)

    Python讀取ZIP和TAR格式壓縮包的實(shí)現(xiàn)

    本文介紹了使用Python讀取ZIP和TAR格式的壓縮包,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2025-01-01
  • Python執(zhí)行遺傳編程gplearn庫(kù)使用實(shí)例探究

    Python執(zhí)行遺傳編程gplearn庫(kù)使用實(shí)例探究

    這篇文章主要為大家介紹了Python執(zhí)行遺傳編程gplearn庫(kù)使用實(shí)例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • python通過(guò)Matplotlib繪制常見(jiàn)的幾種圖形(推薦)

    python通過(guò)Matplotlib繪制常見(jiàn)的幾種圖形(推薦)

    這篇文章主要介紹了使用matplotlib對(duì)幾種常見(jiàn)的圖形進(jìn)行繪制方法的相關(guān)資料,需要的朋友可以參考下
    2021-08-08
  • 在Django的session中使用User對(duì)象的方法

    在Django的session中使用User對(duì)象的方法

    這篇文章主要介紹了在Django的session中使用User對(duì)象的方法,Django是眾Python web開(kāi)發(fā)框架中人氣最高的一個(gè),需要的朋友可以參考下
    2015-07-07
  • python快速進(jìn)階利用Tkinter定制一個(gè)信息提示框

    python快速進(jìn)階利用Tkinter定制一個(gè)信息提示框

    這篇文章主要介紹了python快速進(jìn)階利用Tkinter定制一個(gè)信息提示框,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • Python模擬三級(jí)菜單效果

    Python模擬三級(jí)菜單效果

    這篇文章主要為大家詳細(xì)介紹了Python模擬三級(jí)菜單效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • Python多線程正確用法實(shí)例解析

    Python多線程正確用法實(shí)例解析

    這篇文章主要介紹了Python多線程正確用法實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-05-05
  • 老生常談python字典用法

    老生常談python字典用法

    python 創(chuàng)建字典可以使用 dict 函數(shù),或者使用花括號(hào),用花括號(hào)的方式更為常見(jiàn)。本文給大家介紹python字典用法,感興趣的朋友跟隨小編一起看看吧
    2021-12-12

最新評(píng)論

平度市| 宜丰县| 侯马市| 吉安县| 子长县| 长汀县| 信丰县| 本溪市| 新干县| 武川县| 石楼县| 高台县| 梅河口市| 高雄县| 虹口区| 长阳| 前郭尔| 景泰县| 南充市| 丰顺县| 咸宁市| 静海县| 丰镇市| 长沙县| 吴川市| 永丰县| 社会| 新河县| 武安市| 缙云县| 高唐县| 衡山县| 额敏县| 永吉县| 山阳县| 通州市| 杭州市| 嘉祥县| 威海市| 东台市| 新丰县|