V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
18870715400
V2EX  ›  Python

刚好工作中遇到的 socket 问题想问一下大家

  •  
  •   18870715400 · 2020-06-12 16:38:47 +08:00 · 2712 次点击
    这是一个创建于 1414 天前的主题,其中的信息可能已经有所发展或是发生改变。

    server 端的代码

    import socket
    
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    addr = ("0.0.0.0", 9000)
    server.bind(addr)
    server.listen(5)
    
    
    while 1:
        print("waiting for connection")
        client, address = server.accept()
        print("connection from {}:{}".format(address[0], address[1]))
    
        while 1:
            data = client.recv(1024)
            if data == b"":
                break
            print(data)
        client.close()
        print("close connection from {}:{}".format(address[0], address[1]))
    

    client 的代码

    import socket
    
    addr = ("localhost", 9000)
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client.connect(addr)
    client.close()
    client.connect(addr)
    
    

    运行的时候服务端没有啥问题, 但是在客户端的时候, 我先关闭再连接也就是 client 中的最后一行会报一个错:OSError: [WinError 10038] 在一个非套接字上尝试了一个操作, 我一直不懂为什么会报这个错, 有朋友帮我解释一下么

    13 条回复    2020-06-13 13:25:51 +08:00
    opengps
        1
    opengps  
       2020-06-12 16:42:35 +08:00
    我不懂 py,但我理解 socket 连接不能这么复用(直接断直接重开)。
    在 c#下得先=null 然后重新 new 才能使用新的对象建立连接
    limboMu
        2
    limboMu  
       2020-06-12 16:55:59 +08:00
    TCP 主动关闭一方,是要等待 2msl 才能复用端口的,重新连接多半是要换一个端口,so 原来的 socket 实例是不能使用的
    ysc3839
        3
    ysc3839  
       2020-06-12 16:58:49 +08:00 via Android
    要重新调用 socket.socket 创建个新的吧?
    18870715400
        4
    18870715400  
    OP
       2020-06-12 17:01:30 +08:00
    @limboMu
    等 2msl 是什么意思, 等 2 毫秒么
    client.connect(addr)之前再重新赋值下 client
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    这样就不会报错
    18870715400
        5
    18870715400  
    OP
       2020-06-12 17:01:52 +08:00
    @ysc3839 的确是需要建立一个新的
    est
        6
    est  
       2020-06-12 17:08:04 +08:00
    client.connect(addr)

    这个不能重复写。得再弄一个 client2
    limboMu
        7
    limboMu  
       2020-06-12 17:11:38 +08:00
    @18870715400 2msl 是个虚数,很长可能半分钟也可能一分钟,这个取决于操作系统的网络协议栈的实现,建议了解一下 TCP 的状态机
    lackywind
        8
    lackywind  
       2020-06-12 18:07:23 +08:00
    最后一个 client.connect(addr) 应该是把套接字的句柄给关闭了,需要再重新创建下

    import socket

    addr = ("localhost", 9000)
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client.connect(addr)
    client.close()
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client.connect(addr)
    sujin190
        9
    sujin190  
       2020-06-12 18:22:33 +08:00
    socket 创建的也是文件句柄,你都关闭了,那么这个文件句柄在内核里就直接被释放了啊,你在操作他当然不行了,就好比你一个文件打开然后关闭再读写当然不行了

    第二个也是上面说的,tcp 为了过滤异常包所以关闭后会继续保持占用一段时间端口,立刻重用这个端口也是不行的
    HanMeiM
        10
    HanMeiM  
       2020-06-12 19:57:12 +08:00
    2msl 是指两倍的报文最长生存时间,保证被关闭的一方确定收到 ack 和旧数据的清除
    youngce
        11
    youngce  
       2020-06-12 20:51:13 +08:00
    刚好之前做过类似 tcp 断线(实际上可能是服务端暂时不可用)重连的机制,一般是 client.close()主动 sleep 一段时间,然后再重新发起 client.connect(addr),这样就避免了你这里的报错
    yannxia
        12
    yannxia  
       2020-06-12 21:16:16 +08:00
    Socket 被 close 就约等于 FD 被 lose 约等于 此次的 TCP 链路结束了,再 Connect 需要一个 新的 FD,也就是创建一个新的 Socket
    18870715400
        13
    18870715400  
    OP
       2020-06-13 13:25:51 +08:00
    @sujin190 看到你的例子突然懂了, 谢谢
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3106 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 11:01 · PVG 19:01 · LAX 04:01 · JFK 07:01
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.