第十二章 網絡編程

第十二章 網絡編程

網絡協議概述

通信協議
協議即規則,就好比汽車上路要遵守交通規則一樣,為了使全世界不同類型的計算機都可以連接起來,所以制定了一套全球通用的通信協議——Internet協議。有了Internet協議,任何私有網絡,只要支持這個協議,就可以接入互聯網。

Internet協議主要的協議和層次關系:
在這里插入圖片描述

?
IP:

  • IP協議是整個TCP/IP協議族的核心
  • IP地址就是互聯網上計算機的唯一標識
  • 目前的IP地址有兩種表示方式,即IPv4和IPv6
  • 在命令行下使用 ipconfig 命令可以查看本機的IP地址

在這里插入圖片描述

TCP協議與UDP協議的區別

TCP:
TCP(Transmission Control Protocol)協議即傳輸控制協議,是建立在IP協議基礎之上的。TCP協議負責兩臺計算機之間建立可靠連接,保證數據包按順序發送到。它是一種可靠的、一對一的、面向有連接的通信協議。

在這里插入圖片描述
在這里插入圖片描述

TCP是可靠的協議,這源于TCP的三次握手
在這里插入圖片描述

UDP:
UDP(User Datagram Protocol)協議即用戶數據包協議,它是面向無連接的協議,只要知道對方的IP地址和端口,就可以直接發送數據包,由于是面向無連接的,所以無法保證數據一定會到達接收方。

端口號:

  • 區分計算機中運行的應用程序的整數
  • 端口號的取值范圍是0到65535,一共65536個,其中80這個端口號分配給了HTTP服務,21這個端口號分配給了FTP服務。3306分配給了MySQL數據庫,1521分配給了Oracle數據庫,1433分配給了SQL Server數據庫。

TCP協議與UDP協議的區別:

TCP協議UDP協議
連接方面面向連接的面向無連接
安全方面傳輸消息可靠、不丟失、按順序到達無法保證不丟包
傳輸效率方面傳輸效率相對較低傳輸效率高
連接對象數量方面只能是點對點、一對一支持一對一、一對多、多對多的交互通信

TCP協議:面向連接的、可靠的、不丟失的、按順序到達的,但傳輸效率相對較低,只能實現點對點,一對一的數據傳輸。

UDP協議:面向無連接、無法保證不丟包,但傳輸效率高,可以實現一對一、一對多、多對多的交互通信。

Socket套接字

前面提到IP協議、TCP協議和UDP協議,那么這些協議如何落實到程序中呢?

在Python中有一個類——socket,要想編寫網絡通信程序就一定需要用到socket類。

Socket套接字是用于描述IP地址和端口號的。

在這里插入圖片描述

Socket模塊可以實現TCP編程,也可以實現UDP編程。

socket模塊中socket類的常用方法:

方法名稱功能描述
bind((ip,port))綁定IP地址和端口
listen(N)開始TCP監聽,N表示操作系統掛起的最大連接數量,取值范圍1-5之間,一般設置為5
accept()被動接收TCP客戶端連接,阻塞式
connect((ip,port))主動初始化TCP服務器連接
recv(size)接收TCP數據,返回值為字符串類型,size表示要接收的最大數據量
send(str)發送TCP數據,返回值是要發送的字節數量
sendall(str)完整發送TCP數據,將str中的數據發送到連接的套接字,返回之前嘗試發送所有數據,如果成功為None,失敗拋出異常
recvfrom()接收UDP數據,返回值為一個元組(data,address),data表示接收的數據,address表示發送數據的套接字地址
sendto(data,(ip,port))發送UDP數據,返回值是發送的字節數
close()關閉套接字

TCP服務器端代碼的編寫

由于TCP協議是點對點的、一對一的,需要建立連接才可以進行交互的通信,所以TCP編程分為客戶端編程和TCP服務器端編程。

TCP服務器端編程的步驟:

  1. 使用socket類創建一個套接字對象
  2. 使用bind((ip,port))方法綁定IP地址和端口號
  3. 使用listen()方法開始TCP監聽
  4. 使用accept()方法等待客戶端的連接
  5. 使用recv()/send()方法接收/發送數據
  6. 使用close()關閉套接字
