Python Socket编程详解


Posted in Python onApril 25, 2021

背景

关于Python Socket编程,首先需要了解几个计算机网络的知识,通过以下的几个问题,有助于更好的理解Socket编程的意义,以及整个框架方面的知识:

TCP和UDP协议本质上的区别?

TCP协议,面向连接,可靠,基于字节流的传输层通信协议;UDP协议无连接,不可靠,基于数据包的传输层协议。

TCP协议在建立连接的过程需要经历三次握手,断开连接则需要经历四次挥手,而这建立连接的过程增加了传输过程中的安全性。
而建立连接的过程则会消耗系统的资源,消耗更多的时间,而相比较UDP协议传输过程则不会出现这种问题。

总结来讲,基于TCP协议传输,需要不断的确认对方是否收到信息,从而建立连接(确认过程次数有限制,即三次握手),UDP协议传输则
不需要确认接收端是否收到信息,只需要将信息发给对方。

TCP/IP协议栈、HTTP协议、Socket之间的区别和联系?

TCP/IP协议栈就是一系列网络协议,可以分为四层模型来分析:应用层、传输层、网络层、链路层;

HTTP协议(超文本传输协议)就是在这一协议栈中的应用层协议;HTTP协议简单来说,它的作用就是规范数据的格式,让程序能够方便的识别,并且收发双方都需要遵循同样的协议格式进行数据传输。(应用层的协议也和HTTP协议的作用类似,不一样的是定义不同的数据格式。)

Socket可以理解为TCP/IP协议栈提供的对外的操作接口,即应用层通过网络协议进行通信的接口。Socket可以使用不同的网络协议进行端对端的通信;

TCP Socket服务器的通信过程?

Server端:

建立连接(socket()函数创建socket描述符、bind()函数绑定特定的监听地址(ip+port)、listen()函数监听socket、accept()阻塞等待客户端连接)

数据交互(read()函数阻塞等待客户端发送数据、write()函数发送给客户端数据)

Client端:

建立连接(socket()函数创建socket描述符、connect()函数向指定的监听地址发送连接请求)

数据交互(wirte()函数发送服务端数据、read()函数足阻塞等待接受服务端发送的数据)

socket和websocket之间的联系?

webosocket是一种通信协议,不同于HTTP请求,客户端请求服务端资源,服务端响应的通信过程;websocket允许服务端主动
向客户端推送消息,同时做到客户端和服务端双向通讯的协议。(具体底层原理有待后面实践,暂时未接触)

HTTP,WSGI协议的联系和区别?

HTTP协议(超文本传输协议),属于TCP/IP协议栈中应用层的协议。用于规范传输数据的格式,是一种客户端和服务端传输的规则。

WSGI协议则是Python定义的Web服务器和框架程序通信的接口规则。两者联系不大,强行说的话,Python框架程序主要处理的是HTTP请求。

(后期可以实现一个WSGI协议的Python框架,用于处理HTTP请求的实验。)

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

主流Web框架:Django、Flask

异步Web框架:Tornado(内置异步模块)、Snaic(Python自带asyncio)、FastAPI(基于Starlette库) 、aiohttp(基于asyncio)

asyncio,aiohttp之间的联系?(异步编程)

asyncio是一个异步IO库,aiohttp就是基于asyncio的异步HTTP框架(支持客户端/服务端)

代码设计

Python提供了基本的socket模块:

  1. socket模块;提供了标准的BSD Sockets API;
  2. socketserver模块:提供了服务器中心类,简化服务器的开发;

TCP Socket服务端

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))

代码详解:

  • 创建一个基于IPV4和TCP协议的Socket,这里AF_INET指的是使用IPV4协议,SOCK_STREAM指定使用面向流的TCP协议,绑定监听端口,设置等待连接的最大数量
  • 创建一个永久循环,获取客户端请求的连接,accept()会等待并返回一个客户端的连接;
  • 连接建立后,等待客户端数据,接受完客户端数据,然后返回数据给客户端,最后关闭连接

存在的问题:当出现多个客户端请求时,由于是单个线程会发生阻塞的情况,所以如果需要多线程处理多个客户端请求,可以这样改;

from threading import Thread

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

这样的话,就会在每个客户端请求的时候,生成一个子线程然后处理请求;
(但是存在一个问题:当突然大量请求连接,消耗系统资源达到上限后,很可能造成程序无法处理后续请求。)

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()

代码详解:

  • 处理多个客户端,初始化一个ThreadingTCPServer实例;
  • 设置绑定的IP地址和端口,以及处理类;
  • 使用StreamRequestHandler(使用流的请求处理程序类,类似file-like对象,提供标准文件接口简化通信过程),重写里面的handle方法,获取请求数据,返回数据给客户端;

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("总共耗时:", 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))

