Python - 網(wǎng)絡(luò)編程

socket簡(jiǎn)介

? socket(簡(jiǎn)稱 套接字)是進(jìn)程之間通信的一種方式,與其他進(jìn)程間通信的一個(gè)主要不同是:它能實(shí)現(xiàn)不同主機(jī)間的進(jìn)程通信。

創(chuàng)建套接字

函數(shù)scocket.socket創(chuàng)建一個(gè)socket,該函數(shù)有兩個(gè)參數(shù):

? 1、AF_INET(用于internet進(jìn)程間的通信) 或者 AF_UNIX(用于同一臺(tái)機(jī)器進(jìn)程間通信),工作中常用AF_INET

? 2、SOCKET_STREAM(流式套接字,主要用于TCP協(xié)議) 或者 SOCKET_DGRAM(數(shù)據(jù)報(bào)套接字,主要用于UDP)

import socket
# 1、創(chuàng)建TCP套接字
socket = socket.socket(socket.AF_INET, socket.SOCKET_STREAM)
# 2、使用套接字
# ......
# 3、使用完成后關(guān)閉套接字
socket.close()

socket套接字:UDP協(xié)議

? 1、創(chuàng)建套接字并使用UDP協(xié)議創(chuàng)建一個(gè)Client

import socket

# 創(chuàng)建udp套接字
udp_client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 指定一個(gè)ip地址 與 端口號(hào);ip地址用于標(biāo)識(shí)網(wǎng)絡(luò)中的計(jì)算機(jī),端口號(hào)可以理解用于標(biāo)識(shí)該ip地址計(jì)算機(jī)中的應(yīng)用程序,這里的ip地址是筆者電腦的ip
ip_port = ('192.168.0.104', 8000)

# 準(zhǔn)備向指定的ip與端口發(fā)起通信
send_data = input("請(qǐng)輸入要發(fā)送的信息:")

# 發(fā)送通信信息,sendto發(fā)送的數(shù)據(jù)是byte(字節(jié))類型,需要使用encode將其轉(zhuǎn)碼,windows之間通常使用utf-8
udp_client.sendto(send_data.encode("utf-8"), ip_port)

# 使用完成后關(guān)閉
udp_client.close()

上述代碼可以理解為一個(gè)客戶端使用UDP協(xié)議向服務(wù)器發(fā)起通信

? 2、創(chuàng)建套接字并使用UDP協(xié)議創(chuàng)建一個(gè)Server

import socket

# 創(chuàng)建udp套接字
udp_server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 指定一個(gè)ip地址 與 端口號(hào);這里的ip可以不用填寫,即本機(jī)ip(127.0.0.1)
ip_port = ('', 8000)

# 綁定ip與端口,禁止系統(tǒng)自動(dòng)分配
udp_server.bind(ip_port)

# 等待客戶端發(fā)起通信信息,此時(shí)處于堵塞狀態(tài),1024表示本次接收的最大字節(jié)數(shù)
recv_data = udp_server.recvfrom(1024)

# 打印接收的數(shù)據(jù),接收的數(shù)據(jù)是一個(gè)元組,元組的第一個(gè)元素即是客戶端發(fā)起通信的數(shù)據(jù)信息,第二個(gè)元素是一個(gè)元組(ip與端口)
print(recv_data[0].decode("utf-8"))

# 使用完成后關(guān)閉
udp_server.close()

可以看出client的代碼與server的代碼幾乎一樣,不同的是client的ip地址與端口指向的是服務(wù)器;server的ip地址與端口標(biāo)識(shí)的是本機(jī),并且使用了bind進(jìn)行了ip與port的綁定。

(演示時(shí)兩個(gè)程序在同一電腦上使用請(qǐng)使用同一ip地址;并且使用client率先向服務(wù)器發(fā)起通信)

socket套接字:TCP協(xié)議

? 1、創(chuàng)建套接字并使用TCP協(xié)議創(chuàng)建一個(gè)Client

import socket

# 創(chuàng)建TCP套接字
tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 指定一個(gè)ip地址 與 端口號(hào)
ip_port = ('192.168.0.104', 8000)

# 連接指定的ip與端口
tcp_client.connect(ip_port)

# 準(zhǔn)備向指定的ip與端口的服務(wù)器發(fā)起請(qǐng)求
send_data = input("請(qǐng)輸入要發(fā)送的信息:\n")

# 發(fā)送信息請(qǐng)求,encode編碼,windows之間可以忽略不寫
tcp_client.send(send_data.encode())

