杰瑞科技汇

python file socket

Of course! Let's break down how to work with files and sockets in Python. This is a fundamental concept for network programming, where you need to send the contents of a file over a network.

python file socket-图1
(图片来源网络,侵删)

I'll guide you through this step-by-step, starting with the basics of each component and then combining them to build a practical file transfer application.

The Building Blocks: socket and file

First, let's look at the individual tools we'll be using.

A. Python socket Module

Sockets are endpoints for sending and receiving data across a computer network. Think of them as a phone for your program—you "dial" a server, and you can "talk" (send data) and "listen" (receive data).

Key Socket Concepts:

python file socket-图2
(图片来源网络,侵删)
  • Server Socket: Listens for incoming connections from clients. It's like a receptionist waiting for a call.
  • Client Socket: Initiates a connection to a server. It's like making a phone call.
  • socket.socket(): Creates a new socket object.
  • .bind(): Assigns an address (IP and port) to the server socket.
  • .listen(): Puts the server socket into listening mode.
  • .accept(): Waits for an incoming client connection and returns a new socket object to communicate with that client.
  • .connect(): Used by the client to connect to the server.
  • .send() / .recv(): Used to send and receive data. Crucially, these methods work with bytes, not strings.

B. Python open() and File Handling

To work with files, you use the built-in open() function. This returns a file object, which you can use to read from or write to the file.

Key File Concepts:

  • open(filename, mode): Opens a file.
    • 'r': Read (default)
    • 'w': Write (overwrites the file)
    • 'b': Binary mode. This is essential for file transfers! When you open a file in binary mode, it reads/writes raw bytes, which is exactly what sockets need.
  • .read(): Reads the entire content of a file.
  • .read(size): Reads up to a certain number of bytes.
  • .write(): Writes data to a file.
  • .close(): Closes the file, freeing up resources.

The Core Challenge: Sending a File

The main challenge is that sockets operate in a stream. You can't just send a whole multi-megabyte file in one go if it's too large for memory. The best practice is to read the file in chunks (e.g., 4KB or 8KB at a time) and send each chunk over the socket.

Here is the general logic:

python file socket-图3
(图片来源网络,侵删)

Server Side:

  1. Create a server socket.
  2. Bind it to an IP and port.
  3. Listen for a connection.
  4. When a client connects, accept the connection.
  5. Open the file you want to send in binary read mode ('rb').
  6. Read the file in a loop, sending each chunk over the client socket.
  7. Close the file and the socket.

Client Side:

  1. Create a client socket.
  2. Connect to the server's IP and port.
  3. Open a new file to save the received data in binary write mode ('wb').
  4. Receive data in a loop from the socket, writing each chunk to the new file.
  5. Close the file and the socket.

Complete Example: A Simple File Transfer Script

Let's create a working example. We'll have two Python files: one for the server and one for the client.

server.py - The Sender

This script will wait for a client, send a file named my_data.txt, and then close.

# server.py
import socket
# --- Configuration ---
HOST = '127.0.0.1'  # Standard loopback interface address (localhost)
PORT = 65432        # Port to listen on (non-privileged ports are > 1023)
FILE_TO_SEND = 'my_data.txt'
# --- Server Logic ---
print(f"[SERVER] Starting server on {HOST}:{PORT}")
# 1. Create a TCP socket (AF_INET for IPv4, SOCK_STREAM for TCP)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind((HOST, PORT))
    s.listen()
    print(f"[SERVER] Listening for connections...")
    # 2. Wait for a client to connect
    conn, addr = s.accept()
    with conn:
        print(f"[SERVER] Connected by {addr}")
        # 3. Open the file in binary read mode
        with open(FILE_TO_SEND, 'rb') as f:
            # 4. Read the file in chunks and send it
            while True:
                chunk = f.read(4096)  # Read 4KB at a time
                if not chunk:
                    break  # End of file
                conn.sendall(chunk)
                print(f"[SERVER] Sent {len(chunk)} bytes...")
        print(f"[SERVER] File '{FILE_TO_SEND}' sent successfully.")

client.py - The Receiver

