Python 套接字挂在 connect/accept

Python socket hangs on connect/accept

我正在尝试使用 sockets 发送数据包,并且在今天早上之前都能正常发送。我不确定发生了什么。数据包显示在 tcpdump 中,但服务器和客户端无法相互连接。

netcat.py

import socket
import argparse
import sys
import os
import re
import threading


def convertContent(content: str = "") -> bytes:
    byteContent = []
    # grab the hex from the content
    for i in range(len(content)):
        if content[i] == "\" and content[i+1] == "x":
            byteContent.append(f"{content[i+2]}{content[i+3]}")

    # grab the non hex from the content, split it on the hex
    stringContent = re.split(r"\x.{2}", content)

    byteIndex = 0
    newContent = b""
    # Re add the non-hex content, and the hex content
    for word in stringContent:
        newContent += word.encode()
        if byteIndex < len(byteContent):
            newContent += bytes.fromhex(byteContent[byteIndex])
            byteIndex += 1
    newContent = newContent.replace(b"\n", b"\n").replace(b"\r", b"\r")
    return newContent


class Netcat():
    '''
    Netcat class that can be used to send/receive TCP packets
    '''
    BUFFER_SIZE = 1024

    def __init__(self):
        pass

    @classmethod
    def createSocket(cls):
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # Address might be in a TIME_WAIT status, ignore this
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        # Port might be in a TIME_WAIT status, ignore this
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
        return sock

    @classmethod
    def send(cls, hostname: str = "127.0.0.1", srcPort: int = 0, destPort: int = 9999, content: str = "", buffer_size: int = 1024):
        srcPort = int(srcPort)
        destPort = int(destPort)
        try:
            content = convertContent(content=content)
        except:
            pass
        sock = cls.createSocket()

        # Set the source port before sending
        sock.connect((hostname, destPort))
        sock.sendall(content)
        # shutdown might be redundant/unnecessary (tells connected host that we're done sending data)
        sock.shutdown(socket.SHUT_WR)
        while True:
            data = sock.recv(buffer_size)
            if len(data) == 0:
                break
        sock.close()

    @classmethod
    def receive(cls, port: int = 9999, buffer_size: int = 1024):
        if port <= 1024 and os.geteuid() != 0:
            print(f"Listening on port {port} requires superuser privileges!")
            return
        host = ""
        sock = cls.createSocket()
        sock.bind((host, port))
        sock.listen(10)
        conn, addr = sock.accept()
        while True:
            data = conn.recv(buffer_size)
            if not data:
                break
        conn.close()

threading.Thread(target=Netcat.receive,daemon=True).start()
Netcat.send(content="test")

注意:我正在将数据包从一个 VM 发送到另一个 VM,而不是发送给自己,但是要求人们启动一堆 VM 会很多重现这个。发送方法中的hostname参数应该是接收机器的实际IP

我抛出了一些打印语句,服务器在 sock.accept() 停止,而客户端在 sock.connect((hostname, destPort))

挂起

我检查了服务器的主机名,它正在侦听 (0.0.0.0, 8888)(假设 8888 是端口参数),这意味着它正在侦听该端口上的所有接口,所以我不知道为什么它拒绝连接

我在服务器上进行了 tcpdump,它得到了数据包,它得到了一个 SYN,然后发出了一个 SYN, ACK,但是其余的数据包被标记为重新传输。

我试过循环接受和连接线,认为可能发生了某种竞争条件,但无论我做什么,客户端都无法连接到服务器。

编辑:这适用于我的本地计算机,但当我尝试通过网络发送数据包时仍然中断。握手的前两步经过 SYN & SYN, ACK,但第三步 ACK

不要在客户端绑定。下面的工作示例,但进行了一些小改动以制作独立脚本:

import socket
import threading

def receive(port: int = 9999, buffer_size: int = 1024):
    host = ""
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # Address might be in a TIME_WAIT status, ignore this
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind((host, port))
    sock.listen()
    conn, addr = sock.accept()
    while True:
        data = conn.recv(buffer_size)
        if not data:
            break
        print(data)
    conn.close()

def send(hostname: str = "127.0.0.1", destPort: int = 9999, content: str = b"test", buffer_size: int = 1024):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # Address might be in a TIME_WAIT status, ignore this
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    # Removed bind
    sock.connect((hostname, destPort))
    sock.sendall(content)
    # shutdown might be redundant/unnecessary (tells connected host that we're done sending data)
    sock.shutdown(socket.SHUT_WR)
    while True:
        data = sock.recv(buffer_size)
        if len(data) == 0:
            break
    sock.close()
    
threading.Thread(target=receive,daemon=True).start()
send()

输出:

b'test'