# 服務(wù)器返回的數(shù)據(jù),并使用decode解碼
server_recv_data = tcp_socket.recv(128).decode()
# 將返回的數(shù)據(jù)打印
print(server_recv_data)

# 關(guān)閉套接字
tcp_client.close()

? 2、創(chuàng)建套接字并使用TCP協(xié)議創(chuàng)建一個(gè)Server

import socket

# 創(chuàng)建tcp套接字
tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 指定一個(gè)ip地址 與 端口號(hào)并進(jìn)行綁定
ip_port = ('', 8000)
tcp_server.bind(ip_port)

# 使用 listen 將套接字變?yōu)榭梢员粍?dòng)連接,最多連接數(shù)128
tcp_server.listen(128)

# 等待客戶端連接,返回值是一個(gè)元組,阻塞狀態(tài)
client_socket, client_addr = tcp_socket.accept()
# 元組的第一個(gè)元素是請(qǐng)求該服務(wù)器的客戶端的socket套接字對(duì)象,第二個(gè)元素是請(qǐng)求該服務(wù)器的客戶端的ip與port
print("Client_addr:",client_addr)

# 接收客戶端發(fā)送的請(qǐng)求,decode解碼并打印
recv_data = client_socket.recv(1024).decode()
print("Client_data:",recv_data)

# 向客戶端返回的 數(shù)據(jù)為:'Hello!'+請(qǐng)求該服務(wù)器的客戶端的ip與port
send_data = "Hello!"+str(client_addr[0])+':'+str(client_addr[1])
# 返回?cái)?shù)據(jù)
client_socket.send(send_data.encode())

# 關(guān)閉請(qǐng)求的客戶端的套接字
client_socket.close()
# 使用完成后關(guān)閉
tcp_server.close()

TCP的socket套接字與UDP稍有不同,在同一機(jī)器上演示TCP協(xié)議時(shí),需要注意ip與port,并且需要先運(yùn)行tcp_server程序再運(yùn)行tcp_client發(fā)送請(qǐng)求

總結(jié)

socket 的使用流程可以大致分為:

? 1、創(chuàng)建 tcp/udp 套接字對(duì)象

import socket
#--------------------TCP----------------------
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#--------------------UDP----------------------
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

? 2、指定 ip與port

ip_port = ('127.0.0.1', 8000)

? 如果是服務(wù)器,則需要進(jìn)行 bind 綁定操作;

#--------------------TCP-server---------------------
tcp_server.bind(ip_port)
#--------------------UDP-server---------------------
udp_server.bind(ip_port)

? 如果是TCP協(xié)議服務(wù)端還需要使用 listen 將套接字變?yōu)楸粍?dòng)連接狀態(tài),并且還需要使用 accept() 等待客戶端連接

#--------------------TCP-server---------------------
tcp_server.listen(128)
client_socket, client_addr = tcp_socket.accept()

? 如果是TCP協(xié)議需要使用 connect 連接指定的服務(wù)器

#--------------------TCP-client---------------------
tcp_client.connect(ip_port)

? 3、客戶端向服務(wù)端發(fā)送數(shù)據(jù)信息

#--------------------TCP-client---------------------
tcp_client.send(send_data.encode())
#--------------------UDP-client---------------------
udp_client.sendto(send_data.encode("utf-8"), ip_port)

? 4、服務(wù)器處理客戶端發(fā)送過(guò)來(lái)的數(shù)據(jù)

#--------------------UDP-server---------------------
recv_data = udp_server.recvfrom(1024)
print(recv_data[0].decode("utf-8"))
#--------------------TCP-server---------------------
client_socket, client_addr = tcp_socket.accept()
print("Client_addr:",client_addr)
recv_data = client_socket.recv(1024).decode()
print("Client_data:",recv_data)

? TCP協(xié)議進(jìn)行返回?cái)?shù)據(jù)操作

#--------------------TCP-sever---------------------
send_data = "Hello!"
client_socket.send(send_data.encode())

? UDP一般不會(huì)進(jìn)行返回?cái)?shù)據(jù)操作

? 如果是 TCP_server 端在關(guān)閉socket套接字之前還需要關(guān)閉請(qǐng)求的客戶端的套接字

#--------------------TCP-server---------------------
client_socket.close()

? 6、關(guān)閉 socket 套接字

#--------------------UDP----------------------
udp_client.close()
udp_server.closer()
#--------------------TCP----------------------
tcp_client.close()
tcp_server.close()

?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容