PythonSocket编程详解
⽬录
背景
TCP和UDP协议本质上的区别?
TCP/IP协议栈、HTTP协议、Socket之间的区别和联系?
TCPSocket服务器的通信过程?
socket和websocket之间的联系?
HTTP,WSGI协议的联系和区别?
主流Web框架,异步Web框架?
asyncio,aiohttp之间的联系?(异步编程)
代码设计
TCPSocket服务端
TCPSocket客户端
UDPSocket
总结
背景
关于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 = v(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 = v(8192)
if not msg:
break
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地址和端⼝,以及处理类;
websocket和socket使⽤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)
t(('localhost', 5000))
book_content = ""
with open("", "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 = v(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 = vfrom(8192)
print('Get message from', addr)
resp = ime()
sock.de('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 = quest[0]
print(data)
msg, sock = quest
print(msg)
data = ime()
sock.de('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编程的资料请关注其它相关⽂章!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论