杰瑞科技汇

Java SocketAddress如何正确使用与解析?

Of course! Let's dive deep into java.net.SocketAddress. It's a fundamental, though often overlooked, class in Java's networking API.

Java SocketAddress如何正确使用与解析?-图1
(图片来源网络,侵删)

What is SocketAddress?

In simple terms, SocketAddress is a generic placeholder or a marker interface for a network endpoint. An endpoint is a combination of an IP address and a port number (e.g., 168.1.100:8080).

Think of it as a generic address. You know it's an address for something on a network, but you don't know the specific format (like IPv4, IPv6, or even a Unix domain socket path) until you look at the specific implementation.

Key Characteristics:

  • It's an Abstract Class: SocketAddress is an abstract class, not an interface. This means you can't instantiate it directly with new SocketAddress().
  • It's Generic: It doesn't contain any actual address information (like an InetAddress or a port number). It simply defines the concept of an address.
  • It's a Superclass: All concrete address implementations in Java extend SocketAddress.

Why Does It Exist?

SocketAddress provides a layer of abstraction. The Java networking API was designed to be flexible. It originally only supported IP-based sockets (InetSocketAddress), but it was designed to be extensible to other types of sockets in the future, like Unix domain sockets (which are common on Linux/macOS).

Java SocketAddress如何正确使用与解析?-图2
(图片来源网络,侵删)

By using SocketAddress as a method parameter, the API can accept any kind of address, making it more robust and future-proof.

Analogy: Think of SocketAddress as a generic "Shipping Address" label on a package. The postal service knows it's an address, but the specific format (street number, city, zip code, country) is defined by the concrete implementation of the address. You can just put a generic "Address" label on the box; you need the full details.


The Main Implementation: InetSocketAddress

The most common and important implementation of SocketAddress is InetSocketAddress. This is the class you will use 99% of the time for standard TCP/UDP networking over IP.

InetSocketAddress holds the concrete information:

Java SocketAddress如何正确使用与解析?-图3
(图片来源网络,侵删)
  • An InetAddress (which can be an IPv4 or IPv6 address).
  • A port number (an int).

Creating an InetSocketAddress

You have several ways to create one:

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
public class InetSocketAddressExample {
    public static void main(String[] args) throws UnknownHostException {
        // 1. Using hostname and port
        // DNS lookup will be performed to resolve "google.com" to an IP address.
        InetSocketAddress addr1 = new InetSocketAddress("google.com", 80);
        System.out.println("Addr 1: " + addr1);
        System.out.println("  Hostname: " + addr1.getHostName());
        System.out.println("  IP: " + addr1.getAddress());
        System.out.println("  Port: " + addr1.getPort());
        System.out.println("---------------------------------");
        // 2. Using an InetAddress object and a port
        InetAddress inetAddr = InetAddress.getByName("8.8.8.8");
        InetSocketAddress addr2 = new InetSocketAddress(inetAddr, 53); // DNS port
        System.out.println("Addr 2: " + addr2);
        System.out.println("  Hostname: " + addr2.getHostName()); // May not be the original hostname
        System.out.println("  IP: " + addr2.getAddress());
        System.out.println("  Port: " + addr2.getPort());
        System.out.println("---------------------------------");
        // 3. Using an IP string and a port
        InetSocketAddress addr3 = new InetSocketAddress("127.0.0.1", 8080);
        System.out.println("Addr 3: " + addr3);
        System.out.println("  Hostname: " + addr3.getHostName()); // Will be the IP string if no reverse lookup
        System.out.println("  IP: " + addr3.getAddress());
        System.out.println("  Port: " + addr3.getPort());
    }
}

How is SocketAddress Used in Practice?

You'll typically encounter SocketAddress when working with sockets, especially when you need to bind or connect to a specific endpoint.

Example 1: ServerSocket

When you create a ServerSocket, you bind it to a specific address and port to listen for incoming connections.

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
public class ServerSocketExample {
    public static void main(String[] args) {
        // Create a SocketAddress to bind the server to
        InetSocketAddress serverAddress = new InetSocketAddress("127.0.0.1", 5000);
        try (ServerSocket serverSocket = new ServerSocket()) {
            // Bind the server socket to our specific address and port
            serverSocket.bind(serverAddress);
            System.out.println("Server is listening on " + serverSocket.getLocalSocketAddress());
            // ... accept connections, etc. ...
        } catch (IOException e) {
            System.err.println("Could not start server: " + e.getMessage());
        }
    }
}

