如何在Python中重置TCP套接字? [英] How can I reset a TCP socket in Python?

查看:69
本文介绍了如何在Python中重置TCP套接字?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个用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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