Python——网络编程,如何避免死锁?
问题描述:什么是死锁?
死锁发生在当一个服务器和客户端同时试图往一个连接上写东西或同时从一个连接上读的时候。在这种情况下,没有进程可以得到任何数据(如果它们都正在读),因此,如果它们正在写,向外的buffer会被充满,结果他们就好象被骗了,什么都做不了。
示例服务器代码:
import socket,traceback host=""
port=51423 sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
sock.bind((host,port))
sock.listen(1) while True:
try:
clientsock,clientaddr= sock.accept()
except KeyboardInterrupt:
raise
except:
traceback.print_exc()
continue try:
print("Got connection from ",clientsock.getpeername)
while True:
data = clientsock.recv(4096)
if not len(data):
break
clientsock.sendall(data)
except (KeyboardInterrupt,SystemExit):
raise
except:
traceback.print_exc() try:
clientsock.close()
except KeyboardInterrupt:
raise
except:
traceback.print_exc()
示例客户端代码:
import socket
import sys port=51423
host="localhost" data=b"x"*10485760
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect((host,port)) byteswritten=0
while byteswritten<len(data):
startpos = byteswritten
endpos = min(byteswritten+1024,len(data))
byteswritten+=sock.send(data[startpos:endpos])
sys.stdout.write("wrote %d bytes\r"% byteswritten)
sys.stdout.flush() sock.shutdown(1) print("All data sent.")
while True:
buf = sock.recv(1024).decode()
if not len(buf):
break
sys.stdout.write(buf)
在运行上述服务器代码的情况下运行客户端代码,得到如下结果:
服务器:
(ev1)[root@Simonxu bin]# python testserver.py
Got connection from <built-in method getpeername of socket object at 0x7f5e18d2b460>
客户端:
(ev1)[root@Simonxu bin]# python test.py
wrote bytes
可以看出,上述服务器和客户端卡在的wrote 164864 bytes。
-------------------------------------------------------------------分析--------------------------------------------------------------------------------------------
已知客户端程序试图发送一个10MB的数据,每次传输1KB,同时显示发送数据动态,并在所有数据发送完成后,从服务器每次1KB读取并写数据。
而服务器在建立套接口连接后,从客户端每次读取4KB数据,在接收到数据后,直接把数据发回客户端。
而矛盾的是,由于客户端在发送一个10MB大小的数据,这要发送较长时间,在发送的过程中没有办法读取数据,因此服务器返回的数据就堆积在客户端的接收缓冲区。
当接收缓冲区满了之后,服务器的sendall()函数发生错误,循环死锁,服务器不再接收客户端发来的数据。客户端也无法继续发送数据。就形成了上面的情况。
------------------------------------------------------------------如何避免死锁?----------------------------------------------------------------------------------
1、可以在客户端每次执行完send()后,进行一次recv()以接收服务器发来的数据,避免buffer充满。
2、可以让客户端发送的数据较少,这样在buffer充满之前就可以从缓冲区读取服务器发回的数据。
3、采用多线程或其他一些方法,使客户端可以同时发送和接收。
-----------------------------------------------------------------知识补充------------------------------------------------------------------------------------------
缓冲区:
1. tcp 收发缓冲区默认值
[root@ www.linuxidc.com]# cat /proc/sys/net/ipv4/tcp_rmem
4096 87380 4161536
87380 :tcp接收缓冲区的默认值
[root@ www.linuxidc.com]# cat /proc/sys/net/ipv4/tcp_wmem
4096 16384 4161536
16384 : tcp 发送缓冲区的默认值
2. tcp 或udp收发缓冲区最大值
[root@ www.linuxidc.com]# cat /proc/sys/net/core/rmem_max
131071
131071:tcp 或 udp 接收缓冲区最大可设置值的一半。
也就是说调用 setsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcv_size, &optlen); 时rcv_size 如果超过 131071,那么
getsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcv_size, &optlen); 去到的值就等于 131071 * 2 = 262142
[root@ www.linuxidc.com]# cat /proc/sys/net/core/wmem_max
131071
131071:tcp 或 udp 发送缓冲区最大可设置值得一半。
跟上面同一个道理
3. udp收发缓冲区默认值
[root@ www.linuxidc.com]# cat /proc/sys/net/core/rmem_default
111616:udp接收缓冲区的默认值
[root@ www.linuxidc.com]# cat /proc/sys/net/core/wmem_default
111616
111616:udp发送缓冲区的默认值
4. tcp 或udp收发缓冲区最小值
tcp 或udp接收缓冲区的最小值为 256 bytes,由内核的宏决定;
tcp 或udp发送缓冲区的最小值为 2048 bytes,由内核的宏决定
Python——网络编程,如何避免死锁?的更多相关文章
- 8.Python网络编程_多线程死锁
死锁:指两个或两个以上的线程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死 ...
- python网络编程应用(一)
在之前的一篇博客<python网络编程基础>中介绍了socket.socket()函数及其应用,其实socket模块中还有很多属性可供网络应用程序使用.这里将详细讲解一下socket模块 ...
- Python 网络编程(二)
Python 网络编程 上一篇博客介绍了socket的基本概念以及实现了简单的TCP和UDP的客户端.服务器程序,本篇博客主要对socket编程进行更深入的讲解 一.简化版ssh实现 这是一个极其简单 ...
- Python 网络编程(一)
Python 网络编程 socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. ...
- Python学习(22)python网络编程
Python 网络编程 Python 提供了两个级别访问的网络服务.: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口的 ...
- Day07 - Python 网络编程 Socket
1. Python 网络编程 Python 提供了两个级别访问网络服务: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口 ...
- python网络编程-01
python网络编程 1.socket模块介绍 ①在网络编程中的一个基本组件就是套接字(socket),socket是两个程序之间的“信息通道”. ②套接字包括两个部分:服务器套接字.客户机套接字 ③ ...
- 《Python网络编程》学习笔记--使用谷歌地理编码API获取一个JSON文档
Foundations of Python Network Programing,Third Edition <python网络编程>,本书中的代码可在Github上搜索fopnp下载 本 ...
- Python网络编程基础pdf
Python网络编程基础(高清版)PDF 百度网盘 链接:https://pan.baidu.com/s/1VGwGtMSZbE0bSZe-MBl6qA 提取码:mert 复制这段内容后打开百度网盘手 ...
- python 网络编程(Socket)
# from wsgiref.simple_server import make_server## def RunServer(environ,start_response):# start_resp ...
随机推荐
- docker官方文档中的dns,link,expose,publish
link是过时的了,尽量不要用. dns内部集成,也可以用外部. expose只是用于记录,并不真的. publish是否起作用,也要看情况,是否被占用端口. -------------------- ...
- centos系统设置局域网静态IP
---恢复内容开始--- centos系统设置局域网静态IP 很多时候,我们并不希望漏油器重启之后,自己的服务器动态的获取IP,这样很不利,因为你可能装了mysql,redis,等软件,然后需要远程去 ...
- vs2008下Error LINK2005: already defined in ...的一种解决方式
原因:不同的库之间都定义了相同的名称. 方法:右键工程->Properties->Configuration->Linker->Input 在右侧的Additional Dep ...
- Node 入门<1>
1. Node JavaScript web服务器框架,主要特点:事件驱动,异步 I/O,强制不共享任何资源的单线程,单进程系统. 每一个node进程都构成网络应用中的一个节点. ...
- inline select
- MySQL笔记之视图的使用详解
原文:http://www.jb51.net/article/36363.htm 1.什么是视图 视图是从一个或多个表中导出来的表,是一种虚拟存在的表. 视图就像一个窗口,通过这个窗口可以看到系统专门 ...
- JavaScript中的map方法
假设有一个函数f(x)=x²;作用在一个数组[1,2,3,4,5,6,7,8,9],通常我们会用遍历的方法来实现. function f(x){ return x * x; } var arr = [ ...
- 【指数型母函数】hdu1521 排列组合
#include<cstdio> #include<cstring> using namespace std; int n,m,jiecheng[11]; double a[1 ...
- 【主席树】bzoj2588 Spoj 10628. Count on a tree
每个点的主席树的root是从其父转移来的.询问的时候用U+V-LCA-FA(LCA)即可. #include<cstdio> #include<algorithm> using ...
- [CF911G]Mass Change Queries
题目大意: 给你一个长度为n的数列a,按顺序进行以下m次操作,每次将区间[l,r]中的所有x变成y,问最后数列是怎样的. 思路: 线段树. 每个线段树结点上维护当前区间每个数分别会变成多少.时间复杂度 ...