Java-网络


术语网络编程是指编写跨多个设备(计算机)执行的程序,其中所有设备都通过网络相互连接。

J2SE API 的 java.net 包包含一组提供低级通信细节的类和接口,使您能够编写专注于解决当前问题的程序。

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

  • TCP - TCP 代表传输控制协议,它允许两个应用程序之间进行可靠的通信。TCP 通常通过 Internet 协议(称为 TCP/IP)使用。

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

本章对以下两个主题提供了很好的理解 -

  • 套接字编程- 这是网络中使用最广泛的概念,并且已经进行了非常详细的解释。

  • URL 处理- 这将单独介绍。单击此处了解Java 语言中的URL 处理。

套接字编程

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

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

java.net.Socket 类代表一个套接字,而 java.net.ServerSocket 类为服务器程序提供了一种机制来侦听客户端并与它们建立连接。

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

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

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

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

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

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

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

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

ServerSocket 类方法

服务器应用程序使用 java.net.ServerSocket 类来获取端口并侦听客户端请求

ServerSocket 类有四个构造函数 -

先生。 方法及说明
1

public ServerSocket(int port) 抛出 IOException

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

2

public ServerSocket(int port, int backlog) 抛出 IOException

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

3

public ServerSocket(int port, int backlog, InetAddress 地址) 抛出 IOException

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

4

public ServerSocket() 抛出 IOException

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

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

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

先生。 方法及说明
1

公共 int getLocalPort()

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

2

公共套接字accept()抛出IOException

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

3

公共无效setSoTimeout(int超时)

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

4

公共无效绑定(SocketAddress主机,int积压)

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

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

套接字类方法

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

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

先生。 方法及说明
1

public Socket(String host, int port) 抛出 UnknownHostException、IOException。

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

2

public Socket(InetAddress host, int port) 抛出 IOException

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

3

public Socket(String host, int port, InetAddress localAddress, int localPort) 抛出 IOException。

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

4

public Socket(InetAddress host, int port, InetAddress localAddress, int localPort) 抛出 IOException。

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

5

公共套接字()

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

当 Socket 构造函数返回时,它并不简单地实例化 Socket 对象,而是实际上尝试连接到指定的服务器和端口。

此处列出了 Socket 类中一些令人感兴趣的方法。请注意,客户端和服务器都有一个 Socket 对象,因此客户端和服务器都可以调用这些方法。

先生。 方法及说明
1

public void connect(SocketAddress host, int timeout) 抛出 IOException

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

2

公共 InetAddress getInetAddress()

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

3

公共 int getPort()

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

4

公共 int getLocalPort()

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

5

公共 SocketAddress getRemoteSocketAddress()

返回远程套接字的地址。

6

public InputStream getInputStream() 抛出 IOException

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

7

public OutputStream getOutputStream() 抛出 IOException

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

8

public void close() 抛出 IOException

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

InetAddress 类方法

此类表示 Internet 协议 (IP) 地址。以下是进行套接字编程时需要的有用方法 -

先生。 方法及说明
1

静态 InetAddress getByAddress(byte[] addr)

返回给定原始 IP 地址的 InetAddress 对象。

2

静态 InetAddress getByAddress(String host, byte[] addr)

根据提供的主机名和 IP 地址创建 InetAddress。

3

静态 InetAddress getByName(字符串主机)

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

4

字符串 getHostAddress()

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

5

字符串 getHostName()

获取此 IP 地址的主机名。

6

静态 InetAddress InetAddress getLocalHost()

返回本地主机。

7

字符串转字符串()

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

套接字客户端示例

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

例子

// 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();
      }
   }
}

套接字服务器示例

下面的 GreetingServer 程序是一个服务器应用程序的示例,它使用 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!