如何在Python中重置TCP套接字? [英] How can I reset a TCP socket in Python?
问题描述
我有一个用Python编写的套接字代理,当它从一对通信对等体收到RST时,将通过垃圾回收套接字来关闭与两个对等体的连接.这导致另一个对等方看到FIN而不是RST.
I have a socket proxy written in Python which when it receives a RST from a pair of communicating peers will close the connection to both peers by letting the sockets be garbage collected. This results in the other peer seeing a FIN rather than a RST.
这意味着代理有效地将RST转换为FIN,我认为这不是理想的选择.
This means the proxy effectively translates RST into FIN, which I don't think is ideal.
我发现在Linux中,可以通过调用带有地址为的地址的connect 重置TCP连接AF_UNSPEC
.但是我还没有找到从Python程序执行此操作的方法.
I found that in Linux it possible to reset a TCP connnection by calling connect with an address of family AF_UNSPEC
. But I haven't found a way to do this from a Python program.
如何在Python中 connect
到 AF_UNSPEC
地址?
How do I connect
to an AF_UNSPEC
address in Python?
到目前为止我尝试过的事情
我尝试查看相关的 connect
方法的 help
输出,并发现了以下内容:
I tried looking at the help
output for the relevant connect
method and found this:
Help on built-in function connect:
connect(...)
connect(address)
Connect the socket to a remote address. For IP sockets, the address
is a pair (host, port).
不幸的是,这并不能告诉我要构造 AF_UNSPEC
地址的 address
参数必须是什么.
Unfortunately that doesn't tell me what the address
argument has to be in order to construct a AF_UNSPEC
address.
我试图将原始套接字 fd 包装在一个带有 AF_UNSPEC
族的新套接字对象中,如下所示:
I attempted to wrap the original socket fd in a new socket object with family AF_UNSPEC
like this:
socket.fromfd(s.fileno(), socket.AF_UNSPEC, 0)
生成的对象产生相同的帮助文本,并且在新建的套接字对象上尝试调用 connect
都会导致
The resulting object produce the same help text and any attempt to call connect
on the newly constructed socket object results in
socket.error: getsockaddrarg: bad family
所以看来使用 socket.fromfd
可能不是我的问题的答案.
So it looks like using socket.fromfd
is probably not the answer to my question.
推荐答案
查看当前 socket
包重置Linux上的连接).
Looking at the current socket
package implementation in CPython, there is really no pythonic way (to connect a socket to an AF_UNSPEC
address, as of 2019-01 (i.e. to reset the connection on Linux).
下一个最好的事情是在接受的套接字上设置 SO_LINGER
选项(直接或通过继承).启用延迟(并设置为零超时)后,关闭套接字将重置连接.
The next best thing is to set the SO_LINGER
option on the accepted socket (either directly or via inheritance). When lingering is enabled (and set to a zero timeout) closing the socket yields a reset of the connection.
您必须注意在正确的套接字API级别上设置 SO_LINGER
选项,并对选项值(它是结构)使用正确的编码.
You have to be careful to set the SO_LINGER
option on the right sockets API level and to use the right encoding for the option value (it's a struct).
示例:
import socket
import struct
import time
s = socket.socket(socket.AF_INET6)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
# if we want to inherit this option:
#s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0))
s.bind(('', 2323))
s.listen()
con, addr = s.accept()
con.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0))
time.sleep(1)
con.close()
time.sleep(3)
使用curl连接到该端口:
Connecting to this port with curl:
$ curl localhost:2323
curl: (56) Recv failure: Connection reset by peer
连接到该端口而不发送任何内容:
Connecting to this port without sending anything:
$ socat - tcp:localhost:2323
例如使用
$ tshark -i lo -f 'tcp port 2323'
在两种情况下,最后一个数据包都应该是RST(从服务器发送到客户端),例如:
the last packet should be a RST (sent from server to client), in both cases - for example:
39 9758.478140247 127.0.0.1 → 127.0.0.1 TCP 66 2323 → 34494 [RST, ACK]
Seq=1 Ack=1 Win=43776 Len=0 TSval=2787120418 TSecr=2787119417
这篇关于如何在Python中重置TCP套接字?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!