一文带你彻底了解java 网络编程的基本概念
主题:探索Java网络编程:构建连接世界的桥梁
作者:Stevedash
发布日期:2023年8月11日 15点18分
(PS:这一篇文章作为总章,今天着重讲“Socket套接字编程”这里的知识,其他模块的知识,后续补上,拆分成单独章节来慢慢完善该文,并且后面会附带上其他文章的链接,会持续更新的)
前言:
在数字时代的今天,无处不在的网络连接已经成为现代软件开发的重要组成部分。Java作为一门强大的编程语言,提供了丰富的工具和技术,用于实现各种网络应用,从Web应用到分布式系统,再到网络游戏。本篇博客将带您深入探索Java网络编程的核心概念、基本组件以及实际应用。
基本概念:
网络编程是指编写运行在多个设备之间的程序,这些设备都通过网络链接起来。
java.net 包中 J2SE 的 API 包含有类和接口,它们提供低层次的通信细节。你可以直接使用这些类和接口,来专注于解决问题,而不用关注通信细节。
1. 网络编程的基础:连接世界的纽带
在踏入网络编程的奇妙世界之前,让我们先了解一些基本概念:
-
IP地址和端口号: IP地址用于唯一标识网络中的计算机,而端口号则指定计算机上的特定应用程序。它们是网络通信的基石。
-
Socket: Socket(套接字)是网络编程的核心,它代表了网络通信的端点。通过Socket,我们可以在不同计算机之间建立连接并传输数据。
2. TCP和UDP通信:选择合适的通信方式
java.net 包中提供了两种常见的网络协议的支持:
- TCP:TCP(英语:Transmission Control Protocol,传输控制协议) 是一种面向连接的、可靠的、基于字节流的传输层通信协议,TCP 层是位于 IP 层之上,应用层之下的中间层。TCP 保障了两个应用程序之间的可靠通信。通常用于互联网协议,被称 TCP / IP。
- UDP:UDP (英语:User Datagram Protocol,用户数据报协议),位于 OSI 模型的传输层。一个无连接的协议。提供了应用程序之间要发送数据的数据报。由于UDP缺乏可靠性且属于无连接协议,所以应用程序通常必须容许一些丢失、错误或重复的数据包。
小结:Java为我们提供了两种主要的网络通信协议:TCP和UDP。
-
TCP通信: TCP(传输控制协议)提供稳定可靠的连接,适用于重要数据传输。
-
UDP通信: UDP(用户数据报协议)提供快速但不稳定的连接,适用于实时性较高的应用。
3. Socket编程:构建桥梁的工具
Socket编程是Java网络编程的核心技术,通过它我们可以在不同计算机之间建立连接并传输数据。
套接字使用TCP提供了两台计算机之间的通信机制。
客户端程序创建一个套接字,并尝试连接服务器的套接字。
当连接建立时,服务器会创建一个 Socket 对象。客户端和服务器现在可以通过对 Socket 对象的写入和读取来进行通信。
java.net.Socket 类代表一个套接字,并且 java.net.ServerSocket 类为服务器程序提供了一种来监听客户端,并与他们建立连接的机制。
以下步骤在两台计算机之间使用套接字建立TCP连接时会出现:
- 服务器实例化一个 ServerSocket 对象,表示通过服务器上的端口通信。
- 服务器调用 ServerSocket 类的 accept() 方法,该方法将一直等待,直到客户端连接到服务器上给定的端口。
- 服务器正在等待时,一个客户端实例化一个 Socket 对象,指定服务器名称和端口号来请求连接。
- Socket 类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则在客户端创建一个 Socket 对象能够与服务器进行通信。
- 在服务器端,accept() 方法返回服务器上一个新的 socket 引用,该 socket 连接到客户端的 socket。
连接建立后,通过使用 I/O 流在进行通信,每一个socket都有一个输出流和一个输入流,客户端的输出流连接到服务器端的输入流,而客户端的输入流连接到服务器端的输出流。
TCP 是一个双向的通信协议,因此数据可以通过两个数据流在同一时间发送。以下是一些类提供的一套完整的有用的方法来实现 socket。
3.1 服务器端和客户端
-
服务器端: 服务器使用ServerSocket类监听客户端的连接请求,一旦连接建立,可以创建新的Socket实例与客户端通信。
-
客户端: 客户端使用Socket类连接到服务器端的Socket,通过输入输出流进行数据传输。
// 服务器端示例
ServerSocket serverSocket = new ServerSocket(12345);
Socket clientSocket = serverSocket.accept();
// 使用输入输出流进行数据传输
// 客户端示例
Socket socket = new Socket("服务器IP", 12345);
// 使用输入输出流进行数据传输
下面是ServerSocket、Socket类常用的方法
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 使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。 |
4 | public ServerSocket() throws IOException 创建非绑定服务器套接字。 |
创建非绑定服务器套接字。 如果 ServerSocket 构造方法没有抛出异常,就意味着你的应用程序已经成功绑定到指定的端口,并且侦听客户端请求。
这里有一些 ServerSocket 类的常用方法:
序号 | 方法描述 |
---|---|
1 | public int getLocalPort() 返回此套接字在其上侦听的端口。 |
2 | public Socket accept() throws IOException 侦听并接受到此套接字的连接。 |
3 | public void setSoTimeout(int timeout) 通过指定超时值启用/禁用 SO_TIMEOUT,以毫秒为单位。 |
4 | public void bind(SocketAddress host, int backlog) 将 ServerSocket 绑定到特定地址(IP 地址和端口号)。 |
Socket 类的方法
java.net.Socket 类代表客户端和服务器都用来互相沟通的套接字。客户端要获取一个 Socket 对象通过实例化 ,而 服务器获得一个 Socket 对象则通过 accept() 方法的返回值。
Socket 类有五个构造方法.
序号 | 方法描述 |
---|---|
1 | public Socket(String host, int port) throws UnknownHostException, IOException. 创建一个流套接字并将其连接到指定主机上的指定端口号。 |
2 | public Socket(InetAddress host, int port) throws IOException 创建一个流套接字并将其连接到指定 IP 地址的指定端口号。 |
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. 创建一个套接字并将其连接到指定远程地址上的指定远程端口。 |
5 | public Socket() 通过系统默认类型的 SocketImpl 创建未连接套接字 |
当 Socket 构造方法返回,并没有简单的实例化了一个 Socket 对象,它实际上会尝试连接到指定的服务器和端口。
下面列出了一些感兴趣的方法,注意客户端和服务器端都有一个 Socket 对象,所以无论客户端还是服务端都能够调用这些方法。
序号 | 方法描述 |
---|---|
1 | public void connect(SocketAddress host, int timeout) throws IOException 将此套接字连接到服务器,并指定一个超时值。 |
2 | public InetAddress getInetAddress() 返回套接字连接的地址。 |
3 | public int getPort() 返回此套接字连接到的远程端口。 |
4 | public int getLocalPort() 返回此套接字绑定到的本地端口。 |
5 | public SocketAddress getRemoteSocketAddress() 返回此套接字连接的端点的地址,如果未连接则返回 null。 |
6 | public InputStream getInputStream() throws IOException 返回此套接字的输入流。 |
7 | public OutputStream getOutputStream() throws IOException 返回此套接字的输出流。 |
8 | public void close() throws IOException 关闭此套接字。 |
InetAddress 类的方法
这个类表示互联网协议(IP)地址。下面列出了 Socket 编程时比较有用的方法:
序号 | 方法描述 |
---|---|
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 getLocalHost() 返回本地主机。 |
7 | String toString() 将此 IP 地址转换为 String。 |
下面来个具体的实例,服务端和客户端互联,并且服务端可以接受多条客户端的信息并显示
client类的代码:
package main.socket套接字;
import java.io.*;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.Scanner;
public class Client {
public static void main(String[] args) {
try {
//创建一个socket对象,指定连接的IP地址和端口
Socket clientSocket = new Socket("127.0.0.1", 1234);
//获取输出流
OutputStream outputStream=clientSocket.getOutputStream();
PrintWriter printWriter = new PrintWriter(outputStream,true);
System.out.println("远程主机的地址:"+clientSocket.getRemoteSocketAddress());
//从控制台读取用户输入的信息并且发送给服务端
printWriter.println("谢谢连接我:"+clientSocket.getLocalSocketAddress());
Scanner scanner = new Scanner(System.in);
System.out.println("请输入要发送的消息(输入exit退出):");
String message=scanner.nextLine();
while(!message.equals("exit")){
printWriter.println(message);//
System.out.println("请输入要发送的消息(输入exit退出):");
message=scanner.nextLine();
}
//关闭资源
printWriter.close();
outputStream.close();
clientSocket.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
Server类的代码:
package main.socket套接字;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.Scanner;
public class Server{
public static void main(String[] args) {
try{
//创建一个ServerSocket对象,监听指定端口
ServerSocket serverSocket=new ServerSocket(1234);
System.out.println("等待客户链接...");
while(true){
//接受客户端的连接请求
Socket clientSocket=serverSocket.accept();
System.out.println("客户端已连接,Ip地址:"+clientSocket.getInetAddress());
//创建一个新线程用来处理客户端请求
Thread clientThread=new Thread(new ClientHandler(clientSocket));
clientThread.start();
}
}catch (IOException e){
e.printStackTrace();
}
}
}
class ClientHandler implements Runnable {
private Socket clientSocket;
public ClientHandler(Socket clientSocket) {
this.clientSocket = clientSocket;
}
@Override
public void run() {
try {
//获取客户端输入流
InputStream inputStream = clientSocket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String message1;
while ((message1 = reader.readLine()) != null) {
System.out.println("客户端发送了消息:" + message1);
}
//关闭资源
reader.close();
inputStream.close();
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
输出结果如下:Client端
Server端
4. URL和URLConnection:与网络资源互动
Java提供了URL类和URLConnection类,用于处理URL和与Web资源的通信。我们可以使用URL类创建URL对象表示Web资源的地址,然后使用URLConnection类与服务器进行交互。
URL url = new URL("http://www.example.com");
URLConnection connection = url.openConnection();
// 使用输入输出流进行数据传输
5. 多线程网络编程:并发的奥秘
在网络编程中,多线程是不可或缺的,它允许同时处理多个客户端连接,提高性能和响应速度。
6. Web服务:连接网络的纽带
Java支持创建和消费Web服务,使用JAX-WS和JAX-RS来实现。这使得我们能够构建基于Web的分布式应用程序。
7. 网络安全性:保护通信的防线
网络安全性是Java网络编程中至关重要的方面。我们可以使用SSL/TLS加密通信、数字签名和认证机制来保护数据传输的安全性。
8. 序列化和反序列化:数据的转化器
在网络编程中,经常需要对对象进行序列化和反序列化,以便在不同计算机之间传输数据。确保类的所有属性都是可序列化的,否则需要使用transient
关键字标记不可序列化的属性。
9. 网络编程的条件和注意事项:通行的规则
在进行网络编程时,有一些条件和注意事项需要特别关注:
- 类的属性必须是可序列化的,或者使用
transient
关键字标记不可序列化的属性。 - 避免在网络传输中发送敏感信息,尤其是明文密码等。
- 对于大规模的并发连接,需要注意线程安全性和资源管理。
10. 什么是反序列化?
反序列化是将已序列化的数据恢复成原始对象的过程。在网络编程中,接收方可以通过反序列化来重建从发送方传输的对象。
总结
Java网络编程为现代软件开发提供了强大的工具和技术,使得在不同计算机之间进行数据交换和通信变得更加容易。无论是构建Web应用、分布式系统还是网络游戏,掌握网络编程对于程序员来说都是必不可少的一部分。通过本篇博客,您已经了解了Java网络编程的核心概念、基本组件和实际应用。希望这些知识能够帮助您在实际项目中更好地应用网络编程技术。
作者:Stevedash
发表于:2023年8月11日 15点18分
来源:Java 网络编程 | 菜鸟教程 (runoob.com)
注:本文内容基于个人学习理解,如有错误或疏漏,欢迎指正。感谢阅读!如果觉得有帮助,请点赞和分享。