zoukankan      html  css  js  c++  java
  • 02_tcp_deadlock

    # 这个程序我们是测试客户端和服务端在进行通信的过程中,可能会产生死锁的情况。

    # 这是因为缓冲区,和TCP协议的可靠性连接导致的。

    # 在程序中我们可以看到,客户端先向服务端发送数据,然后服务端就收之后再发送给客户端。

    # 注意这里我们可以看到,程序设置的是不能缓冲区满就立即发送出去。

    # 那么我们可以考虑一下,如果客户端需要发送的字节数比较小,那么是能够正常的通信的,

    # 因为小于缓冲区的大小,不会把缓冲区填满。

    # 再来考虑客户端发送数据很大的情况比如说1个G。

    # 从流程上边来看,客户端的一条信息就会发送出去,而不是等着缓冲区满。

    # 服务端那边也是这样的,接收到数据之后直接就发送,此时就产生问题了,因为要发送的数据是很大的,

    # 客户端的数据没有发送完成,就无法调用recv接收服务端穿过来的数据,那从服务端看,服务端发送的数据

    # 客户端没有接收,TCP 就判断网络不好了,就会不让服务端发送字节。同时服务端也不接受字节,就会导致

    # 客户端也发送不出去。这样就导致死锁了。

    # 导入模块
    import argparse,socket,sys
    def server(host,port,bytecount):
    # 创建一个服务端的套接字。
    sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    # 设置套接字
    sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    # 套接字绑定IP,端口
    sock.bind((host,port))
    # 设置监听的数量为1
    sock.listen(1)
    # 打印出服务端的IP,端口
    print("Listening at ",sock.getsockname())
    while True:
    # 服务端的套接字连接上客户端的套接字
    sc,sockname = sock.accept()
    print("Processing up to 1024 bytes at a time from",sockname)
    # 定义一个变量,用来计算一共接收了多少字节。
    n = 0
    # 死循环,一直接收客户端发过来的字母
    while True:
    # 每次接收从最大客户端传过来的1024个字节,然后赋给data变量
    data = sc.recv(1024)
    # 约定一个结束符
    if data == b'efo' or data == b'':break
    # 将接收的二进制字节进行解码,然后转换成大写字母,在进行编码。
    output = data.decode('ascii').upper().encode('ascii')
    # 服务端发送消息给客户端。
    sc.sendall(output)
    # 计算接收到的字节长度
    n += len(data)
    print("接收的数据量为:",n)
    # 强行刷新缓冲区。
    sys.stdout.flush()
    print('结束了')
    # 回收套接字。
    sc.close()
    print(' Socket closed')
    def client(host,port,bytecount):
    # 定义一个套接字,同上边服务端。
    sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    bytecount = (bytecount + 15) // 16 * 16
    print("bytecount",bytecount)
    # 定义一个十六个字节的字符串
    message = b'capitalize this'
    print('Sending ',bytecount,'bytes of data,in chunks of 16 bytes')
    # 连接服务端。
    sock.connect((host,port))
    # 定义发送数量
    sent = 0
    while sent <= bytecount :
    # 客户端发送消息
    sock.sendall(message)
    sent += len(message)
    print("发送了多少数据:",sent)
    # 强行刷新缓冲区
    sys.stdout.flush()
    # 最后发送一个结束符,告诉服务端发送结束了。
    sock.sendall(b'efo')

    print("结束了")
    # 单向的socket便称为半开放Socket。要实现半开放式,需要用到shutdown()函数。
    sock.shutdown(socket.SHUT_WR)
    print('Receving all the data the server sends back')
    # 定义接收到的字节变量
    received = 0
    while True:
    # 用来接收服务端传回来的消息
    data = sock.recv(42)
    if not received :
    # 打印第一次进来,接收到的数据
    print(" The firse data received says",repr(data))
    if not data:
    break
    # 计算接收到字节数的总和。
    received += len(data)
    print("接收的数据量为:",received)
    print('结束了')
    sock.close()


    if __name__ == "__main__":
    # 定义一个字典
    choices = {'client':client,'server':server}
    parser = argparse.ArgumentParser(description = 'Get deadlocked over TCP')
    parser.add_argument('role',choices = choices,help = 'which role to play')
    parser.add_argument('host',help = 'interface the server listens at;'
    ' host the client sends to')
    parser.add_argument("bytecount",type = int,nargs ='?',default = 16,
    help = 'number of bytes for client to send (default 16)')
    parser.add_argument('-p',metavar = "PORT",type = int,default = 1060,help = "TCP port (default 1060")

    args = parser.parse_args()
    function = choices[args.role]
    function(args.host,args.p,args.bytecount)




  • 相关阅读:
    一道有意思的面试算法题
    你真的了解回流和重绘吗
    一道面试题引起的思考
    手把手教你实现一个引导动画
    你可能不知道的setInterval的坑
    不到50行代码实现一个能对请求并发数做限制的通用RequestDecorator
    使用装饰者模式做有趣的事情
    广告
    vue运行svg文件
    el-table表格样式设置方法 :cell-class-name
  • 原文地址:https://www.cnblogs.com/cong12586/p/13944098.html
Copyright © 2011-2022 走看看