zoukankan      html  css  js  c++  java
  • 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()
    View Code

    示例客户端代码:

    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
    "% 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)
    View Code

    在运行上述服务器代码的情况下运行客户端代码,得到如下结果:

    服务器:
    (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 164864 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,由内核的宏决定

  • 相关阅读:
    WCF 第十三章 可编程站点 为站点创建操作
    WCF 第十三章 可编程站点 所有都与URI相关
    WCF 第十二章 对等网 使用自定义绑定实现消息定向
    WCF 第十三章 可编程站点 使用WebOperationContext
    Using App.Config for user defined runtime parameters
    WCF 第十三章 可编程站点
    WCF 第十三章 可编程站点 使用AJAX和JSON进行网页编程
    WCF 第十二章 总结
    WCF 第十三章 可编程站点 使用WebGet和WebInvoke
    WCF 第十三章 可编程站点 URI和UriTemplates
  • 原文地址:https://www.cnblogs.com/Simon-xm/p/4072986.html
Copyright © 2011-2022 走看看