Java 教程
- Java - 首页
- Java - 概述
- Java - 历史
- Java - 特性
- Java vs. C++
- JVM - Java虚拟机
- Java - JDK vs JRE vs JVM
- Java - Hello World 程序
- Java - 环境搭建
- Java - 基本语法
- Java - 变量类型
- Java - 数据类型
- Java - 类型转换
- Java - Unicode 系统
- Java - 基本运算符
- Java - 注释
- Java - 用户输入
- Java - 日期和时间
Java 控制语句
- Java - 循环控制
- Java - 决策制定
- Java - if-else
- Java - switch
- Java - for 循环
- Java - for-each 循环
- Java - while 循环
- Java - do-while 循环
- Java - break
- Java - continue
面向对象编程
- Java - 面向对象编程概念
- Java - 对象和类
- Java - 类属性
- Java - 类方法
- Java - 方法
- Java - 变量作用域
- Java - 构造函数
- Java - 访问修饰符
- Java - 继承
- Java - 聚合
- Java - 多态
- Java - 方法重写
- Java - 方法重载
- Java - 动态绑定
- Java - 静态绑定
- Java - 实例初始化块
- Java - 抽象
- Java - 封装
- Java - 接口
- Java - 包
- Java - 内部类
- Java - 静态类
- Java - 匿名类
- Java - 单例类
- Java - 包装类
- Java - 枚举
- Java - 枚举构造函数
- Java - 枚举字符串
Java 内置类
Java 文件处理
Java 错误和异常
- Java - 异常
- Java - try-catch 块
- Java - try-with-resources
- Java - 多重catch块
- Java - 嵌套try块
- Java - finally 块
- Java - throw 异常
- Java - 异常传播
- Java - 内置异常
- Java - 自定义异常
Java 多线程
- Java - 多线程
- Java - 线程生命周期
- Java - 创建线程
- Java - 启动线程
- Java - 线程连接
- Java - 线程命名
- Java - 线程调度器
- Java - 线程池
- Java - 主线程
- Java - 线程优先级
- Java - 守护线程
- Java - 线程组
- Java - 关闭钩子
Java 同步
Java 网络编程
- Java - 网络编程
- Java - Socket 编程
- Java - URL 处理
- Java - URL 类
- Java - URLConnection 类
- Java - HttpURLConnection 类
- Java - Socket 类
- Java -泛型
Java 集合
Java 接口
Java 数据结构
Java 集合算法
高级 Java
- Java - 命令行参数
- Java - Lambda 表达式
- Java - 发送邮件
- Java - Applet 基础
- Java - Javadoc 注释
- Java - 自动装箱和拆箱
- Java - 文件不匹配方法
- Java - REPL (JShell)
- Java - 多版本 Jar 文件
- Java - 私有接口方法
- Java - 内部类菱形运算符
- Java - 多分辨率图像API
- Java - 集合工厂方法
- Java - 模块系统
- Java - Nashorn JavaScript
- Java - Optional 类
- Java - 方法引用
- Java - 函数式接口
- Java - 默认方法
- Java - Base64 编码解码
- Java - switch 表达式
- Java - Teeing Collectors
- Java - 微基准测试
- Java - 文本块
- Java - 动态 CDS 归档
- Java - Z 垃圾收集器 (ZGC)
- Java - 空指针异常
- Java - 打包工具
- Java - 密封类
- Java - 记录类
- Java - 隐藏类
- Java - 模式匹配
- Java - 简洁数字格式化
- Java - 垃圾收集
- Java - JIT 编译器
Java 其他
- Java - 递归
- Java - 正则表达式
- Java - 序列化
- Java - 字符串
- Java - Process API 增强
- Java - Stream API 增强
- Java - 增强@Deprecated 注解
- Java - CompletableFuture API 增强
- Java - 流
- Java - 日期时间 API
- Java 8 - 新特性
- Java 9 - 新特性
- Java 10 - 新特性
- Java 11 - 新特性
- Java 12 - 新特性
- Java 13 - 新特性
- Java 14 - 新特性
- Java 15 - 新特性
- Java 16 - 新特性
Java APIs 和框架
Java 类引用
- Java - Scanner
- Java - 数组
- Java - 字符串
- Java - Date
- Java - ArrayList
- Java - Vector
- Java - Stack
- Java - PriorityQueue
- Java - LinkedList
- Java - ArrayDeque
- Java - HashMap
- Java - LinkedHashMap
- Java - WeakHashMap
- Java - EnumMap
- Java - TreeMap
- Java - IdentityHashMap
- Java - HashSet
- Java - EnumSet
- Java - LinkedHashSet
- Java - TreeSet
- Java - BitSet
- Java - Dictionary
- Java - Hashtable
- Java - Properties
- Java - Collection
- Java - Array
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!