# 服務器端
from socket import socket, AF_INET, SOCK_STREAM# 從socket模塊中導入socket類
# 參數AF_INET用于Internet之間的進程通信
# 參數SOCK_STREAM表示的是用TCP協議編程
# AF_INET、SOCK_STREAM大寫說明這是常量# (1)創建socket對象
server_socket = socket(AF_INET, SOCK_STREAM)  # AF_INET用于Internet之間的進程通信,SOCK_STREAM表示的是用TCP協議編程
# (2)綁定IP地址和端口
ip = '127.0.0.1'  # 本機的IP地址,等同于 localhost
port = 8888  # 端口號
server_socket.bind((ip, port))# (3)使用listen()開始監聽
server_socket.listen(5)
print('服務器已啟動')# (4)等待客戶端的連接
# 客戶端發送過來一個socket對象,以及地址。這里用的是系列解包賦值
client_socket, client_addr = server_socket.accept()  # 返回的是一個元組,使用系列解包賦值# (5)接收來自客戶端的數據
data = client_socket.recv(1024)  # recv()接收數據
# 客戶端發送過來時需要編碼,服務器端接收時要解碼
print('客戶端發送過來的數據為:', data.decode('utf-8'))  # 解碼# (6) 關閉socket
server_socket.close()

在這里插入圖片描述

TCP客戶端代碼的編寫

TCP客戶端編程的步驟:

  1. 使用socket類創建一個套接字對象
  2. 使用connect((host,port))設置連接的主機IP和主機設置的端口號
  3. 使用recv() / send()方法接收/發送數據
  4. 使用close()關閉套接字

這里我們需要新建一個Python項目來代表另一臺電腦:
在這里插入圖片描述

選擇New Window打開,這樣就會打開兩個PyCharm,每一個PyCharm就相當于一臺電腦。

在這里插入圖片描述
?

# 客戶端
from socket import socket# (1)創建Socket對象
client_socket = socket()
# (2)IP地址和主機接口,向服務器端發送連接請求
ip = '127.0.0.1'  # 要連接的主機的IP地址
port = 8888
client_socket.connect((ip, port))
print('----------與服務器連接建立成功------------')# (3)發送數據
# 客戶端發送時需要編碼
client_socket.send('Welcome to python world'.encode('utf-8'))# (4)關閉socket
client_socket.close()
print('發送完畢')

注意
服務器端和客戶端都編寫好之后,一定要先啟動服務器端,然后啟動客戶端,服務器端等待客戶端發送連接。

當客戶端和服務器端的連接建立好后,客戶端和服務器端的地位是相等的,誰先發送數據都可以。只不過在上面的例子中是客戶端先發送的數據,服務器端接收數據。

TCP編程客戶端與服務器端啟動運行有先后,先啟動運行服務器端再啟動運行客戶端,連接建立之后雙方誰先發送數據均可。

圖示TCP通信過程:
在這里插入圖片描述

TCP多次通信服務器端代碼編寫

在上面的例子中客戶端與服務器端只進行了一次數據交互,事實上兩者之間可以進行多次數據交互。

客戶端與服務器端進行多次數據交互可以使用循環來實現。首先兩者之間交互的次數不知道,所以應使用while循環實現。

# 多次通信。服務器端
# from socket import socket, AF_INET, SOCK_STREAM
import socket  # 這次使用這種導入方式# 從socket模塊中導入socket類
# 參數AF_INET用于Internet之間的進程通信
# 參數SOCK_STREAM表示的是用TCP協議編程
# AF_INET、SOCK_STREAM大寫說明這是常量# (1)創建socket對象
socket_obj = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # AF_INET用于Internet之間的進程通信,SOCK_STREAM表示的是用TCP協議編程
# (2)綁定IP地址和端口
socket_obj.bind(('127.0.0.1', 8888))# (3)使用listen()開始監聽
socket_obj.listen(5)  # 設置最大的連接數量--->5
print('服務器已啟動')# (4)等待客戶端的TCP連接
# 客戶端發送過來一個socket對象,以及地址(IP地址)。這里用的是系列解包賦值
client_socket, client_addr = socket_obj.accept()  # 返回的是一個元組,使用系列解包賦值# 服務器端接收/發送數據時用的都是客戶端的socket對象(client_socket)
# (5)接收來自客戶端的數據
# while循環的四個步驟,info是初始化變量
info = client_socket.recv(1024).decode('utf-8')  # recv()接收數據.客戶端發送過來時需要編碼,服務器端接收時要解碼
while info != 'bye':  # 條件判斷,中間的是循環體if info != '':print('接收到的數據是:', info)# 準備發送數據data = input('請輸入要發送的數據:')# 服務器端回復客戶端client_socket.send(data.encode('utf-8'))if data == 'bye':breakinfo = client_socket.recv(1024).decode('utf-8')  # 改變變量# (6) 關閉socket對象
client_socket.close()  # 接收到的客戶端的socket對象需要關閉
socket_obj.close()  # 服務器端的socket對象需要關閉

