佳木斯湛栽影视文化发展公司

主頁(yè) > 知識(shí)庫(kù) > Python Socket編程詳解

Python Socket編程詳解

熱門(mén)標(biāo)簽:百度AI接口 硅谷的囚徒呼叫中心 呼叫中心市場(chǎng)需求 Win7旗艦版 電話運(yùn)營(yíng)中心 客戶服務(wù) 企業(yè)做大做強(qiáng) 語(yǔ)音系統(tǒng)

背景

關(guān)于Python Socket編程,首先需要了解幾個(gè)計(jì)算機(jī)網(wǎng)絡(luò)的知識(shí),通過(guò)以下的幾個(gè)問(wèn)題,有助于更好的理解Socket編程的意義,以及整個(gè)框架方面的知識(shí):

TCP和UDP協(xié)議本質(zhì)上的區(qū)別?

TCP協(xié)議,面向連接,可靠,基于字節(jié)流的傳輸層通信協(xié)議;UDP協(xié)議無(wú)連接,不可靠,基于數(shù)據(jù)包的傳輸層協(xié)議。

TCP協(xié)議在建立連接的過(guò)程需要經(jīng)歷三次握手,斷開(kāi)連接則需要經(jīng)歷四次揮手,而這建立連接的過(guò)程增加了傳輸過(guò)程中的安全性。
而建立連接的過(guò)程則會(huì)消耗系統(tǒng)的資源,消耗更多的時(shí)間,而相比較UDP協(xié)議傳輸過(guò)程則不會(huì)出現(xiàn)這種問(wèn)題。

總結(jié)來(lái)講,基于TCP協(xié)議傳輸,需要不斷的確認(rèn)對(duì)方是否收到信息,從而建立連接(確認(rèn)過(guò)程次數(shù)有限制,即三次握手),UDP協(xié)議傳輸則
不需要確認(rèn)接收端是否收到信息,只需要將信息發(fā)給對(duì)方。

TCP/IP協(xié)議棧、HTTP協(xié)議、Socket之間的區(qū)別和聯(lián)系?

TCP/IP協(xié)議棧就是一系列網(wǎng)絡(luò)協(xié)議,可以分為四層模型來(lái)分析:應(yīng)用層、傳輸層、網(wǎng)絡(luò)層、鏈路層;

HTTP協(xié)議(超文本傳輸協(xié)議)就是在這一協(xié)議棧中的應(yīng)用層協(xié)議;HTTP協(xié)議簡(jiǎn)單來(lái)說(shuō),它的作用就是規(guī)范數(shù)據(jù)的格式,讓程序能夠方便的識(shí)別,并且收發(fā)雙方都需要遵循同樣的協(xié)議格式進(jìn)行數(shù)據(jù)傳輸。(應(yīng)用層的協(xié)議也和HTTP協(xié)議的作用類(lèi)似,不一樣的是定義不同的數(shù)據(jù)格式。)

Socket可以理解為T(mén)CP/IP協(xié)議棧提供的對(duì)外的操作接口,即應(yīng)用層通過(guò)網(wǎng)絡(luò)協(xié)議進(jìn)行通信的接口。Socket可以使用不同的網(wǎng)絡(luò)協(xié)議進(jìn)行端對(duì)端的通信;

TCP Socket服務(wù)器的通信過(guò)程?

Server端:

建立連接(socket()函數(shù)創(chuàng)建socket描述符、bind()函數(shù)綁定特定的監(jiān)聽(tīng)地址(ip+port)、listen()函數(shù)監(jiān)聽(tīng)socket、accept()阻塞等待客戶端連接)

數(shù)據(jù)交互(read()函數(shù)阻塞等待客戶端發(fā)送數(shù)據(jù)、write()函數(shù)發(fā)送給客戶端數(shù)據(jù))

Client端:

建立連接(socket()函數(shù)創(chuàng)建socket描述符、connect()函數(shù)向指定的監(jiān)聽(tīng)地址發(fā)送連接請(qǐng)求)

數(shù)據(jù)交互(wirte()函數(shù)發(fā)送服務(wù)端數(shù)據(jù)、read()函數(shù)足阻塞等待接受服務(wù)端發(fā)送的數(shù)據(jù))

socket和websocket之間的聯(lián)系?

webosocket是一種通信協(xié)議,不同于HTTP請(qǐng)求,客戶端請(qǐng)求服務(wù)端資源,服務(wù)端響應(yīng)的通信過(guò)程;websocket允許服務(wù)端主動(dòng)
向客戶端推送消息,同時(shí)做到客戶端和服務(wù)端雙向通訊的協(xié)議。(具體底層原理有待后面實(shí)踐,暫時(shí)未接觸)

HTTP,WSGI協(xié)議的聯(lián)系和區(qū)別?

HTTP協(xié)議(超文本傳輸協(xié)議),屬于TCP/IP協(xié)議棧中應(yīng)用層的協(xié)議。用于規(guī)范傳輸數(shù)據(jù)的格式,是一種客戶端和服務(wù)端傳輸?shù)囊?guī)則。

