杰瑞科技汇

Python中recv与recvfrom有何区别?

Of course! This is a fundamental concept in network programming with Python. Let's break down recv() and recvfrom(), focusing on their differences, use cases, and practical examples.

Python中recv与recvfrom有何区别?-图1
(图片来源网络,侵删)

The Core Concept: Connection-Oriented vs. Connectionless

The key to understanding recv() vs. recvfrom() lies in the type of socket you are using.

  • recv(): Used with connection-oriented sockets (specifically, TCP sockets). A TCP connection is like a phone call. You first establish a dedicated, reliable channel between two endpoints. Once connected, you don't need to know where the data is coming from because you're already in a conversation with that specific party.
  • recvfrom(): Used with connectionless sockets (specifically, UDP sockets). UDP is like sending a postcard. You just write a message, address it, and send it. You don't have a dedicated connection. The recvfrom() function must therefore tell you two things: 1) the data that arrived, and 2) the address it came from, so you know who to "reply" to.

socket.recv(bufsize, [flags])

This method is the workhorse for TCP communication.

What it does:

Receives data from the socket. The data is returned as a bytes object. The function will block (wait) until at least one byte of data is available.

Key Parameters:

  • bufsize (required): An integer specifying the maximum amount of data to be received at once. If the incoming data is larger than bufsize, the excess data will remain in the operating system's buffer and can be received on a subsequent call to recv().
  • flags (optional): Can be specified as a bitwise OR of values. For most basic use cases, you can omit this. The most common flag is socket.MSG_PEEK, which lets you look at the data in the buffer without removing it.

What it returns:

  • A bytes object containing the received data.
  • An empty bytes object (b'') if the remote side has closed the connection gracefully. This is the standard way to detect a disconnect in TCP.

socket.recvfrom(bufsize, [flags])

This method is essential for UDP communication.

Python中recv与recvfrom有何区别?-图2
(图片来源网络,侵删)

What it does:

Receives data from the socket, just like recv(). However, it also captures the address of the socket that sent the data.

Key Parameters:

  • bufsize (required): Same as in recv(). The maximum number of bytes to receive.
  • flags (optional): Same as in recv().

What it returns:

A tuple containing two elements:

  1. A bytes object with the received data.
  2. A tuple representing the sender's address. The format of this address tuple depends on the address family:
    • For AF_INET (IPv4): (ip_address, port) (e.g., ('192.168.1.100', 54321))
    • For AF_INET6 (IPv6): (ip_address, port, flowinfo, scope_id)

Comparison Table

Feature socket.recv() socket.recvfrom()
Socket Type Connection-Oriented (TCP) Connectionless (UDP)
Use Case After accept() on a server, or after connect() on a client. For servers and clients using datagram sockets.
Return Value bytes object. A tuple: (bytes, sender_address).
Sender Info Not needed. The connection is already established. Crucial. The sender's address is returned.
Blocking Blocks until data is received or connection is closed. Blocks until a datagram is received.

Practical Examples

Let's see them in action with a simple TCP echo server and a simple UDP echo server.

Example 1: TCP Echo Server (recv())

The server waits for a connection, then uses recv() to get data from the connected client.

Python中recv与recvfrom有何区别?-图3
(图片来源网络,侵删)
# tcp_server.py
import socket
HOST = '127.0.0.1'  # Standard loopback interface address (localhost)
PORT = 65432        # Port to listen on (non-privileged ports are > 1023)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind((HOST, PORT))
    s.listen()
    print(f"TCP Server listening on {HOST}:{PORT}")
    conn, addr = s.accept() # conn is a NEW socket object for the connection
    with conn:
        print(f"Connected by {addr}")
        while True:
            data = conn.recv(1024) # Use recv() on the connected socket
            if not data:
                # If recv() returns an empty bytes object, the client has closed the connection
                break
            print(f"Received from TCP client: {data.decode('utf-8')}")
            conn.sendall(data) # Echo the data back

Example 2: TCP Echo Client (recv())

The client connects to the server and uses recv() to get the response.

# tcp_client.py
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 = b"Hello, TCP Server!"
    print(f"Sending to TCP server: {message.decode('utf-8')}")
    s.sendall(message)
    data = s.recv(1024) # Use recv() to get the response
print(f"Received from TCP server: {data.decode('utf-8')}")

Example 3: UDP Echo Server (recvfrom())

The server uses recvfrom() to get both the data and the client's address in one go.

# udp_server.py
import socket
HOST = '127.0.0.1'  # Standard loopback interface address (localhost)
PORT = 65433        # Port to listen on (non-privileged ports are > 1023)
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
    s.bind((HOST, PORT))
    print(f"UDP Server listening on {HOST}:{PORT}")
    while True:
        # Use recvfrom() to get data and the sender's address
        data, addr = s.recvfrom(1024)
        print(f"Received from UDP client {addr}: {data.decode('utf-8')}")
        # Echo the data back to the same address it came from
        s.sendto(data, addr)

Example 4: UDP Echo Client (recvfrom())

The client uses sendto() to send data to a specific address and recvfrom() to get the response.

# udp_client.py
import socket
HOST = '127.0.0.1'  # The server's hostname or IP address
PORT = 65433        # The port used by the server
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
    message = b"Hello, UDP Server!"
    # Use sendto() to send data to a specific address
    s.sendto(message, (HOST, PORT))
    print(f"Sending to UDP server at {HOST}:{PORT}: {message.decode('utf-8')}")
    # Use recvfrom() to get the response and the server's address
    data, addr = s.recvfrom(1024)
print(f"Received from UDP server {addr}: {data.decode('utf-8')}")

How to Run the Examples

  1. Save the four files: tcp_server.py, tcp_client.py, udp_server.py, udp_client.py.
  2. Open two terminal windows.
  3. In the first terminal, run the TCP server:
    python tcp_server.py

    You should see: TCP Server listening on 127.0.0.1:65432

  4. In the second terminal, run the TCP client:
    python tcp_client.py

    You will see the client's output, and the server's terminal will show the connection and received data.

  5. Now, open two new terminals for the UDP example.
  6. In the third terminal, run the UDP server:
    python udp_server.py

    You should see: UDP Server listening on 127.0.0.1:65433

  7. In the fourth terminal, run the UDP client:
    python udp_client.py

    You will see the client's output, and the server's terminal will show the received data and the client's address.

分享:
扫描分享到社交APP
上一篇
下一篇