杰瑞科技汇

socket recv python

Of course! Let's dive deep into socket.recv() in Python. This is one of the most fundamental and important functions for network programming.

The Big Picture: What is socket.recv()?

socket.recv() is a method used on a socket object to receive data from a connected socket. It's the primary way your program reads information sent by a remote program over the network.

Think of it like this:

  • socket.send() is like putting a letter in a mailbox (the network).
  • socket.recv() is like checking that mailbox to see if you've got any mail.

The Basic Syntax

data = socket_object.recv(buffer_size)

Let's break down the parameters and return value:

  • socket_object: This is the socket instance you created (e.g., sock).
  • buffer_size (an integer): This is a crucial parameter. It's the maximum number of bytes to receive at one time. If the remote sender sends more data than this, the rest will be waiting for you in the network's buffer, ready for your next call to recv().
    • Best Practice: A common size is 4096 or 8192 bytes (4KB or 8KB). You should choose a reasonable size that balances memory usage with performance.
  • Return Value (data):
    • On success, it returns the data received as a bytes object (bytes).
    • If the remote client has closed the connection gracefully, recv() will return an empty bytes object (b''). This is the standard way to know the connection is over.
    • If an error occurs (e.g., the network connection is broken), it will raise an exception (like ConnectionResetError).

The Most Important Concept: Blocking

By default, socket.recv() is a blocking call.

What does "blocking" mean? It means that when your program calls sock.recv(1024), your program will pause and wait until one of two things happens:

  1. Data is received from the network (even if it's just 1 byte).
  2. The connection is closed by the remote side.

This is a fundamental concept in network programming. Your program flow will literally stop at the recv() line until it gets something.


Code Examples

Let's see recv() in action with a classic "Echo Server" example. The server will receive a message from a client and send the exact same message back.

The Server (server.py)

The server will listen for a connection, receive data, and then send it back.

import socket
# Use a context manager to ensure the socket is properly closed
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    # AF_INET is for IPv4, SOCK_STREAM is for TCP
    s.bind(('127.0.0.1', 65432))  # Bind to localhost on port 65432
    s.listen()                     # Enable the server to accept connections
    print("Server listening on 127.0.0.1:65432")
    # accept() blocks and waits for an incoming connection.
    # It returns a new socket object (conn) to communicate with the client
    # and the address of the client (addr).
    conn, addr = s.accept()
    with conn:
        print(f"Connected by {addr}")
        while True:
            # recv() is a blocking call. It will wait here for data.
            data = conn.recv(1024) # Receive up to 1024 bytes
            # If recv() returns an empty bytes object, the client has closed the connection.
            if not data:
                break
            print(f"Received from client: {data.decode('utf-8')}")
            # Send the received data back to the client
            conn.sendall(data)
            print("Echoed back to client.")
    print("Client disconnected.")

The Client (client.py)

The client will connect to the server, send a message, and wait for the server's response.

import socket
HOST = '127.0.0.1'  # The server's hostname or IP address
PORT = 65432        # The port used by the server
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect((HOST, PORT))
    message_to_send = b"Hello, server! This is a test."
    s.sendall(message_to_send)
    print(f"Sent to server: {message_to_send.decode('utf-8')}")
    # recv() is a blocking call. It will wait here for the server's response.
    data = s.recv(1024)
print(f"Received from server: {data.decode('utf-8')}")

How to Run:

  1. Save the code as server.py and client.py.
  2. Open two terminal windows.
  3. In the first terminal, run the server: python server.py
  4. In the second terminal, run the client: python client.py

You will see the output in both terminals showing the communication.


Common Patterns and Best Practices

Just calling recv() once is often not enough. Here are the common patterns for handling it.

Pattern 1: Receiving a Fixed-Size Message

Sometimes you know exactly how many bytes to expect (e.g., a 4-byte integer header).

# Expecting a 4-byte header
header = conn.recv(4)
if len(header) < 4:
    # Connection closed or error before full header was received
    raise ConnectionError("Connection broken while reading header")
# Now you can process the 4-byte header
message_size = int.from_bytes(header, 'big')

Pattern 2: Receiving Until a Delimiter

This is useful for protocols that end messages with a special character, like a newline (\n).

def recv_until_delimiter(conn, delimiter=b'\n'):
    data = b''
    while True:
        chunk = conn.recv(1024) # Read in chunks
        if not chunk:
            raise ConnectionError("Connection closed before delimiter was found")
        data += chunk
        if delimiter in data:
            break
    # Return the data up to (and including) the delimiter
    return data.split(delimiter)[0] + delimiter

Pattern 3: Receiving All Data (The Robust Way)

The most common mistake is to assume one recv() call is enough. To receive all the data a client is sending, you must loop.

def recv_all(conn, size):
    """Receive exactly 'size' bytes from the socket."""
    data = bytearray()
    while len(data) < size:
        # recv() returns whatever is available, up to 'size' bytes.
        # We need to keep calling it until we have the full amount.
        packet = conn.recv(size - len(data))
        if not packet:
            raise ConnectionError("Connection broken")
        data.extend(packet)
    return bytes(data)
# Example: Receiving a 1024-byte file
file_data = recv_all(conn, 1024)

Pattern 4: The Classic "Echo Server" Loop

This is the pattern from our first example, but it's so important it's worth highlighting again. It shows how to handle a stream of data from a client until they disconnect.

with conn:
    while True:
        data = conn.recv(1024)
        if not data:
            break  # Connection closed by client
        # Process data...
        conn.sendall(data) # Echo it back

Key Takeaways

  1. recv() is for receiving data from a connected socket.
  2. It returns a bytes object.
  3. It is a blocking call by default, meaning your program will pause until data arrives or the connection is closed.
  4. An empty bytes object (b'') is the signal that the remote side has closed the connection.
  5. You must not assume one recv() call will get all the data. Always loop and use the buffer_size to manage how much you read at a time.
  6. Remember to decode the bytes object to a str if you want to work with text (e.g., data.decode('utf-8')).
分享:
扫描分享到社交APP
上一篇
下一篇