This script will connect to the server, receive the file, and save it as received_data.txt.

# client.py
import socket
# --- Configuration ---
HOST = '127.0.0.1'  # The server's hostname or IP address
PORT = 65432        # The port used by the server
FILE_TO_RECEIVE = 'received_data.txt'
# --- Client Logic ---
print(f"[CLIENT] Connecting to server at {HOST}:{PORT}")
# 1. Create a TCP socket
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect((HOST, PORT))
    print(f"[CLIENT] Connected to server. Receiving file...")
    # 2. Open a new file in binary write mode
    with open(FILE_TO_RECEIVE, 'wb') as f:
        # 3. Receive data in chunks and write it to the file
        while True:
            chunk = s.recv(4096)  # Receive up to 4KB
            if not chunk:
                break  # No more data
            f.write(chunk)
            print(f"[CLIENT] Received {len(chunk)} bytes...")
    print(f"[CLIENT] File saved as '{FILE_TO_RECEIVE}'.")

How to Run It

  1. Create a file to send: In the same directory, create a file named my_data.txt and put some text in it. For example:

    Hello, this is a test file.
    It will be sent over a network socket.
  2. Open two terminal windows.

  3. Run the server: In the first terminal, run the server script.

    python server.py

    You will see:

    [SERVER] Starting server on 127.0.0.1:65432
    [SERVER] Listening for connections...
  4. Run the client: In the second terminal, run the client script.

    python client.py

    You will see output in both terminals:

    • Client Terminal:
      [CLIENT] Connecting to server at 127.0.0.1:65432
      [CLIENT] Connected to server. Receiving file...
      [CLIENT] Received 54 bytes...
      [CLIENT] File saved as 'received_data.txt'.
    • Server Terminal:
      [SERVER] Starting server on 127.0.0.1:65432
      [SERVER] Listening for connections...
      [SERVER] Connected by ('127.0.0.1', 54321)
      [SERVER] Sent 54 bytes...
      [SERVER] File 'my_data.txt' sent successfully.
  5. Check the result: A new file named received_data.txt will be created in the same directory. If you open it, its content will be identical to my_data.txt.


Important Considerations for Real-World Applications

The simple example above works, but a robust file transfer application needs more.

A. Handling File Metadata

How does the client know what file it's receiving and how big it is? You need to send metadata before the file content.

A common protocol is:

  1. Send Filename: Send the name of the file as a string, encoded to bytes.
  2. Send File Size: Send the size of the file as an integer, converted to bytes (e.g., 4 bytes).
  3. Send File Content: Send the actual file content in chunks.

Modified server.py (with metadata):

# ... (socket setup is the same)
with conn:
    print(f"[SERVER] Connected by {addr}")
    with open(FILE_TO_SEND, 'rb') as f:
        # 1. Send filename
        filename_bytes = FILE_TO_SEND.encode('utf-8')
        conn.sendall(len(filename_bytes).to_bytes(4, 'big')) # Send length of filename
        conn.sendall(filename_bytes) # Send filename itself
        # 2. Send file size
        file_size = f.seek(0, 2) # Go to end of file to get size
        f.seek(0) # Go back to the beginning
        conn.sendall(file_size.to_bytes(8, 'big')) # Send size as 8-byte integer
        print(f"[SERVER] Sending file '{FILE_TO_SEND}' of size {file_size} bytes.")
        # 3. Send file content
        while True:
            chunk = f.read(4096)
            if not chunk:
                break
            conn.sendall(chunk)

B. Error Handling

What if the file doesn't exist on the server? What if the network connection drops? Your code should handle these exceptions using try...except blocks.

C. Progress Bars

For large files, it's helpful to show a progress bar. You can use libraries like tqdm to display a simple progress bar in the terminal.

D. Security

This example is not secure. Anyone on your local network can connect to it. For real applications, you would need to:

  • Use TLS/SSL: Encrypt the communication channel using libraries like ssl.wrap_socket().
  • Authentication: Implement a mechanism to verify the identity of the client or user.
分享:
扫描分享到社交APP
上一篇
下一篇