Python file objects have a read method which takes an optional size argument, which is basically the maximum number of bytes to return. For example:
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!"
So even though our file has fewer than 99 characters, a call to read(99)
returns immediately with all of the available data.
I'd like to get this behavior on the file objects returned from socket.makefile. But if I say:
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
According to the socket.makefile
docs, "The optional mode and bufsize arguments are interpreted the same way as by the built-in file() function." But my original file example works even when I say open(fname, "r+b", 0)
, whereas I can't figure out a way to return all available data up to the specified number of bytes with a socket pseudo-file.
This seems to work perfectly well if I just use 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!"
So is there any way to make this work with socket.makefile
, or is this kind of "advanced" functionality simply not available?
EDIT: Python 3.2 seems to behave correctly, though the argument syntax to socket.makefile
appears to have changed:
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!"
I haven't dug into the source code yet to figure out the difference between these two versions, but that may be a hint.
recvfrom(data, address) − This method receives data from the socket. Two pair (data, address) value is returned by this method. Data defines the received data and address specifies the address of socket sending the data.
SOCK_STREAM. Provides sequenced, two-way byte streams with a transmission mechanism for stream data. This socket type transmits data on a reliable basis, in order, and with out-of-band capabilities. In the UNIX domain, the SOCK_STREAM socket type works like a pipe.
A socket is much like a file, except that a single socket provides a two-way connection between two programs. You can both read from and write to the same socket. If you write something to a socket, it is sent to the application at the other end of the socket.
AF_INET is the Internet address family for IPv4. SOCK_STREAM is the socket type for TCP, the protocol that will be used to transport messages in the network. The . bind() method is used to associate the socket with a specific network interface and port number: # echo-server.py # ... with socket.
The problem here is that client.read()
tries to read from current position to the EOF
, but the EOF for the socket appears only when the other side closes the connection. recv
on the other hand will return any data ready to be read (if there are any), or may block according to blocking and timeout settings.
Compare to this one:
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With