Example 2: Socket

When you connect a client Socket to a server, you specify the server's address.

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
public class SocketClientExample {
    public static void main(String[] args) {
        // The address of the server we want to connect to
        InetSocketAddress serverAddress = new InetSocketAddress("127.0.0.1", 5000);
        try (Socket socket = new Socket()) {
            // Connect to the server's address
            System.out.println("Connecting to server at " + serverAddress);
            socket.connect(serverAddress);
            // If connect() returns without an exception, we are connected
            System.out.println("Connected to server: " + socket.getRemoteSocketAddress());
            // Send some data
            OutputStream out = socket.getOutputStream();
            out.write("Hello, Server!".getBytes());
            System.out.println("Data sent.");
        } catch (IOException e) {
            System.err.println("Failed to connect to server: " + e.getMessage());
        }
    }
}

Example 3: DatagramSocket

For UDP, the usage is very similar.

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
public class DatagramSocketExample {
    public static void main(String[] args) {
        // The address we want to send the packet to
        InetSocketAddress targetAddress = new InetSocketAddress("127.0.0.1", 5001);
        try (DatagramSocket socket = new DatagramSocket()) {
            String message = "Hello from UDP Client!";
            byte[] buffer = message.getBytes();
            // Create a packet to send to the target address
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length, targetAddress);
            System.out.println("Sending UDP packet to " + targetAddress);
            socket.send(packet);
            System.out.println("Packet sent.");
        } catch (SocketException e) {
            System.err.println("Socket error: " + e.getMessage());
        } catch (IOException e) {
            System.err.println("I/O error: " + e.getMessage());
        }
    }
}

Other Implementations (Less Common)

While InetSocketAddress is the king, other implementations exist, primarily for niche or advanced use cases.

  • UnixDomainSocketAddress (Java 16+): This represents a Unix domain socket address, which is an inter-process communication (IPC) mechanism. Instead of an IP/port, it uses a file path on the filesystem. This is much faster than TCP for communication on the same machine.

    // Java 16+ example
    import java.net.UnixDomainSocketAddress;
    import java.nio.file.Paths;
    UnixDomainSocketAddress uds = UnixDomainSocketAddress.of(Paths.get("/tmp/my.socket"));
  • Inet6SocketAddress (Internal): This is a specialized version for IPv6 addresses. You usually don't interact with it directly, as InetSocketAddress handles both IPv4 and IPv6 seamlessly.


Key Methods of SocketAddress

Since it's abstract, SocketAddress itself only has a few methods:

  • String toString(): Returns a string representation of the address (e.g., /127.0.0.1:8080).
  • boolean equals(Object obj): Compares this address to another for equality.
  • int hashCode(): Returns a hash code for the address.

Important: The SocketAddress class does not have getPort() or getAddress() methods. These are specific to InetSocketAddress. This is why you often see code that checks the type before casting:

// This is a common pattern when dealing with a generic SocketAddress
SocketAddress genericAddress = ...; // Could be from a method like socket.getRemoteSocketAddress()
if (genericAddress instanceof InetSocketAddress) {
    InetSocketAddress inetAddress = (InetSocketAddress) genericAddress;
    int port = inetAddress.getPort();
    InetAddress ip = inetAddress.getAddress();
    System.out.println("Connected to IP: " + ip + " on port: " + port);
} else if (genericAddress instanceof UnixDomainSocketAddress) {
    // Handle Unix domain socket
    System.out.println("Connected to a Unix domain socket.");
}

Summary

Feature Description
What it is An abstract class representing a generic network endpoint.
Purpose Provides abstraction for network addresses, allowing the API to be flexible and support different types of sockets (like IP and Unix domain sockets).
Main Implementation InetSocketAddress. This is what you use for all standard TCP/UDP networking. It contains an InetAddress and a port number.
How to Use Pass it to bind(), connect(), or send() methods of sockets like ServerSocket, Socket, and DatagramSocket to specify where to listen or connect.
Other Implementations UnixDomainSocketAddress (Java 16+) for high-performance local IPC.
Key Takeaway You will almost always work with InetSocketAddress directly. You'll only see the generic SocketAddress type when it's returned by methods like getRemoteSocketAddress().
分享:
扫描分享到社交APP
上一篇
下一篇