注意
服務器端接收/發送數據時用的都是客戶端的socket對象(client_socket)。【見上方循環體】

TCP多次通信客戶端代碼編寫

# 多次通信。客戶端
import socket# (1)創建Socket對象
client_socket = socket.socket()
# (2)主機IP地址和主機接口,向服務器端發送連接請求
client_socket.connect(('127.0.0.1', 8888))
print('----------與服務器連接建立成功------------')# (3)客戶端先發送數據(在我們多次通信的例子中,編寫的是服務器端先接收數據)
# while循環的四個步驟
info = ''
while info != 'bye':# 準備發送的數據send_data = input('請客戶端輸入要發送的數據:')client_socket.send(send_data.encode('utf-8'))# 判斷if send_data == 'bye':break  # 退出循環# 接收一條數據info = client_socket.recv(1024).decode('utf-8')print('收到服務器的響應數據:', info)# (4)關閉socket
client_socket.close()
print('發送完畢')

在這里插入圖片描述

UDP的一次雙向通信

UDP協議是面向無連接的,只需要知道對方的IP地址和端口號就可以發送數據包,但是它不保證數據包能夠一定到達。

UDP編程客戶端(發送方)步驟:

  1. 使用socket類創建一個套接字對象
  2. 準備發送的數據
  3. 定義接收方的IP地址和端口號
  4. 使用sendto()/recvfrom()方法發送/接收數據
  5. 關閉socket對象

UDP編程服務器端(接收方)步驟:

  1. 使用socket類創建一個套接字對象
  2. 使用bind()方法綁定IP地址和端口號
  3. 使用sendto()/recvfrom()方法發送/接收數據
  4. 關閉socket對象

UDP編程接收方與發送方啟動運行無先后,但先啟動運行發送方,數據包會丟包,因此一般先啟動接收方。

圖示UDP通信過程:
在這里插入圖片描述

UDP客戶端(發送端)代碼編寫

# UDP客戶端(發送端)
from socket import socket, AF_INET, SOCK_DGRAM# 從socket模塊中導入socket類
# 參數AF_INET用于Internet之間的進程通信
# 參數SOCK_DGRAM表示的是用UDP協議編程
# AF_INET、SOCK_DGRAM大寫說明這是常量# (1)創建Socket對象
send_socket = socket(AF_INET, SOCK_DGRAM)
# (2)準備發送數據
data = input('請輸入要發送的數據:')
# (3)指定接收方的IP地址和端口
ip_port = ('127.0.0.1', 8888)# (4)發送數據
send_socket.sendto(data.encode('utf-8'), ip_port)# (5)接收來自接收方的回復數據
# recvfrom()返回的是一個元組-->(接收到的數據,從哪里獲得的數據即地址)
recv_data, addr = send_socket.recvfrom(1024)
print('接收到的數據為:', recv_data.decode('utf-8'))# (4)關閉socket
send_socket.close()
print('發送完畢')

UDP服務器端(接收端)代碼編寫

# UDP服務器端(接收方)
from socket import socket, AF_INET, SOCK_DGRAM# 從socket模塊中導入socket類
# 參數AF_INET用于Internet之間的進程通信
# 參數SOCK_DGRAM表示的是用UDP協議編程
# AF_INET、SOCK_DGRAM大寫說明這是常量# (1)創建socket對象
recv_socket = socket(AF_INET, SOCK_DGRAM)  # AF_INET用于Internet之間的進程通信,SOCK_DGRAM表示的是用UDP協議編程
# (2)綁定IP地址和端口
recv_socket.bind(('127.0.0.1', 8888))# (3)接收來自發送方的數據
# recvfrom()返回的是一個元組-->(接收到的數據,從哪里獲得的數據即地址)
recv_data, addr = recv_socket.recvfrom(1024)
print('接收到的數據為:', recv_data.decode('utf-8'))# (4)準備回復對方的數據
data = input('請輸入要回復的數據:')# (5)回復
recv_socket.sendto(data.encode('utf-8'), addr)# (6) 關閉socket對象
recv_socket.close()

運行效果

在這里插入圖片描述

UDP模擬客服咨詢小程序

聊天軟件一般都是使用UDP編程實現的,這里我們使用UDP編程模擬客服咨詢。

兩者之間交互的次數不知道,所以應使用while循環實現。

客服人員(接收方)