WSGI協(xié)議則是Python定義的Web服務(wù)器和框架程序通信的接口規(guī)則。兩者聯(lián)系不大,強(qiáng)行說(shuō)的話,Python框架程序主要處理的是HTTP請(qǐng)求。

(后期可以實(shí)現(xiàn)一個(gè)WSGI協(xié)議的Python框架,用于處理HTTP請(qǐng)求的實(shí)驗(yàn)。)

主流Web框架,異步Web框架?

主流Web框架:Django、Flask

異步Web框架:Tornado(內(nèi)置異步模塊)、Snaic(Python自帶asyncio)、FastAPI(基于Starlette庫(kù)) 、aiohttp(基于asyncio)

asyncio,aiohttp之間的聯(lián)系?(異步編程)

asyncio是一個(gè)異步IO庫(kù),aiohttp就是基于asyncio的異步HTTP框架(支持客戶端/服務(wù)端)

代碼設(shè)計(jì)

Python提供了基本的socket模塊:

  1. socket模塊;提供了標(biāo)準(zhǔn)的BSD Sockets API;
  2. socketserver模塊:提供了服務(wù)器中心類(lèi),簡(jiǎn)化服務(wù)器的開(kāi)發(fā);

TCP Socket服務(wù)端

socket模塊:

# -*- coding: utf-8 -*-
from socket import socket, AF_INET, SOCK_STREAM

def echo_handler(sock ,address):
	print("Get Connection from address:", address)

	while True:
		response = sock.recv(8192)
		if not response:
			break
		print(f"Got {response}")
		sock.sendall(response)

def echo_server(address, back_log=5):
	sock = socket(AF_INET, SOCK_STREAM)
	sock.bind(address)
	sock.listen(back_log)

	while True:
		sock_client, address = sock.accept()
		echo_handler(sock_client, address)

if __name__ == "__main__":
	echo_server(('localhost', 5000))

代碼詳解:

  • 創(chuàng)建一個(gè)基于IPV4和TCP協(xié)議的Socket,這里AF_INET指的是使用IPV4協(xié)議,SOCK_STREAM指定使用面向流的TCP協(xié)議,綁定監(jiān)聽(tīng)端口,設(shè)置等待連接的最大數(shù)量
  • 創(chuàng)建一個(gè)永久循環(huán),獲取客戶端請(qǐng)求的連接,accept()會(huì)等待并返回一個(gè)客戶端的連接;
  • 連接建立后,等待客戶端數(shù)據(jù),接受完客戶端數(shù)據(jù),然后返回?cái)?shù)據(jù)給客戶端,最后關(guān)閉連接

存在的問(wèn)題:當(dāng)出現(xiàn)多個(gè)客戶端請(qǐng)求時(shí),由于是單個(gè)線程會(huì)發(fā)生阻塞的情況,所以如果需要多線程處理多個(gè)客戶端請(qǐng)求,可以這樣改;

from threading import Thread

while True:
        client_sock, address = sock.accept()
        thread = Thread(target=echo_handler, args=(client_sock, address))
        thread.start()

這樣的話,就會(huì)在每個(gè)客戶端請(qǐng)求的時(shí)候,生成一個(gè)子線程然后處理請(qǐng)求;
(但是存在一個(gè)問(wèn)題:當(dāng)突然大量請(qǐng)求連接,消耗系統(tǒng)資源達(dá)到上限后,很可能造成程序無(wú)法處理后續(xù)請(qǐng)求。)

socketserver模塊:

from socketserver import BaseRequestHandler, TCPServer

class EchoHandler(BaseRequestHandler):
    def handle(self):
        print("Got Connection From: %s" % str(self.client_address))
        while True:
            msg = self.request.recv(8192)
            if not msg:
                break
            self.request.send(msg)

if __name__ == "__main__":
    server = TCPServer(("", 5000), EchoHandler)
    server.serve_forever()
from socketserver import StreamRequestHandler, TCPServer, ThreadingTCPServer
import time

class EchoHandler(StreamRequestHandler):
    def handle(self):
        print("Got Connection Address: %s" % str(self.client_address))
        for line in self.rfile:
            print(line)
            self.wfile.write(bytes("hello {}".format(line.decode('utf-8')).encode('utf-8')))

if __name__ == "__main__":
    serv = ThreadingTCPServer(("", 5000), EchoHandler)
    serv.serve_forever()

代碼詳解:

  • 處理多個(gè)客戶端,初始化一個(gè)ThreadingTCPServer實(shí)例;
  • 設(shè)置綁定的IP地址和端口,以及處理類(lèi);
  • 使用StreamRequestHandler(使用流的請(qǐng)求處理程序類(lèi),類(lèi)似file-like對(duì)象,提供標(biāo)準(zhǔn)文件接口簡(jiǎn)化通信過(guò)程),重寫(xiě)里面的handle方法,獲取請(qǐng)求數(shù)據(jù),返回?cái)?shù)據(jù)給客戶端;

TCP Socket客戶端

