Java 教程

Java 控制语句

面向对象编程

Java 内置类

Java 文件处理

Java 错误和异常

Java 多线程

Java 同步

Java 网络编程

Java 集合

Java 接口

Java 数据结构

Java 集合算法

高级 Java

Java 其他

Java APIs 和框架

Java 类引用

Java 有用资源

Java - 网络编程



Java 网络编程

Java 网络编程 指的是编写在多个设备(计算机)上执行的程序,这些设备通过网络相互连接。

Java 网络编程的优势

  • 创建服务器-客户端应用程序
  • 实现网络协议
  • 实现套接字编程
  • 创建 Web 服务

网络编程中使用的包

J2SE API 的 java.net 包包含一系列类和接口,它们提供了底层的通信细节,允许您编写专注于解决问题的程序。

java.net 包为两种常见的网络协议提供支持:

  • TCP − TCP 代表传输控制协议,它允许两个应用程序之间进行可靠的通信。TCP 通常用于互联网协议之上,称为 TCP/IP。

  • UDP − UDP 代表用户数据报协议,这是一种无连接的协议,允许在应用程序之间传输数据包。

本章对以下两个主题进行了很好的讲解:

  • 套接字编程 − 这是网络编程中最常用的概念,已进行详细解释。

  • URL 处理 − 这将在单独章节中介绍。点击此处了解 Java 语言中的URL 处理

Java 网络编程中的套接字编程

套接字使用 TCP 提供两台计算机之间的通信机制。客户端程序在其通信端创建一个套接字,并尝试将该套接字连接到服务器。

建立连接后,服务器在其通信端创建一个套接字对象。客户端和服务器现在可以通过写入和读取套接字进行通信。

java.net.Socket 类表示套接字,java.net.ServerSocket 类为服务器程序提供了一种机制,用于监听客户端并与之建立连接。

使用套接字在两台计算机之间建立 TCP 连接时,会发生以下步骤:

  • 服务器实例化一个 ServerSocket 对象,表示要进行通信的端口号。

  • 服务器调用 ServerSocket 类的 accept() 方法。此方法一直等到客户端连接到给定端口上的服务器。

  • 服务器等待后,客户端实例化一个 Socket 对象,指定要连接到的服务器名称和端口号。

  • Socket 类的构造函数尝试将客户端连接到指定的服务器和端口号。如果建立了通信,则客户端现在拥有一个能够与服务器通信的 Socket 对象。

  • 在服务器端,accept() 方法返回对服务器上连接到客户端套接字的新套接字的引用。

建立连接后,可以使用 I/O 流进行通信。每个套接字都有一个 OutputStream 和一个 InputStream。客户端的 OutputStream 连接到服务器的 InputStream,客户端的 InputStream 连接到服务器的 OutputStream。

TCP 是一种双向通信协议,因此数据可以同时通过两个流发送。以下是提供完整方法集以实现套接字的有用类。

ServerSocket 类构造函数

java.net.ServerSocket 类用于服务器应用程序获取端口并监听客户端请求。

ServerSocket 类有四个构造函数:

序号 方法和描述
1

public ServerSocket(int port) throws IOException

尝试创建一个绑定到指定端口的服务器套接字。如果端口已被其他应用程序绑定,则会发生异常。

2

public ServerSocket(int port, int backlog) throws IOException

与之前的构造函数类似,backlog 参数指定在等待队列中存储多少个传入客户端。

3

public ServerSocket(int port, int backlog, InetAddress address) throws IOException

与之前的构造函数类似,InetAddress 参数指定要绑定的本地 IP 地址。对于可能具有多个 IP 地址的服务器,InetAddress 用于允许服务器指定其哪个 IP 地址用于接受客户端请求。

4

public ServerSocket() throws IOException

创建一个未绑定的服务器套接字。使用此构造函数时,准备好绑定服务器套接字后,请使用 bind() 方法。

如果 ServerSocket 构造函数没有抛出异常,则表示您的应用程序已成功绑定到指定的端口,并已准备好接受客户端请求。

ServerSocket 类方法

以下是 ServerSocket 类的一些常用方法:

序号 方法和描述
1

public int getLocalPort()

返回服务器套接字正在监听的端口。如果您在构造函数中传入 0 作为端口号并让服务器为您查找端口,则此方法很有用。

2

public Socket accept() throws IOException

等待传入客户端。此方法会阻塞,直到客户端连接到指定端口上的服务器或套接字超时(假设已使用 setSoTimeout() 方法设置了超时值)。否则,此方法将无限期阻塞。

3

public void setSoTimeout(int timeout)

设置服务器套接字在 accept() 期间等待客户端的时间超时值。

4

public void bind(SocketAddress host, int backlog)

将套接字绑定到 SocketAddress 对象中指定的服务器和端口。如果您使用无参数构造函数实例化了 ServerSocket,请使用此方法。

当 ServerSocket 调用 accept() 时,该方法在客户端连接之前不会返回。客户端连接后,ServerSocket 会在未指定的端口上创建一个新的 Socket,并返回对这个新 Socket 的引用。现在客户端和服务器之间存在 TCP 连接,可以开始通信。

Socket 类构造函数

java.net.Socket 类表示客户端和服务器都用来彼此通信的套接字。客户端通过实例化一个 Socket 对象来获取它,而服务器则从 accept() 方法的返回值获取 Socket 对象。

Socket 类有五个构造函数,客户端可以使用它们来连接到服务器:

序号 方法和描述
1

public Socket(String host, int port) throws UnknownHostException, IOException.

