杰瑞科技汇

Python socket errno 错误如何解决?

Of course. Understanding socket.error and its relationship with the errno module is fundamental to writing robust network programs in Python. This error is the primary way your program is notified of low-level, system-level network issues.

Python socket errno 错误如何解决?-图1
(图片来源网络,侵删)

Here's a comprehensive breakdown.


The Core Concept: socket.error

In Python, almost all socket-related errors are raised as exceptions of the type socket.error. This is a base class for all socket exceptions.

  • Location: It's in the socket module, so you import it as import socket.
  • Inheritance: socket.error inherits from OSError. This means you can catch it with a try...except OSError as e: block, which is a common and recommended practice.
# This is the most common way to catch socket errors
try:
    # Some socket operation that might fail
    s.connect(('some-non-existent-server.com', 80))
except OSError as e:
    print(f"A system/OSError occurred: {e}")

The Role of errno: The Error Number

When a socket.error (or OSError) is raised, it contains two key pieces of information:

  1. The error message: A human-readable string (e.g., "Connection refused").
  2. The error number (errno): An integer that uniquely identifies the specific error. This number is a standard defined by the operating system (POSIX).

The errno module in Python provides a human-readable name for these common error numbers.

Python socket errno 错误如何解决?-图2
(图片来源网络,侵删)
  • Location: It's a built-in module, so you import it as import errno.

How to Access errno from an Exception

The exception object has an attribute .errno that holds this integer.

import socket
import errno
try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(('127.0.0.1', 65432)) # Try to connect to a port that is likely not listening
except OSError as e:
    print(f"Error message: {e}")
    print(f"Error number (errno): {e.errno}")
    # Now use the errno module to get the name of the error
    if e.errno == errno.ECONNREFUSED:
        print("The connection was refused. The server is probably not running.")
    elif e.errno == errno.ETIMEDOUT:
        print("The connection timed out.")
    else:
        print(f"An unknown error occurred with errno: {e.errno}")

Common errno Values and Their Meanings

Here is a table of the most frequent socket errors you'll encounter, along with their errno number and name.

Error Name (errno) Number Description Common Scenario
ECONNREFUSED 111 Connection refused. You tried to connect to a port, but there is no process (server) listening on that port.
ETIMEDOUT 110 Connection timed out. The server didn't respond within a certain period (the timeout you set on the socket).
EHOSTUNREACH 113 No route to host. The network cannot deliver the data to the specified IP address. The host might be down or fireblocked.
EADDRINUSE 98 Address already in use. You tried to bind() a socket to an IP/port that is already in use by another socket on your machine.
EAFNOSUPPORT 97 Address family not supported. You tried to use an address family (e.g., AF_INET6) that your system or socket type doesn't support.
ENETUNREACH 101 Network is unreachable. Similar to EHOSTUNREACH, but the network itself is not reachable from your machine.
ECONNRESET 104 Connection reset by peer. The other side closed the connection forcefully. This often happens with HTTP keep-alive when a server times out a connection.
EBADF 9 Bad file descriptor. You tried to use a socket that has already been closed.

Practical Examples

Let's see these errors in action.

Example 1: ECONNREFUSED (Connection Refused)

This happens when you try to connect to a port with no listener.

Python socket errno 错误如何解决?-图3
(图片来源网络,侵删)
import socket
import errno
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Port 12345 is unlikely to have a server running
try:
    s.connect(('127.0.0.1', 12345))
except OSError as e:
    print(f"Caught an error: {e}")
    print(f"Error number: {e.errno}")
    if e.errno == errno.ECONNREFUSED:
        print("Success! We correctly identified 'Connection refused'.")
finally:
    s.close()

Output:

Caught an error: [Errno 111] Connection refused
Error number: 111
Success! We correctly identified 'Connection refused'.

Example 2: EADDRINUSE (Address Already in Use)

This happens when you try to start a server on a port that is already in use.

import socket
import errno
# Start a server on port 8080
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('127.0.0.1', 8080))
server_socket.listen(1)
print("Server is listening on port 8080. Press Ctrl+C to stop.")
# Now, try to start another server on the *same* port
try:
    second_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    second_server.bind(('127.0.0.1', 8080)) # This will fail
except OSError as e:
    print(f"\nCaught an error in the second server: {e}")
    print(f"Error number: {e.errno}")
    if e.errno == errno.EADDRINUSE:
        print("Success! We correctly identified 'Address already in use'.")
finally:
    server_socket.close()

Output:

Server is listening on port 8080. Press Ctrl+C to stop.
Caught an error in the second server: [Errno 98] Address already in use
Error number: 98
Success! We correctly identified 'Address already in use'.

Best Practices

  1. Always Catch OSError (or socket.error): When performing socket operations, wrap them in a try...except OSError block. This is the Pythonic way to handle system-level errors.

  2. Use .errno for Programmatic Logic: Don't just print the error string. Use the e.errno attribute to check for specific conditions and implement retry logic, fallbacks, or user-friendly messages.

  3. Set Timeouts: To avoid your program hanging indefinitely, always set a timeout on your sockets using s.settimeout(seconds). This will cause operations like connect() and recv() to raise an OSError with errno.ETIMEDOUT if they take too long.

  4. Clean Up Resources: Use a finally block to ensure your sockets are always closed, even if an error occurs.

import socket
import errno
import time
def connect_with_retry(host, port, max_retries=3, timeout=5):
    retries = 0
    while retries < max_retries:
        s = None
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.settimeout(timeout)
            print(f"Attempt {retries + 1}: Connecting to {host}:{port}...")
            s.connect((host, port))
            print("Connection successful!")
            return s # Return the connected socket
        except OSError as e:
            print(f"Error: {e}")
            if e.errno == errno.ECONNREFUSED:
                print("Connection refused. Retrying in 2 seconds...")
            elif e.errno == errno.ETIMEDOUT:
                print("Connection timed out. Retrying in 2 seconds...")
            else:
                print(f"An unexpected error occurred: {e.errno}. Not retrying.")
                break # Don't retry on unknown errors
            retries += 1
            time.sleep(2)
        finally:
            if s: # If socket was created but connection failed, close it
                s.close()
    print("Failed to connect after multiple retries.")
    return None
# This will likely fail and demonstrate the retry logic
connect_with_retry('127.0.0.1', 12345)

Summary

Concept What it is Why it's important
socket.error The exception class raised for socket problems. It's the entry point for all error handling in socket programming.
errno An integer code that identifies the specific error. It allows your program to distinguish between "connection refused" and "timed out" and react accordingly.
errno module A Python module that maps error numbers to readable names (e.g., errno.ECONNREFUSED). It makes your code more readable and maintainable than using magic numbers like 111.
分享:
扫描分享到社交APP
上一篇
下一篇