# UDP模擬客服咨詢小程序,客服人員(接收方)
from socket import socket, AF_INET, SOCK_DGRAM# 從socket模塊中導入socket類
# 參數AF_INET用于Internet之間的進程通信
# 參數SOCK_DGRAM表示的是用UDP協議編程
# AF_INET、SOCK_DGRAM大寫說明這是常量# (1)創建socket對象
recv_socket = socket(AF_INET, SOCK_DGRAM)  # AF_INET用于Internet之間的進程通信,SOCK_DGRAM表示的是用UDP協議編程
# (2)綁定IP地址和端口
recv_socket.bind(('127.0.0.1', 8888))while True:# (3)接收來自發送方的數據# recvfrom()返回的是一個元組-->(接收到的數據,從哪里獲得的數據即地址)recv_data, addr = recv_socket.recvfrom(1024)print('客戶說:', recv_data.decode('utf-8'))if recv_data.decode('utf-8') == 'bye':break# (4)準備回復對方的數據data = input('客服回復:')# (5)回復recv_socket.sendto(data.encode('utf-8'), addr)# (6) 關閉socket對象
recv_socket.close()

客戶(發送方)

# UDP模擬客服咨詢小程序,客戶(發送方)
from socket import socket, AF_INET, SOCK_DGRAM# 從socket模塊中導入socket類
# 參數AF_INET用于Internet之間的進程通信
# 參數SOCK_DGRAM表示的是用UDP協議編程
# AF_INET、SOCK_DGRAM大寫說明這是常量# (1)創建Socket對象
send_socket = socket(AF_INET, SOCK_DGRAM)
while True:# (2)準備發送數據data = input('客戶說:')# (3)指定接收方的IP地址和端口ip_port = ('127.0.0.1', 8888)# (4)發送數據send_socket.sendto(data.encode('utf-8'), ip_port)if data == 'bye':break# (5)接收來自接收方的回復數據# recvfrom()返回的是一個元組-->(接收到的數據,從哪里獲得的數據即地址)recv_data, addr = send_socket.recvfrom(1024)print('客服回復:', recv_data.decode('utf-8'))# (4)關閉socket
send_socket.close()
print('發送完畢')

運行效果

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/14162.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/14162.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/14162.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【mysql】【docker】mysql8-互為主從

🌸🌸 Linux/docker-compose/mysql8 互為主從 優雅部署 🌸🌸 記錄下兩臺Linux的mysql需要熱備份,互為主從,后期加上keepalived實現高可用切換 參考博客:答 案 🌸 一、準備文件 這里…

圖形學初識--直線插值算法