此方法尝试连接到指定端口上的指定服务器。如果此构造函数没有抛出异常,则连接成功,客户端已连接到服务器。

2

public Socket(InetAddress host, int port) throws IOException

此方法与之前的构造函数相同,只是主机由 InetAddress 对象表示。

3

public Socket(String host, int port, InetAddress localAddress, int localPort) throws IOException.

连接到指定的主机和端口,在本地主机上创建套接字,地址和端口由参数指定。

4

public Socket(InetAddress host, int port, InetAddress localAddress, int localPort) throws IOException.

此方法与之前的构造函数相同,只是主机由 InetAddress 对象而不是 String 表示。

5

public Socket()

创建一个未连接的套接字。使用 connect() 方法将此套接字连接到服务器。

当 Socket 构造函数返回时,它不仅会实例化一个 Socket 对象,还会尝试连接到指定的服务器和端口。

Socket 类方法

这里列出了一些 Socket 类中值得关注的方法。请注意,客户端和服务器都有一个 Socket 对象,因此这些方法可以由客户端和服务器调用。

序号 方法和描述
1

public void connect(SocketAddress host, int timeout) throws IOException

此方法将套接字连接到指定的主机。仅当您使用无参数构造函数实例化 Socket 时才需要此方法。

2

public InetAddress getInetAddress()

此方法返回此套接字连接到的另一台计算机的地址。

3

public int getPort()

返回套接字在远程计算机上绑定的端口。

4

public int getLocalPort()

返回套接字在本地计算机上绑定的端口。

5

public SocketAddress getRemoteSocketAddress()

返回远程套接字的地址。

6

public InputStream getInputStream() throws IOException

返回套接字的输入流。输入流连接到远程套接字的输出流。

7

public OutputStream getOutputStream() throws IOException

返回套接字的输出流。输出流连接到远程套接字的输入流。

8

public void close() throws IOException

关闭套接字,这使得此 Socket 对象不再能够连接到任何服务器。

InetAddress 类方法

此类表示互联网协议 (IP) 地址。以下是在进行套接字编程时可能需要的一些有用方法:

序号 方法和描述
1

static InetAddress getByAddress(byte[] addr)

给定原始 IP 地址,返回一个 InetAddress 对象。

2

static InetAddress getByAddress(String host, byte[] addr)

基于提供的主机名和 IP 地址创建 InetAddress。

3

static InetAddress getByName(String host)

根据主机名确定主机的 IP 地址。

4

String getHostAddress()

以文本形式返回 IP 地址字符串。

5

String getHostName()

获取此 IP 地址的主机名。

6

static InetAddress InetAddress getLocalHost()

返回本地主机。

7

String toString()

将此 IP 地址转换为字符串。

Java 网络编程示例

在 Java 中实现 Socket 客户端

下面的 GreetingClient 是一个客户端程序,它使用套接字连接到服务器,发送问候语,然后等待响应。

示例:Socket 客户端

// File Name GreetingClient.java
import java.net.*;
import java.io.*;

public class GreetingClient {

   public static void main(String [] args) {
      String serverName = args[0];
      int port = Integer.parseInt(args[1]);
      try {
         System.out.println("Connecting to " + serverName + " on port " + port);
         Socket client = new Socket(serverName, port);
         
         System.out.println("Just connected to " + client.getRemoteSocketAddress());
         OutputStream outToServer = client.getOutputStream();
         DataOutputStream out = new DataOutputStream(outToServer);
         
         out.writeUTF("Hello from " + client.getLocalSocketAddress());
         InputStream inFromServer = client.getInputStream();
         DataInputStream in = new DataInputStream(inFromServer);
         
         System.out.println("Server says " + in.readUTF());
         client.close();
      } catch (IOException e) {
         e.printStackTrace();
      }
   }
}

在 Java 中实现 Socket 服务器

下面的 GreetingServer 程序是一个服务器应用程序示例,它使用 Socket 类监听命令行参数指定的端口号上的客户端:

示例:Socket 服务器

// File Name GreetingServer.java
import java.net.*;
import java.io.*;

public class GreetingServer extends Thread {
   private ServerSocket serverSocket;
   
   public GreetingServer(int port) throws IOException {
      serverSocket = new ServerSocket(port);
      serverSocket.setSoTimeout(10000);
   }

   public void run() {
      while(true) {
         try {
            System.out.println("Waiting for client on port " + 
               serverSocket.getLocalPort() + "...");
            Socket server = serverSocket.accept();
            
            System.out.println("Just connected to " + server.getRemoteSocketAddress());
            DataInputStream in = new DataInputStream(server.getInputStream());
            
            System.out.println(in.readUTF());
            DataOutputStream out = new DataOutputStream(server.getOutputStream());
            out.writeUTF("Thank you for connecting to " + server.getLocalSocketAddress()
               + "\nGoodbye!");
            server.close();
            
         } catch (SocketTimeoutException s) {
            System.out.println("Socket timed out!");
            break;
         } catch (IOException e) {
            e.printStackTrace();
            break;
         }
      }
   }
   
   public static void main(String [] args) {
      int port = Integer.parseInt(args[0]);
      try {
         Thread t = new GreetingServer(port);
         t.start();
      } catch (IOException e) {
         e.printStackTrace();
      }
   }
}

编译客户端和服务器,然后按如下方式启动服务器:

$ java GreetingServer 6066
Waiting for client on port 6066...

按如下方式检查客户端程序:

输出

$ java GreetingClient localhost 6066
Connecting to localhost on port 6066
Just connected to localhost/127.0.0.1:6066
Server says Thank you for connecting to /127.0.0.1:6066
Goodbye!
广告