2011-08-04 15 views
12

Python dosya nesneleri, temel olarak döndürülen maksimum bayt sayısı olan isteğe bağlı boyut argümanını alan bir okuma yöntemine sahiptir. Örneğin:Bir normal dosyayla aynı okunan semantiklere sahip olmak için bir socket.makefile alabilir miyim?

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!" 

Yani bizim dosya daha az 99 karakter, hemen eldeki verilerin hepsi ile read(99) getiriler bir çağrı olsa bile.

Bu davranışı, socket.makefile'dan döndürülen dosya nesnelerine almak istiyorum. Ama söylersem:

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 

socket.makefile Docs göre "isteğe bağlı modu ve BUFSIZE argümanlar yerleşik dosyası() işlevi tarafından aynı şekilde yorumlanır." Ancak, özgün dosya örneğim, open(fname, "r+b", 0) derken bile çalışır, oysa mevcut tüm verileri belirtilen bir bayt sayısına bir soket sözde dosyasıyla döndürmenin bir yolunu anlayamıyorum. Sadece kullanırsanız

Bu gayet iyi iş gibi görünüyor 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!" 

Yani socket.makefile ile bu işi yapmak için herhangi bir yolu yoktur, ya da "gelişmiş" işlevsellik bu tür basit yok?

DÜZENLEME:

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!" 

Bunları arasındaki farkı anlamaya henüz kaynak koduna kazılmış değil: Python 3.2 socket.makefile argüman sözdizimi değişmiş gibi görünse de, doğru davranmaya görünüyor iki versiyon, ama bu bir ipucu olabilir.

+0

@BrandonRhodes bu 'sock.shutdown (SHUT_WR)' – Mazyod

cevap

22

Buradaki sorun, client.read()'un geçerli konumdan EOF numarasına okumaya çalışmasıdır, ancak soketin EOF'si yalnızca diğer taraf bağlantıyı kapattığında görünür. Diğer yandan, recv, okunmaya hazır herhangi bir veriyi (varsa) döndürür veya engelleme ve zaman aşımı ayarlarına göre engelleyebilir.

buna karşılaştırın:

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

Bu cevap tam olarak doğru olur soket kapanış başka uygun bir alternatif olduğuna inanıyorum: Bir dosyanın kavramsal eşdeğer EOF bir soket close(); bu cevap kabul edilmeli. –

+0

Sadece mevcut verilere okuyorsanız hala duruyor mu? 99 bayt bir kez geldiğinde bunu anlamaya başladım. Okuma, 99 byte veya EOF vermesi için w/e IO'nun beklemesini engelliyor. – Kaliber64

İlgili konular