文章目錄 為什么需要插值算法?插值算法是什么?有哪些常見的插值算法呢?1. 線性插值(Linear Interpolation)2. 多項式插值(Polynomial Interpolation)3. 樣條插值(Spline Interpolati…

Blazor 下支持 Azure AD 的多套登錄方案

比如上圖配置了兩套不同的登錄方案,各有自己的 TenantId 和 ClientId ,要同時支持他們的登錄(其實在同一套 TenantId 和 ClientId 里面配置多個登錄賬戶不就好了,但是......那套登錄的管理是在客戶自己的Azure AD賬戶管理下的&…

SpringBoot3 解決NoResourceFoundException: No static resource favicon.ico.異常

SpringBoot3 解決NoResourceFoundException: No static resource favicon.ico.異常 spring boot3項目中瀏覽器中訪問報錯找不到favicon.ico,雖然不影響使用,用api工具也可以忽略這個異常,但是防止瀏覽器訪問時出現異常干擾日志,所…

oracle數據庫解析過高分析

解析非常高,通過時間模型可以看到解析占比非常高 解析大致可以分為硬解析( hard parse)、軟解析( soft parse)和軟軟解析( soft soft parse)。如,執行一條 SQL 的時候,如…

星型模型和雪花模型的區別

星型模型和雪花模型都是數據倉庫設計中常用的維度建模方法,它們之間的主要區別在于數據組織結構、數據冗余度、查詢效率、可擴展性和正規化程度等方面: 星型模型 結構特點:星型模型中,一個中心的事實表連接多個維度表&#xff0…

在電腦中,Apple Mobile Device Support程序是什么?

Apple Mobile Device Support 是一項關鍵的后臺服務,它為 Windows 用戶提供了與蘋果 iOS 設備(包括 iPhone、iPad 和 iPod)順暢互動的能力。這項服務的核心功能是為iTunes軟件提供必要的支持,使得用戶能夠將他們的移動設備與電腦連…

Google Find My Device:科技守護,安心無憂

在數字化的時代,我們的生活與各種智能設備緊密相連。而 Google Find My Device 便是一款為我們提供安心保障的實用工具。 一、Find My Decice Netword的定義 谷歌的Find My Device Netword旨在通過利用Android設備的眾包網絡的力量,幫助用戶安全的定位所…

HTML5 歷史、地理位置處理、全屏處理

目錄 歷史HistoryAPI地理位置處理GeolocationAPI全屏處理FullscreenAPIHistoryAPI window.history 對象 window.history 是瀏覽器提供的一個內置對象,它提供了對瀏覽器歷史記錄的訪問和操作能力。通過這個對象,開發者可以實現無刷新頁面跳轉、添加新的瀏覽歷史條目等,從而提…

STM32F4_HAL控制GPIO輸出——跑馬燈實驗

1、GPIO工作模式 1.1 端口輸入數據寄存器(IDR) 1.2 端口輸出數據寄存器(ODR) 1.3 端口置位/復位寄存器(BSRR) 為什么有了 ODR 寄存器,還要這個 BSRR 寄存器呢?我們先看看 BSRR 的寄…

23種設計模式(持續輸出中)

一.設計模式的作用 設計模式是軟件從業人員長期總結出來用于解決特定問題的通用性框架,它提高了代碼的可維護性、可擴展性、可讀性以及復用性。 二.設計模式 1.工廠模式 工廠模式提供了創建對象的接口,而無需制定創建對象的具體類,工廠類…

hive表在HDFS的每個文件的大小加大

配置參數: spark.hadoop.hive.exec.orc.default.stripe.size78643200 spark.hadoop.orc.stripe.size78643200 spark.hadoopRDD.targetBytesInPartition78643200 spark.hadoop.hive.exec.dynamic.partition.modenonstrict spark.sql.sources.partitionOverwriteMode…

華為OD機試 - 剩余銀飾的重量(Java 2024 C卷 100分)

華為OD機試 2024C卷題庫瘋狂收錄中,刷題點這里 專欄導讀 本專欄收錄于《華為OD機試(JAVA)真題(A卷B卷C卷)》。 刷的越多,抽中的概率越大,每一題都有詳細的答題思路、詳細的代碼注釋、樣例測試…

【Python】 如何對對象列表進行排序,有點意思

在Python中,我們經常需要對對象列表進行排序,這可以通過多種方式實現。當對象是一個自定義類實例時,排序通常基于對象的一個或多個屬性。Python提供了內置的sorted()函數和列表的sort()方法,它們都允許我們指定一個排序的關鍵字。…

iPhone徹底刪除的照片怎么恢復?專業技巧助您解憂

在使用iPhone的過程中,我們可能會因為誤操作或其他原因將一些重要的照片徹底刪除。然而,即使照片被徹底刪除,也并不意味著它們就永遠消失了,它們只是被打上了“可覆蓋的空間”的標簽。 在照片被新數據覆蓋之前,我們仍…

C語言學習【C控制語句:循環】

C語言學習【C控制語句:循環】 while循環 /* 根據用戶鍵入的整數求和 */#include "stdio.h"int main(void) {long num;long sum 0L; /* 把sum初始化為0 */int status;printf("Please enter an integer to be summed");printf(&quo…

基于微信小程序的校園捐贈系統的設計與實現

校園捐贈系統是一種便捷的平臺,為校園內的各種慈善活動提供支持和便利。通過該系統,學生、教職員工和校友可以方便地進行捐贈,并了解到相關的項目信息和捐助情況。本文將介紹一個基于Java后端和MySQL數據庫的校園捐贈系統的設計與實現。 技術…

Java日期Date和LocalDateTime的工具類

Date package com.qiangesoft.utils.date;import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date;/*** 日期工具類** author lq* date 2024-05-23*/ public class DateUtil {public static final String[] CHINESE_WEEK_DAY new String[]{&q…

Excel 公式積累

1.獲取當前位置的左側單元格 引用當前單元格左側的第一個單元格:OFFSET(INDIRECT(ADDRESS(ROW(), COLUMN())),0,-1) ROW()返回當前單元格的行號,COLUMN()返回當前單元格的列號。 ADDRESS函數可以根據指定行號和列號獲得工作表中的某個單元格的地址。例如…

go全部版本下載目錄

linux安裝教程: Download and install - The Go Programming Language rm -rf /usr/local/go && tar -C /usr/local -xzf go1.22.3.linux-amd64.tar.gzexport PATH$PATH:/usr/local/go/bin go version 全部版本下載目錄: All releases - Th…