代码不详解,和之前的差不多,注意不同的协议就完事了

客户端测试:

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()

代码不在赘述,如果需要多线程处理并发操作可以使用ThreadingUDPServer

总结

关于本篇介绍Python Socket编程,大都是皮毛,只是谈到了Python实际处理socket的几个模块,
关于socket底层方面的知识并未提及,先了解个大概,从实际使用方面出发,在实际使用过程中结合
计算机网络知识,能够对socket在整个TCP/IP协议栈中的作用。

socket和socketserver模块都可以用来编写网络程序,不同的是socketserver省事很多,你可以专注
业务逻辑,不用去理会socket的各种细节,包括不限于多线程/多进程,接收数据,发送数据,通信过程。

以上就是Python Socket编程详解的详细内容,更多关于Python Socket编程的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
python如何实现excel数据添加到mongodb
Jul 30 Python
Python通过RabbitMQ服务器实现交换机功能的实例教程
Jun 29 Python
详解Python中表达式i += x与i = i + x是否等价
Feb 08 Python
pycharm远程调试openstack的图文教程
Nov 21 Python
Python三种遍历文件目录的方法实例代码
Jan 19 Python
python如何在列表、字典中筛选数据
Mar 19 Python
python flask安装和命令详解
Apr 02 Python
Python3.5运算符操作实例详解
Apr 25 Python
python语言元素知识点详解
May 15 Python
Django ModelForm操作及验证方式
Mar 30 Python
python使用XPath解析数据爬取起点小说网数据
Apr 22 Python
Python数组变形的几种实现方法
May 30 Python
Python Django 后台管理之后台模型属性详解
如何用python反转图片,视频
python基于tkinter制作m3u8视频下载工具
用python自动生成日历
解决Django transaction进行事务管理踩过的坑
Apr 24 #Python
pdf论文中python画的图Type 3 fonts字体不兼容的解决方案
Apr 24 #Python
Python使用UDP实现720p视频传输的操作
You might like
利用 window_onload 实现select默认选择
2006/10/09 PHP
用php+javascript实现二级级联菜单的制作
2008/05/06 PHP
phpnow php探针环境检测代码
2014/11/04 PHP
PHP 中 var_export、print_r、var_dump 调试中的区别
2018/06/19 PHP
php封装的page分页类完整实例代码
2020/02/01 PHP
jquery select(列表)的操作(取值/赋值)
2009/08/06 Javascript
javascript 无提示关闭窗口脚本
2009/08/17 Javascript
jQuery中的bind绑定事件与文本框改变事件的临时解决方法
2010/08/13 Javascript
JavaScript访问样式表代码
2010/10/15 Javascript
解决css和js的{}与smarty定界符冲突问题的两种方法
2013/09/10 Javascript
类似php的js数组的in_array函数自定义方法
2013/12/27 Javascript
js二维数组排序的简单示例代码
2014/01/24 Javascript
JavaScript运动减速效果实例分析
2015/08/04 Javascript
BootStrap iCheck插件全选与获取value值的解决方法
2016/08/24 Javascript
微信小程序 实现列表项滑动显示删除按钮的功能
2017/04/13 Javascript
详解如何在 vue 项目里正确地引用 jquery 和 jquery-ui的插件
2017/06/01 jQuery
jQuery动画_动力节点节点Java学院整理
2017/07/04 jQuery
深入理解jquery的$.extend()、$.fn和$.fn.extend()
2017/07/08 jQuery
详解Angular5/Angular6项目如何添加热更新(HMR)功能
2018/10/10 Javascript
简述vue路由打开一个新的窗口的方法
2018/11/29 Javascript
node基于async/await对mysql进行封装
2019/06/20 Javascript
小程序实现按下录音松开识别语音
2019/11/22 Javascript
Python获取电脑硬件信息及状态的实现方法
2014/08/29 Python
详尽讲述用Python的Django框架测试驱动开发的教程
2015/04/22 Python
Python获取二维矩阵每列最大值的方法
2018/04/03 Python
Pandas中DataFrame的分组/分割/合并的实现
2019/07/16 Python
tensorflow 自定义损失函数示例代码
2020/02/05 Python
python根据用户需求输入想爬取的内容及页数爬取图片方法详解
2020/08/03 Python
大学毕业登记表自我鉴定
2013/10/09 职场文书
社区母亲节活动方案
2014/03/05 职场文书
学习决心书范文
2014/03/11 职场文书
班委竞选演讲稿
2014/04/28 职场文书
大明湖导游词
2015/02/03 职场文书
社团招新宣传语
2015/07/13 职场文书
SQL Server 数据库实验课第五周——常用查询条件
2021/04/05 SQL Server
win10如何快速切换窗口 win10切换窗口快捷键分享
2022/07/23 数码科技