socket模塊:

# -*- coding: utf-8 -*-
from socket import socket, AF_INET, SOCK_STREAM
import time

def request_handler():
	start_time = time.time()
	sock_client = socket(AF_INET, SOCK_STREAM)
	sock_client.connect(('localhost', 5000))
	
	book_content = ""
	with open("send_books.txt", "r") as f:
		book_content = f.read()
	
	content_list = book_content.split("\n")
	for content in content_list:
		if content:
			sock_client.send((content).encode())
			time.sleep(2)
			response = sock_client.recv(8192)
			print(response)

	end_time = time.time()
	print("總共耗時(shí):", end_time-start_time)

		

if __name__ == "__main__":
	request_handler()

UDP Socket

Socket模塊:

from socket import socket, AF_INET, SOCK_DGRAM
import time

def time_server(address):
    sock = socket(AF_INET, SOCK_DGRAM)
    sock.bind(address)

    while True:
        msg, addr = sock.recvfrom(8192)
        print('Get message from', addr)
        resp = time.ctime()
        sock.sendto(resp.encode('ascii'), addr)

if __name__ == "__main__":
    time_server(('', 5000))

代碼不詳解,和之前的差不多,注意不同的協(xié)議就完事了

客戶端測(cè)試:

from socket import socket, AF_INET, SOCK_DGRAM

if __name__ == "__main__":
    s = socket(AF_INET, SOCK_DGRAM)
    s.sendto(b'hello', ('localhost', 5000))
    text = s.recvfrom(8192)
    print(text)

socketserver模塊:

from socketserver import BaseRequestHandler, UDPServer
import time


class TimeHandler(BaseRequestHandler):
    def handle(self):
        print("Got Connection %s".format(str(self.client_address)))
        data = self.request[0]
        print(data)
        msg, sock = self.request
        print(msg)
        data = time.ctime()
        sock.sendto(data.encode('ascii'), self.client_address)

if __name__ == "__main__":
    u = UDPServer(("localhost", 9999), TimeHandler)
    u.serve_forever()

代碼不在贅述,如果需要多線程處理并發(fā)操作可以使用ThreadingUDPServer

總結(jié)

關(guān)于本篇介紹Python Socket編程,大都是皮毛,只是談到了Python實(shí)際處理socket的幾個(gè)模塊,
關(guān)于socket底層方面的知識(shí)并未提及,先了解個(gè)大概,從實(shí)際使用方面出發(fā),在實(shí)際使用過(guò)程中結(jié)合
計(jì)算機(jī)網(wǎng)絡(luò)知識(shí),能夠?qū)ocket在整個(gè)TCP/IP協(xié)議棧中的作用。

socket和socketserver模塊都可以用來(lái)編寫(xiě)網(wǎng)絡(luò)程序,不同的是socketserver省事很多,你可以專(zhuān)注
業(yè)務(wù)邏輯,不用去理會(huì)socket的各種細(xì)節(jié),包括不限于多線程/多進(jìn)程,接收數(shù)據(jù),發(fā)送數(shù)據(jù),通信過(guò)程。

以上就是Python Socket編程詳解的詳細(xì)內(nèi)容,更多關(guān)于Python Socket編程的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

您可能感興趣的文章:
  • python SOCKET編程基礎(chǔ)入門(mén)
  • python Socket網(wǎng)絡(luò)編程實(shí)現(xiàn)C/S模式和P2P
  • python網(wǎng)絡(luò)編程:socketserver的基本使用方法實(shí)例分析
  • python網(wǎng)絡(luò)編程socket實(shí)現(xiàn)服務(wù)端、客戶端操作詳解
  • 基于python3的socket聊天編程
  • python socket通信編程實(shí)現(xiàn)文件上傳代碼實(shí)例
  • Python 網(wǎng)絡(luò)編程之TCP客戶端/服務(wù)端功能示例【基于socket套接字】
  • Python 網(wǎng)絡(luò)編程之UDP發(fā)送接收數(shù)據(jù)功能示例【基于socket套接字】
  • python粘包問(wèn)題及socket套接字編程詳解

標(biāo)簽:海南 安康 喀什 崇左 濟(jì)南 長(zhǎng)沙 山西 山西

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《Python Socket編程詳解》,本文關(guān)鍵詞  ;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。
  • 相關(guān)文章
  • 收縮
    • 微信客服
    • 微信二維碼
    • 電話咨詢

    • 400-1100-266
    长葛市| 云浮市| 北宁市| 新乡县| 沂水县| 商河县| 哈尔滨市| 囊谦县| 原阳县| 台东县| 江门市| 米林县| 秦安县| 嘉义县| 新乡县| 思茅市| 靖州| 台南县| 原平市| 大冶市| 民县| 东台市| 盱眙县| 云安县| 河池市| 南召县| 应城市| 镇雄县| 定安县| 乐清市| 镇原县| 柘城县| 察哈| 蚌埠市| 尼木县| 南京市| 泽普县| 无棣县| 花垣县| 三亚市| 绥德县|