2011-08-04 21 views
12

Đối tượng tệp Python có phương thức đọc có tham số kích thước tùy chọn, về cơ bản là số byte tối đa cần trả về. Ví dụ:Tôi có thể lấy một tệp socket.makefile để có cùng ngữ nghĩa đọc như một tệp thông thường không?

fname = "message.txt" 
open(fname, "w").write("Hello World!") 
print open(fname).read() # prints the entire file contents 
print open(fname).read(5) # print "Hello" 
print open(fname).read(99) # prints "Hello World!" 

Vì vậy, mặc dù tệp của chúng tôi có ít hơn 99 ký tự, cuộc gọi tới read(99) sẽ trả về ngay lập tức với tất cả dữ liệu có sẵn.

Tôi muốn nhận hành vi này trên các đối tượng tệp được trả về từ socket.makefile. Nhưng nếu tôi nói:

import socket 
ADDR = ("localhost", 12345) 

listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
listener.bind(ADDR) 
listener.listen(1) 

client = socket.create_connection(ADDR) 
cf = client.makefile("r+b", bufsize=0) 

server, client_addr = listener.accept() 
sf = server.makefile("r+b", bufsize=0) 

sf.write("Hello World!") 
sf.flush() 
print cf.read(99)   # hangs forever 

Theo socket.makefile docs, "Các chế độ khác nhau và bufsize đối số được giải thích theo cùng một cách như bởi được xây dựng trong tập tin() chức năng." Nhưng ví dụ tệp gốc của tôi hoạt động ngay cả khi tôi nói open(fname, "r+b", 0), trong khi tôi không thể tìm ra cách trả về tất cả dữ liệu có sẵn cho đến số byte được chỉ định bằng tệp giả ổ cắm.

Điều này dường như làm việc hoàn toàn tốt nếu tôi chỉ sử dụng socket.recv:

import socket 
ADDR = ("localhost", 12345) 

listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
listener.bind(ADDR) 
listener.listen(1) 

client = socket.create_connection(ADDR) 
server, client_addr = listener.accept() 

server.sendall("Hello World!") 
print client.recv(99)   # prints "Hello World!" 

Vậy có cách nào để làm cho công việc này với socket.makefile, hoặc là loại chức năng "tiên tiến" chỉ đơn giản là không có sẵn?

EDIT: Python 3.2 dường như cư xử một cách chính xác, mặc dù các cú pháp lập luận để socket.makefile dường như đã thay đổi:

import socket 
ADDR = ("localhost", 12345) 

listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
listener.bind(ADDR) 
listener.listen(1) 

client = socket.create_connection(ADDR) 
cf = client.makefile("rwb", buffering=0) 

server, client_addr = listener.accept() 
sf = server.makefile("rwb", buffering=0) 

sf.write(b"Hello World!") 
sf.flush() 
print(cf.read(99))   # prints "Hello World!" 

tôi đã không đào vào mã nguồn chưa tìm ra sự khác biệt giữa các hai phiên bản, nhưng đó có thể là một gợi ý.

+0

@BrandonRhodes Tôi tin rằng đây là một thay thế khả thi để đóng socket 'sock.shutdown (SHUT_WR) ' – Mazyod

Trả lời

22

Vấn đề ở đây là client.read() cố gắng đọc từ vị trí hiện tại đến EOF, nhưng EOF cho ổ cắm chỉ xuất hiện khi bên kia đóng kết nối. Mặt khác, recv sẽ trả về mọi dữ liệu sẵn sàng để đọc (nếu có) hoặc có thể chặn theo cài đặt chặn và thời gian chờ.

Hãy so sánh với trang này:

import socket 
ADDR = ("localhost", 12345) 

listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
listener.bind(ADDR) 
listener.listen(1) 

client = socket.create_connection(ADDR) 
cf = client.makefile("r+b", bufsize=0) 

server, client_addr = listener.accept() 
sf = server.makefile("r+b", bufsize=0) 

sf.write("Hello World!") 
sf.flush() 
sf.close() 
server.close() 
print cf.read(99)   # does not hang 
+1

Câu trả lời này được nó hoàn toàn đúng: tương đương với khái niệm của một tập tin EOF là một ổ cắm gần(); câu trả lời này nên được chấp nhận. –

+0

Nếu bạn chỉ đọc dữ liệu có sẵn thì nó vẫn bị treo? Tôi thấy rằng một khi 99 byte đi vào. Việc đọc sẽ ngừng chặn vì nó đang chờ w/e IO để cung cấp cho nó 99 byte hoặc EOF. – Kaliber64

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