Java 简明教程

Java - Socket Programming

Socket Programming in Java

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

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

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

Steps of Socket Programming in Java

建立以下步骤 TCP 使用套接字连接两台计算机时发生 −

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

  2. 服务器调用 ServerSocket 类的 accept() 方法。此方法会一直等到客户端通过给定端口连接到服务器。

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

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

  5. 在服务器端,accept() 方法返回一个对服务器上与客户端套接字连接的新套接字的引用。

连接建立后,可以使用 I/O 流进行通信。每个套接字都有一个 OutputStream 和一个 InputStream。客户端的 OutputStream 连接到服务器的 InputStream,客户端的 InputStream 连接到服务器的 OutputStream。TCP 是一个双向通信协议,因此数据可以同时通过这两个流发送。

Advantages of Java Socket Programming

  1. Platform Independence - Java 套接字最大的一个优点是它们与平台无关。这意味着相同的 Java 代码可以在多个操作系统和设备上运行,而无需修改。这允许在不同的系统之间轻松部署基于网络的应用程序,并确保可以在不同的设备上运行该应用程序,而无需平台特定的代码。

  2. Easy to Use - Java 套接字也相对容易使用,即使是网络编程新手也是如此。Java API 为创建和管理套接字提供了一个简单、一致的界面,这使得无需理解底层网络协议就可以轻松实现基于网络的应用程序。

  3. Scalability - Java 套接字具有很高的可伸缩性,这使其适用于大规模的基于网络的应用程序。它们可以轻松处理数千个同时连接,并且可以用于创建可以处理高流量的分布式系统。

  4. Security - Java 套接字提供对安全通信的内置支持,包括 SSL 和 TLS 加密。这使得创建安全的基于网络的应用程序变得容易,并确保敏感数据在传输过程中受到保护。

  5. Multithreading - Java 套接字支持多线程,这意味着可以同时使用多个线程来处理多个连接。这改进了基于网络的应用程序的性能,允许它们处理大量请求而不会过载。

Disadvantages of Java Socket Programming

  1. Complexity -虽然 Java 套接字相对容易使用,但它们仍然可能难以实现,特别是对于网络编程新手。这种复杂性可能使得基于网络的应用程序难以进行调试和故障排除,这可能耗时且令人沮丧。

  2. Latency - Java 套接字可能会给基于网络的应用程序引入延迟,特别是在处理大量数据时。对于需要实时通信的应用程序来说,这可能是一个问题,例如在线游戏或视频会议。

  3. Resource Intensive - Java 套接字可能是资源密集型的,特别是当处理大量的连接或数据时。对于资源有限的系统来说,这可能是一个问题,例如移动设备或嵌入式系统。

  4. Limited Protocol Support - Java 套接字支持有限数量的网络协议,这可能限制某些类型的基于网络的应用程序。这可能使得创建需要使用专有协议与其他系统通信的应用程序变得困难。

  5. Potential for Security Vulnerabilities − 类似于任何基于网络的应用程序,Java 套接字均易受安全威胁的影响,例如攻击和中间人攻击。设计和实现基于 Java 套接字的系统时必须密切注意安全性,以确保敏感数据得到保护,并且找出并解决潜在漏洞。

Socket Programming Applications

  1. Chat Applications − Java 套接字通常用于创建聊天应用程序,例如即时消息程序和在线聊天室。此类应用程序通常使用客户端-服务器体系结构,其中客户端连接到中央服务器来发送和接收消息。

  2. File Transfer Applications − Java 套接字也可以用于创建文件传输应用程序,例如点对点文件共享程序。此类应用程序使用点对点体系结构,其中每台设备既充当客户端,又充当服务器。这使得设备之间能够直接通信,从而可以提高文件传输的速度和可靠性。

  3. Remote Control Applications − Java 套接字还可以用于创建远程控制应用程序,例如远程桌面软件。此类应用程序使用客户端-服务器体系结构,其中客户端连接到远程服务器来控制服务器的桌面。这使用户能够从任何具有互联网连接的设备访问和控制他们的桌面。

  4. Multiplayer Games − Java 套接字还常用于创建多人游戏,例如在线角色扮演游戏和第一人称射击游戏。此类应用程序通常使用客户端-服务器体系结构,其中客户端连接到中央服务器来玩游戏。服务器充当客户端之间的中介,处理通信和游戏逻辑。

  5. IoT Applications − Java 套接字还可用于物联网 (IoT) 应用程序,例如智能家居系统。此类应用程序使用客户端-服务器体系结构,其中 IoT 设备连接到中央服务器来发送和接收数据。这可以使用户远程监控和控制设备,并收集和分析数据。

Socket Programming Example

Example: Socket Client

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

Example: Socket Server

以下 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!