问题描述:什么是死锁?

死锁发生在当一个服务器和客户端同时试图往一个连接上写东西或同时从一个连接上读的时候。在这种情况下,没有进程可以得到任何数据(如果它们都正在读),因此,如果它们正在写,向外的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——网络编程,如何避免死锁?的更多相关文章

  1. 8.Python网络编程_多线程死锁

    死锁:指两个或两个以上的线程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死 ...

  2. python网络编程应用(一)

     在之前的一篇博客<python网络编程基础>中介绍了socket.socket()函数及其应用,其实socket模块中还有很多属性可供网络应用程序使用.这里将详细讲解一下socket模块 ...

  3. Python 网络编程(二)

    Python 网络编程 上一篇博客介绍了socket的基本概念以及实现了简单的TCP和UDP的客户端.服务器程序,本篇博客主要对socket编程进行更深入的讲解 一.简化版ssh实现 这是一个极其简单 ...

  4. Python 网络编程(一)

    Python 网络编程 socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. ...

  5. Python学习(22)python网络编程

    Python 网络编程 Python 提供了两个级别访问的网络服务.: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口的 ...

  6. Day07 - Python 网络编程 Socket

    1. Python 网络编程 Python 提供了两个级别访问网络服务: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口 ...

  7. python网络编程-01

    python网络编程 1.socket模块介绍 ①在网络编程中的一个基本组件就是套接字(socket),socket是两个程序之间的“信息通道”. ②套接字包括两个部分:服务器套接字.客户机套接字 ③ ...

  8. 《Python网络编程》学习笔记--使用谷歌地理编码API获取一个JSON文档

    Foundations of Python Network Programing,Third Edition <python网络编程>,本书中的代码可在Github上搜索fopnp下载 本 ...

  9. Python网络编程基础pdf

    Python网络编程基础(高清版)PDF 百度网盘 链接:https://pan.baidu.com/s/1VGwGtMSZbE0bSZe-MBl6qA 提取码:mert 复制这段内容后打开百度网盘手 ...

  10. python 网络编程(Socket)

    # from wsgiref.simple_server import make_server## def RunServer(environ,start_response):# start_resp ...

随机推荐

  1. [译]Java8:循环与函数式编程

    Java8函数式编程的加入彻底改变了游戏规则.对Java开发者来说这是一个全新的世界,我们也需要做出相应的改变. 在这篇文章中我们将找寻传统循环代码的可替代方案.Java8的函数式编程特性改变了编程思 ...

  2. NAT+穿洞基础知识梳理

    参考:https://www.cnblogs.com/shilxfly/p/6589255.html https://blog.csdn.net/phoenix06/article/details/7 ...

  3. linux查看cpu内存信息

    # 总核数 = 物理CPU个数 X 每颗物理CPU的核数 # 总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数 # 查看物理CPU个数 cat /proc/cpuinfo| ...

  4. HDU 2045 LELE的RPG难题(递推)

    不容易系列之(3)—— LELE的RPG难题 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/O ...

  5. requests库使用socks5代理

    备查: #!usr/bin/env python # coding=utf-8 import requests proxies = {'https': 'https://127.0.0.1:1080' ...

  6. 洛谷—— P1775 古代人的难题_NOI导刊2010提高(02)

    P1775 古代人的难题_NOI导刊2010提高(02) 题目描述 门打开了,里面果然是个很大的厅堂.但可惜厅堂内除了中央的一张羊皮纸和一支精致的石笔,周围几具骷髅外什么也没有.难道这就是王室的遗产? ...

  7. noi 题库1.7字符串 第16至20题

    16:忽略大小写的字符串比较 一般我们用strcmp可比较两个字符串的大小,比较方法为对两个字符串从前往后逐个字符相比较(按ASCII码值大小比较),直到出现不同的字符或遇到'\0'为止.如果全部字符 ...

  8. Linux命令之dd

    dd [OPERAND] dd 选项 复制一个文件,根据[OPERAND]进行转换和格式化 (1). OPERAND参数 说明1:dd的选项只有’--help’和’--version’,也就是帮助与版 ...

  9. CentOS7部署l2tp/IPsec服务

    1.安装必要的工具 yum install vim net-tools wget unzip -y 2. 下载安装脚本 wget -O StackScript.zip http://files.cnb ...

  10. [BZOJ 4034] 树上操作

    Link: BZOJ 4034 传送门 Solution: 树剖模板题…… Code: #include <bits/stdc++.h> using namespace std; type ...