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

2020-06-12 16:38:47 +08:00
 18870715400

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] 在一个非套接字上尝试了一个操作, 我一直不懂为什么会报这个错, 有朋友帮我解释一下么

2913 次点击
所在节点    Python
13 条回复
opengps
2020-06-12 16:42:35 +08:00
我不懂 py,但我理解 socket 连接不能这么复用(直接断直接重开)。
在 c#下得先=null 然后重新 new 才能使用新的对象建立连接
limboMu
2020-06-12 16:55:59 +08:00
TCP 主动关闭一方,是要等待 2msl 才能复用端口的,重新连接多半是要换一个端口,so 原来的 socket 实例是不能使用的
ysc3839
2020-06-12 16:58:49 +08:00
要重新调用 socket.socket 创建个新的吧?
18870715400
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
2020-06-12 17:01:52 +08:00
@ysc3839 的确是需要建立一个新的
est
2020-06-12 17:08:04 +08:00
client.connect(addr)

这个不能重复写。得再弄一个 client2
limboMu
2020-06-12 17:11:38 +08:00
@18870715400 2msl 是个虚数,很长可能半分钟也可能一分钟,这个取决于操作系统的网络协议栈的实现,建议了解一下 TCP 的状态机
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
2020-06-12 18:22:33 +08:00
socket 创建的也是文件句柄,你都关闭了,那么这个文件句柄在内核里就直接被释放了啊,你在操作他当然不行了,就好比你一个文件打开然后关闭再读写当然不行了

第二个也是上面说的,tcp 为了过滤异常包所以关闭后会继续保持占用一段时间端口,立刻重用这个端口也是不行的
HanMeiM
2020-06-12 19:57:12 +08:00
2msl 是指两倍的报文最长生存时间,保证被关闭的一方确定收到 ack 和旧数据的清除
youngce
2020-06-12 20:51:13 +08:00
刚好之前做过类似 tcp 断线(实际上可能是服务端暂时不可用)重连的机制,一般是 client.close()主动 sleep 一段时间,然后再重新发起 client.connect(addr),这样就避免了你这里的报错
yannxia
2020-06-12 21:16:16 +08:00
Socket 被 close 就约等于 FD 被 lose 约等于 此次的 TCP 链路结束了,再 Connect 需要一个 新的 FD,也就是创建一个新的 Socket
18870715400
2020-06-13 13:25:51 +08:00
@sujin190 看到你的例子突然懂了, 谢谢

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/681025

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX