2015-06-03 11 views
6

Tôi đang viết một mô-đun Python đang giao tiếp với một chương trình đi qua các khe cắm unix. Máy khách (mô đun python) ghi dữ liệu vào socket và máy chủ tiêu thụ chúng.Ổ cắm Python đóng trước khi tất cả dữ liệu đã được tiêu thụ bởi điều khiển từ xa

# Simplified version of the code used 
outputStream = socket.socket(socketfamily, sockettype, protocol) 
outputStream.connect(socketaddress) 
outputStream.setblocking(True) 
outputStream.sendall(message) 
.... 
outputStream.close() 

Vấn đề của tôi là khách hàng Python có xu hướng để kết thúc và đóng ổ cắm trước khi dữ liệu đã được đọc một cách hiệu quả bởi các máy chủ dẫn đến một "đường ống bị hỏng, Connection reset by peer" ở phía máy chủ. Bất cứ điều gì tôi làm, cho mã Python tất cả mọi thứ đã được gửi đi và do đó các cuộc gọi đến send() sendall() select() đều thành công ...

Cảm ơn trước

EDIT: Tôi không thể sử dụng tắt máy vì mac OS

EDIT2: tôi cũng đã cố gắng để loại bỏ thời gian chờ và gọi setblocking (True) nhưng nó không thay đổi bất cứ điều gì

EDIT3: Sau khi đã sẵn sàng vấn đề này http://bugs.python.org/issue6774 có vẻ như rằng các tài liệu là không cần thiết đáng sợ vì vậy tôi đã khôi phục việc tắt máy nhưng vẫn gặp sự cố tương tự:

# 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() 

Trả lời

0

IHMO điều này được thực hiện tốt nhất với thư viện/khung công tác I/O Asynchornous. Dưới đây là một giải pháp sử dụng circuits:

Máy chủ lặp lại những gì nó nhận được để stdout và khách hàng mở tệp và gửi tệp này đến máy chủ đang chờ nó hoàn thành trước khi đóng socket và kết thúc. Điều này được thực hiện với một hỗn hợp của Async I/O và Coroutines.

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() 

client.py:

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() 

Trong thử nghiệm của tôi về này nó cư xử chính xác như tôi hy vọng nó sẽ không có lỗi và các máy chủ nhận được tệp hoàn chỉnh trước khi khách hàng clsoes ổ cắm và tắt.

0

Sau một cuộc thảo luận với một đồng nghiệp nhận thức được những ổ cắm C (trong CPython module socket là một wrapper cho ổ cắm C) ông nói về http://ia600609.us.archive.org/22/items/TheUltimateSo_lingerPageOrWhyIsMyTcpNotReliable/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable.html này (đó là cách nó được thực hiện trong PHP nội bộ cho các hồ sơ)

TL & DR: tắt máy + cuộc thăm dò nhanh + đóng hoặc ioctl (SIOCOUTQ) trên linux

Các vấn đề liên quan