博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python--socket/Socketerver并发/udp
阅读量:5261 次
发布时间:2019-06-14

本文共 4117 字,大约阅读时间需要 13 分钟。

Socketerve并发

基于tcp套接字,关键就是两个循环,一个链接循环,一个通讯循环

Socketserver模块中分两个大类:server类(解决链接问题)和request类(解决通信问题)

server类:

 

request类:

 

继承关系:

 

 

以下述代码为例,分析socketserver源码:

ftpserver=socketserver.ThreadingTCPServer(('127.0.0.1',8080),FtpServer)

ftpserver.serve_forever()

查找属性的顺序:

ThreadingTCPServer-->ThreadingMixIn-->TCPServer-->BaseServer

1.实例化得到tfpserver,先找类ThreadingTCPServer的_init_,在TCPServer中找到,进而执行Server_bind,server_active

2.找ftpsever下的server_forever,在BaseServer中找到,进而执行self._handle_request_noblock(),该方法同样是在BaseServer中

3.执行self._handle_request_noblcok()进而执行request,client_address=self.get_request()(就是TCPServer中的self.socket.accept()),然后执行self.process_request(request,client_address)

4.在ThreadingMiIn中找到process_request,开启多线程应对并发,进而执行process_request_thread,self.finish_request(request,client_address)

5.上述四部分完成了链接循环,本部分开始进入处理通讯部分,在BaseServer中找到finish_request,触发我们自己定义的类的实例化,去找_init_方法,而我们自己定义的类没有该方法,则去它的父类也就是BaseRequestHandler中找 

源代码分析总结:

基于tcp的socketserver我们自己定义的类中的

1.self.server即套接字对象

2.self.request即一个链接

3.self.client_adderss即客户端地址

#服务端:import  socketserverclass FTPserver(socketserver.BaseRequestHandler):#定义一个类 继承BaseRequestHandler #进行通讯    def handle(self):         # print(self)        # print(self.request) #拿到一个conn链接循环        while True: #通信循环            data=self.request.recv(1024)            print(data.decode("utf-8"))            self.request.send(data.upper())if __name__ == '__main__':    obj=socketserver.ThreadingTCPServer(("127.0.0.1",8000),FTPserver) #自己的类名    obj.serve_forever()#链接循环#客户端1import sockets=socket.socket(socket.AF_INET,socket.SOCK_STREAM)s.connect(("127.0.0.1",8000))while True:    msg=input(">>").strip()    if not msg:continue    s.send(msg.encode("utf-8"))    data=s.recv(1024)s.close()#客户端2import sockets=socket.socket(socket.AF_INET,socket.SOCK_STREAM)s.connect(("127.0.0.1",8000))while True:    msg=input(">>").strip()    if not msg:continue    s.send(msg.encode("utf-8"))    data=s.recv(1024)s.close()#客户端3import sockets=socket.socket(socket.AF_INET,socket.SOCK_STREAM)s.connect(("127.0.0.1",8000))while True:    msg=input(">>").strip()    if not msg:continue    s.send(msg.encode("utf-8"))    data=s.recv(1024)s.close()

 

基于UDP的套接字

udp:sendto发消息,recvfrom收消息

udp是基于数据报

sendinto

sendinto(bytes_data,ip_port):发送数据报,bytes_data为空,还有ip_port,所有即便是发送空的bytes_data,数据报其实也不是空的,自己这端的缓冲区收到内容,操作系统就会控制udp协议发包

recvfrom

udp协议

(1)如果如果收消息缓冲区里的数据为“空”,recvfrom也会阻塞

(2)只不过udp协议的客户端sendinto一个空数据并不是真的空数据(包含:空数据+地址信息,得到的报仍然不会为空),所以客户端只要有一个sendinto(不管是否发送空数据,都不是真的空数据),服务端就可以recvfrom到数据。

(3)udp无链接

无链接,因而无需listen(backlog),更加没有什么连接池之说了

无链接,udp的sendinto不用管是否有一个正在运行的服务端,可以己端一个劲的发消息,只不过数据丢失

recvfrom收的数据小于sendinto发送的数据时,在mac和linux系统上数据直接丢失,在windows系统上发送的比接收的大直接报错

只有sendinto发送数据没有recvfrom收数据,数据丢失

udp套接字简单示例:

#udp服务端import socketip_port=("127.0.0.1",8000)buffer_size=1024udp_server=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #数据报udp_server.bind(ip_port)while True: #通信循环    data,addr=udp_server.recvfrom(buffer_size)    print(data.decode("utf-8"),addr)    msg=input(">>:")udp_server.sendto(msg.encode("utf-8"),addr)    udp_server.sendto(data.upper(),addr)udp_serve.close()#udp客户端import socketip_port=("127.0.0.1",8000)buffer_size=1024udp_client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #数据报while True: #通信循环    msg=input(">>:").strip()    udp_client.sendto(msg.encode("utf-8"),ip_port) #每次发包都要指定端口    data,addr= udp_client.recvfrom(buffer_size)    print(data.decode("utf-8"))udp_client.close()#udp客户端1import socketip_port=("127.0.0.1",8000)buffer_size=1024udp_client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #数据报while True: #通信循环    msg=input(">>:").strip()    udp_client.sendto(msg.encode("utf-8"),ip_port) #每次发包都要指定端口    data,addr= udp_client.recvfrom(buffer_size)    print(data.decode("utf-8"))udp_client.close()#udp客户端2import socketip_port=("127.0.0.1",8000)buffer_size=1024udp_client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #数据报while True: #通信循环    msg=input(">>:").strip()    udp_client.sendto(msg.encode("utf-8"),ip_port) #每次发包都要指定端口    data,addr= udp_client.recvfrom(buffer_size)    print(data.decode("utf-8"))udp_client.close()

 

转载于:https://www.cnblogs.com/niejinmei/p/6814417.html

你可能感兴趣的文章
多线程《三》进程与线程的区别
查看>>
linux sed命令
查看>>
html标签的嵌套规则
查看>>
[Source] Machine Learning Gathering/Surveys
查看>>
HTML <select> 标签
查看>>
类加载机制
查看>>
tju 1782. The jackpot
查看>>
湖南多校对抗赛(2015.03.28) H SG Value
查看>>
hdu1255扫描线计算覆盖两次面积
查看>>
hdu1565 用搜索代替枚举找可能状态或者轮廓线解(较优),参考poj2411
查看>>
bzoj3224 splay板子
查看>>
程序存储问题
查看>>
Mac版OBS设置详解
查看>>
优雅地书写回调——Promise
查看>>
android主流开源库
查看>>
AX 2009 Grid控件下多选行
查看>>
PHP的配置
查看>>
Struts框架----进度1
查看>>
Round B APAC Test 2017
查看>>
MySQL 字符编码问题详细解释
查看>>