套接字提供了使用 TCP 在两台计算机之间进行通信的机制。客户端程序在其一端创建一个套接字,并试图将其连接到服务器。
当连接建立后,服务器在其一端创建一个套接字对象。此时,客户端和服务器可以通过向套接字写入和从中读取来进行通信。
java.net.Socket
类表示一个套接字,而 java.net.ServerSocket
类则提供了服务器程序监听客户端并与其建立连接的机制。
Java 套接字编程的步骤
使用套接字在两台计算机之间建立 TCP 连接时,会发生以下步骤:
-
服务器实例化一个
ServerSocket
对象,指定通信所使用的端口号。
-
服务器调用
ServerSocket
类的 accept()
方法。这个方法会一直等待直到一个客户端连接到指定端口的服务器。
-
当服务器正在等待时,客户端实例化一个
Socket
对象,指定要连接的服务器名称和端口号。
-
Socket
类的构造器尝试让客户端连接到指定的服务器和端口号。如果建立了通信,则客户端现在有了一个可以与服务器通信的 Socket
对象。
-
在服务器端,
accept()
方法返回一个与客户端套接字相连的新套接字的引用。
-
建立连接之后,可以通过输入/输出流进行通信。每个套接字都有一个
OutputStream
和一个 InputStream
。客户端的 OutputStream
与服务器的 InputStream
相连,而客户端的 InputStream
则与服务器的 OutputStream
相连。TCP 是一种双向通信协议,因此可以在两个流上同时发送数据。
Java 套接字编程的优点
-
平台独立性 - Java 套接字的最大优点之一是它们是平台独立的。这意味着相同的 Java 代码可以在多个操作系统和设备上运行而无需修改。这允许在网络基础的应用程序跨不同的系统轻松部署,并确保应用程序可以在不同的设备上运行而无需特定于平台的代码。
-
易于使用 - Java 套接字相对容易使用,即使是对于网络编程新手的开发人员也是如此。Java API 提供了一个简单一致的接口来创建和管理套接字,这使得实施基于网络的应用程序变得容易,而不需要理解底层的网络协议。
-
可扩展性 - Java 套接字高度可扩展,使其适合大规模的基于网络的应用程序。它们可以轻松处理数千个并发连接,并可用于创建处理高流量的分布式系统。
-
安全性 - Java 套接字提供了内置的安全通信支持,包括 SSL 和 TLS 加密。这使得创建安全的网络应用程序变得容易,并确保了敏感数据在传输过程中的保护。
-
多线程 - Java 套接字支持多线程,这意味着可以使用多个线程同时处理多个连接。这提高了基于网络的应用程序的性能,并允许它们在不过载的情况下处理大量的请求。
Java 套接字编程的缺点
-
复杂性 - 尽管 Java 套接字相对容易使用,但在实现时仍可能很复杂,特别是对于网络编程新手的开发人员。这种复杂性可能会使调试和故障排除网络应用程序变得困难,这可能是耗时且令人沮丧的。
-
延迟 - Java 套接字可能会在网络应用程序中引入延迟,特别是在处理大量数据时。这可能对于需要实时通信的应用程序(如在线游戏或视频会议)是一个问题。
-
资源密集型 - Java 套接字可能是资源密集型的,尤其是在处理大量连接或大量数据时。这可能对于资源有限的系统(如移动设备或嵌入式系统)是一个问题。
-
有限的协议支持 - Java 套接字支持有限数量的网络协议,这可能对某些类型的基于网络的应用程序是一个限制。这可能会使得创建需要使用专有协议与其他系统通信的应用程序变得困难。
-
潜在的安全漏洞 - Java 套接字像任何基于网络的应用程序一样,容易受到诸如黑客攻击和中间人攻击等安全威胁。设计和实施基于 Java 套接字的系统时必须仔细考虑安全性,以确保敏感数据得到保护,并识别和解决潜在的漏洞。
套接字编程的应用
-
聊天应用程序 - Java 套接字常用于创建聊天应用程序,例如即时通讯程序和在线聊天室。这类应用程序通常使用客户端-服务器架构,其中客户端连接到中央服务器以发送和接收消息。
-
文件传输应用程序 - Java 套接字也可以用于创建文件传输应用程序,例如点对点文件共享程序。这类应用程序使用点对点架构,其中每个设备既充当客户端又充当服务器。这允许设备之间的直接通信,从而提高文件传输的速度和可靠性。
-
远程控制应用程序 - Java 套接字还可以用于创建远程控制应用程序,例如远程桌面软件。这类应用程序使用客户端-服务器架构,其中客户端连接到远程服务器以控制服务器的桌面。这允许用户通过互联网连接从任何设备访问和控制其桌面。
-
多人游戏 - Java 套接字也常用于创建多人游戏,例如在线角色扮演游戏和第一人称射击游戏。这类应用程序通常使用客户端-服务器架构,其中客户端连接到中央服务器以玩游戏。服务器充当客户端之间的中介,处理通信和游戏逻辑。
-
物联网应用程序 - Java 套接字也可以用于物联网(IoT)应用程序,例如智能家居系统。这类应用程序使用客户端-服务器架构,其中 IoT 设备连接到中央服务器以发送和接收数据。这允许远程监控和控制设备,以及数据收集和分析。
套接字编程示例
套接字客户端示例
下面的 GreetingClient
是一个使用套接字连接到服务器并发送问候信息,然后等待响应的客户端程序。
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
类在命令行参数指定的端口上监听客户端连接。
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!