Python套接字在远程服务器使用所有数据之前关闭

Python套接字在远程服务器使用所有数据之前关闭,python,sockets,Python,Sockets,我正在编写一个Python模块,它通过unix套接字与go程序通信。客户端(python模块)将数据写入套接字,服务器使用这些数据 # Simplified version of the code used outputStream = socket.socket(socketfamily, sockettype, protocol) outputStream.connect(socketaddress) outputStream.setblocking(True) outputStream.s

我正在编写一个Python模块,它通过unix套接字与go程序通信。客户端(python模块)将数据写入套接字,服务器使用这些数据

# Simplified version of the code used
outputStream = socket.socket(socketfamily, sockettype, protocol)
outputStream.connect(socketaddress)
outputStream.setblocking(True)
outputStream.sendall(message)
....
outputStream.close()
我的问题是,Python客户端往往在服务器有效读取数据之前完成并关闭套接字,这会导致服务器端出现“管道断开,对等端重置连接”。无论我做什么,对于Python代码,所有内容都已发送,因此对send()sendall()select()的调用都是成功的

提前谢谢

编辑:由于mac OS,我无法使用关机

EDIT2:我还尝试删除超时并调用setblocking(True),但它没有改变任何事情

EDIT3:准备好这个问题后,文档似乎是不必要的,所以我恢复了关机,但我仍然有相同的问题:

# Simplified version of the code used
outputStream = socket.socket(socketfamily, sockettype, protocol)
outputStream.connect(socketaddress)
outputStream.settimeout(5)
outputStream.sendall(message)
....
outputStream.shutdown(socket.SHUT_WR)
outputStream.close()

IHMO最好使用异步I/O库/框架来实现这一点。下面是这样一个解决方案,使用:

服务器将接收到的内容回显到stdout,客户端打开一个文件并将其发送到服务器,等待它完成,然后关闭套接字并终止。这是通过异步I/O和协同路由的混合实现的

server.py:

from circuits import Component
from circuits.net.sockets import UNIXServer

class Server(Component):

    def init(self, path):
        UNIXServer(path).register(self)

    def read(self, sock, data):
        print(data)

Server("/tmp/server.sock").run()
import sys

from circuits import Component, Event
from circuits.net.sockets import UNIXClient
from circuits.net.events import connect, close, write

class done(Event):
    """done Event"""

class sendfile(Event):
    """sendfile Event"""

class Client(Component):

    def init(self, path, filename, bufsize=8192):
        self.path = path
        self.filename = filename
        self.bufsize = bufsize

        UNIXClient().register(self)

    def ready(self, *args):
        self.fire(connect(self.path))

    def connected(self, *args):
        self.fire(sendfile(self.filename, bufsize=self.bufsize))

    def done(self):
        raise SystemExit(0)

    def sendfile(self, filename, bufsize=8192):
        with open(filename, "r") as f:
            while True:
                try:
                    yield self.call(write(f.read(bufsize)))
                except EOFError:
                    break
                finally:
                    self.fire(close())
                    self.fire(done())

Client(*sys.argv[1:]).run()
client.py:

from circuits import Component
from circuits.net.sockets import UNIXServer

class Server(Component):

    def init(self, path):
        UNIXServer(path).register(self)

    def read(self, sock, data):
        print(data)

Server("/tmp/server.sock").run()
import sys

from circuits import Component, Event
from circuits.net.sockets import UNIXClient
from circuits.net.events import connect, close, write

class done(Event):
    """done Event"""

class sendfile(Event):
    """sendfile Event"""

class Client(Component):

    def init(self, path, filename, bufsize=8192):
        self.path = path
        self.filename = filename
        self.bufsize = bufsize

        UNIXClient().register(self)

    def ready(self, *args):
        self.fire(connect(self.path))

    def connected(self, *args):
        self.fire(sendfile(self.filename, bufsize=self.bufsize))

    def done(self):
        raise SystemExit(0)

    def sendfile(self, filename, bufsize=8192):
        with open(filename, "r") as f:
            while True:
                try:
                    yield self.call(write(f.read(bufsize)))
                except EOFError:
                    break
                finally:
                    self.fire(close())
                    self.fire(done())

Client(*sys.argv[1:]).run()
在我对它的测试中,它的行为完全符合我的预期,没有任何错误 错误,服务器在客户端CLSOE之前获取完整文件 打开插座,然后关机


在与一位了解C套接字的同事讨论后(在cpython中,套接字模块是C套接字的包装器),他谈到了这一点(在PHP内部记录中就是这样做的)

TL&DR:shutdown+quick poll+close或ioctl(SIOCOUTQ)在linux上