问题描述:什么是死锁?

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

    在MySQL应用时,经常要使用这两个函数TIMESTAMPDIFF和TIMESTAMPADD. 一,TIMESTAMPDIFF 语法: TIMESTAMPDIFF(interval,datetime_ ...

  2. Codeforces Round 251 (Div. 2)

    layout: post title: Codeforces Round 251 (Div. 2) author: "luowentaoaa" catalog: true tags ...

  3. 洛谷——P1495 曹冲养猪

    题目描述 自从曹冲搞定了大象以后,曹操就开始捉摸让儿子干些事业,于是派他到中原养猪场养猪,可是曹冲满不高兴,于是在工作中马马虎虎,有一次曹操想知道母猪的数量,于是曹冲想狠狠耍曹操一把.举个例子,假如有 ...

  4. 【推广】实用命令——tldr

    碎碎念 如题,通常遇到一个新的命令需要查询其帮助的时候,一般使用`command -h`或者`man command`来查询,但是,有时候仅仅想知道这个命令怎么用,并不想知道具体含义啊(这个命令可能不 ...

  5. [Atcoder Grand Contest 001] Tutorial

    Link: AGC001 传送门 A: …… #include <bits/stdc++.h> using namespace std; ; ]; int main() { scanf(& ...

  6. 【R笔记】给R加个编译器——notepad++

    R的日记-给R加个编译器 转载▼ R是一款强大免费且开源的统计分析软件,这是R的长处,可也是其“缺陷”的根源:不似商业软件那样user-friendly.记得初学R时,给我留下最深印象的不是其功能的强 ...

  7. Java堆内存不足

    1)使用IDEA开发程序时有时候会提示“Java Heap space error”,说明IDEA默认配置的Java堆内存不足,程序需要更多的堆内存. 2)堆(Heap)和非堆(Non-heap)内存 ...

  8. NHibernate官方文档中文版--只读实体类型(Read-only entities)

    重点 NHIbernate处理只读对象的方式可能和你在别处看到的不同.不正确的使用方式可能造成不可预料的结果. 当一个实体是只读的时候: NHIbernate不会对实体的简单属性和单向关联数据检查数据 ...

  9. PHP反射(ReflectionClass、ReflectionMethod)在ThinkPHP框架的控制器调度模块中的应用

    ThinkPHP框架的控制器模块是如何实现 前控制器.后控制器,及如何执行带参数的方法? PHP系统自带的 ReflectionClass.ReflectionMethod 类,可以反射用户自定义类的 ...

  10. CSS3:box-sizing 怪异盒模型

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...