📓
Be a Javaer
  • Introduction
  • 第 1 章 Java编程开发入门
    • 第 1 节 Java开发准备
    • 第 2 节 Java基本概念
    • 第 3 节 Java数据类型划分
    • 第 4 节 Java运算符
    • 第 5 节 Java程序逻辑控制
    • 第 6 节 Java方法的定义及使用
  • 第 2 章 Java面向对象编程
    • 第 1 节 类与对象
    • 第 2 节 深入分析类与对象
    • 第 3 节 数组的定义与使用
    • 第 4 节 String类的基本概念
    • 第 5 节 String类的常用方法
    • 第 6 节 this关键字
    • 第 7 节 引用传递
    • 第 8 节 数据表与简单Java类映射
    • 第 9 节 对象比较
    • 第 10 节 static关键字
    • 第 11 节 代码块
    • 第 12 节 内部类
    • 第 13 节 链表的定义与使用
    • 第 14 节 继承性
    • 第 15 节 覆写
    • 第 16 节 数组操作
    • 第 17 节 辅助概念
      • final关键字
      • 多态性
    • 第 18 节 抽象类的定义及使用
    • 第 19 节 接口的定义及使用
    • 第 20 节 Object类
    • 第 21 节 拓展概念
      • 匿名内部类
      • 包装类
    • 第 22 节 包的定义及使用
    • 第 23 节 访问控制权限
      • 单例设计模式
      • 多例设计模式
    • 第 24 节 异常的捕获及处理
    • 第 25 节 Java5新特性
      • 可变参数
      • foreach循环
      • 静态导入
    • 第 26 节 泛型
    • 第 27 节 枚举
    • 第 28 节 Annotation
    • 第 29 节 Java7新特性
      • AutoCloseable
      • Try-with-resources
    • 第 30 节 Java8新特性
      • 接口定义增强
      • Lambda表达式
      • 方法引用
      • 函数式接口
  • 第 3 章 Java高级编程
    • 第 1 节 Java多线程基础实现
    • 第 2 节 线程常用操作方法
    • 第 3 节 线程的同步与死锁
    • 第 4 节 生产者与消费者
    • 第 5 节 Java基础类库
      • StringBuffer
      • Runtime
      • System
      • finalize
      • Cleaner
      • 对象克隆
    • 第 6 节 数字操作类
      • Math类
      • Random类
      • 大数字操作类
    • 第 7 节 日期处理类
      • Date类
      • 日期格式化
      • Calendar类
    • 第 8 节 比较器
    • 第 9 节 正则表达式
      • 常用的正则标记
      • String类对正则的支持
      • java.util.regex包支持
    • 第 10 节 反射机制
    • 第 11 节 动态代理
    • 第 12 节 反射与Annotation
    • 第 13 节 国际化程序实现
    • 第 14 节 开发支持类库
      • Arrays类
      • UUID类
      • Optional类
      • ThreadLocal类
      • 定时器
      • Base64加密工具
    • 第 15 节 文件操作
    • 第 16 节 字节流与字符流
    • 第 17 节 IO辅助概念
      • 字符编码
      • 内存流
      • 管道流
      • RandomAccessFile
    • 第 18 节 打印流
    • 第 19 节 System类对IO的支持
    • 第 20 节 对象序列化
    • 第 21 节 IO高级应用
      • 缓冲输入流
      • Scanner
    • 第 22 节 网络编程
    • 第 23 节 类集框架
    • 第 24 节 List集合
    • 第 25 节 集合输出
    • 第 26 节 Map集合
    • 第 27 节 Set集合
    • 第 28 节 集合工具类
      • Stack
      • Queue
      • Properties
      • Collections工具类
    • 第 29 节 数据流Stream
    • 第 30 节 JDBC简介
    • 第 31 节 Statement接口
    • 第 32 节 PreparedStatment接口
    • 第 33 节 批处理与事务处理
  • 第 4 章 Oracle数据库基础
    • 第 1 节 Oracle简介
    • 第 2 节 Oracle安装与配置
    • 第 3 节 SQLPlus命令
    • 第 4 节 SQL简介与数据表分析
    • 第 5 节 SQL简单查询
    • 第 6 节 SQL限定查询
    • 第 7 节 查询排序
    • 第 8 节 综合练习:基础查询
    • 第 9 节 单行函数
    • 第 10 节 多表查询
    • 第 11 节 分组统计查询
    • 第 12 节 子查询
    • 第 13 节 综合案例:复杂查询
    • 第 14 节 数据更新操作
    • 第 15 节 事务处理
    • 第 16 节 数据伪列
    • 第 17 节 数据表的创建与管理
    • 第 18 节 约束的创建与管理
    • 第 19 节 综合案例:数据表操作
    • 第 20 节 序列的定义与使用
  • 第 5 章 JavaWeb基础
  • 第 6 章 走向单体地狱
  • 第 7 章 GitFlow工作流指南
    • 版本控制
    • Git
    • 集中式工作流
    • 功能分支工作流
    • GitFlow 工作流
    • Forking 工作流
    • Pull Requests
  • 第 8 章 微服务入门
    • 第 1 节 微服务简介
    • 第 2 节 Linux
    • 第 3 节 Docker
    • Docker 仓库
    • Ubuntu 安装 Docker
    • Docker 镜像加速器
    • 第 4 节 Docker Compose
    • 第 5 节 GitLab
    • 第 6 节 Nexus
    • 第 7 节 Harbor
  • 第 9 章 再谈微服务
  • 第 10 章 Spring Boot
  • 第 11 章 Spring Cloud Netflix
  • 第 12 章 Apache Dubbo Zookeeper
  • 第 13 章 Spring Cloud Alibaba
  • 第 14 章 Vue
  • 第 15 章 Kubernetes
  • 第 16 章 Spring Security oAuth2
  • 第 17 章 Flutter
  • Redis
    • Redis 入门
    • Redis 的数据类型
    • Redis 事务
    • Jedis
    • Spring Boot 整合 Redis
    • Redis 配置文件
    • Redis 持久化
    • Redis 发布/订阅
    • Redis 主从复制
    • Redis Sentinel
    • Redis 缓存故障
  • Glossary
由 GitBook 提供支持
在本页
  • 网络编程
  • 开发第一个网络程序
  • Echo程序
  • 数据报协议

这有帮助吗?

  1. 第 3 章 Java高级编程

第 22 节 网络编程


利用Java进行网络编程的时代基本上已经过去了。之所以讲解主要的目的是为了阐述网络操作的过程,因为这些过程会影响到之后的JavaEE的开发。

网络编程

网络:是将物理上分开的主机进行连接所形成的交换区域。那么所谓的网络编程值得的就是服务区段与客户端编程的开发操作实现。

但是在实际的工作下对于网络的编程有两种形式:

  • 形式一:C/S结构(Client/Server),此类模式的开发一般要编写两套程序,一套是客户端代码,另外一套属于服务器代码,这样的程序开发非常的麻烦,因为要维护两套程序的使用,但是这类程序有一点好处:安全性高,因为使用的是自己的连接端口,并且使用的是自己的通讯协议。

  • 形式二:B/S结构(Browser/Server),不再单独开发客户端代码,只开发一套服务器端程序,客户端将利用浏览器进行访问,这种模式只需要开发一套程序,但是安全性不高,因为使用的而是公共的HTTP协议,以及公共的80端口。

本次的网络编程值得就是C/S程序开发,即:要开发两套程序,并且这样的程序也可以称为Socket程序,而对于 C/S结构的程序分为两类:

  • TCP程序:采用可靠的链接方式进行的传输;

  • UDP程序:不可靠的链接,属于数据报协议。

传输控制协议(英语:Transmission Control Protocol,缩写为TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。 用户数据报协议(英语:User Datagram Protocol,缩写为UDP),又称用户数据报文协议,是一个简单的面向数据报的传输层协议,正式规范为RFC 768。

开发第一个网络程序

如果要想进行网络程序的开发,那么最为核心的两个类:

  • 服务器类:ServerSocket,主要工作在服务器端,用于接收用户的请求;

  • 客户端类:Socket,每一个链接到服务区上的用户都通过Socket表示;

范例: 定义服务器端 —— 主要使用ServerSocket

  • 构造方法:public ServerSocket(int port) throws IOException,设置监听端口;

  • 接收客户端连接:public Socket accept() throws IOException;

  • 取得客户端的输出功能,Socket类定义方法:public OutputStream getOutputStream() throws IOException;

public class HelloServer {
	public static void main(String[] args) throws Exception {
		ServerSocket server = new ServerSocket(9527); // 所有的服务器必须有端口
		System.out.println("等待客户端连接......");
		Socket client = server.accept(); // 等待客户端连接
		// OutputStream并不方便进行内容的输出,所以利用打印流完成输出
		PrintStream out = new PrintStream(client.getOutputStream());
		out.println("Hello World!");
		out.close();
		client.close();
		server.close();
	}
}

此时的服务器只是出处一个Hello World字符串而后就关闭服务器,只能够处理一次客户端的请求。

范例: 编写客户端 —— Socket

  • 构造方法:public Socket(String host, int port) throws UnknownHostException, IOException

    • host表示主机的IP地址,如果是本机直接访问那么使用localhost(127.0.0.1)代替IP;

  • 得到输入数据:public InputStream getInputStream() throws IOException。

public class HelloClient {
	public static void main(String[] args) throws Exception {
		Socket client = new Socket("localhost", 9527); // 连接服务器端
		// 取得客户端的输入流对象,表示接收服务器端的输出信息
		Scanner scan = new Scanner(client.getInputStream());
		scan.useDelimiter("\n");
		if (scan.hasNext()) {
			System.out.println("[Echo] " + scan.next());
		}
		scan.close();
		client.close();
	}
}

客户端现在也只是连接一次服务器并且接收输入数据输出后结束操作。

Echo程序

在网络编程之中ECHO是一个经典的程序开发模型,本程序的意义在于:客户端随意输入信息并且将信息发送给服务器端,服务器端接收后前面加上一个"ECHO"的标记返回。

本程序设计如下:

  • 由于需要多次输入,所以不能够每次连接后立刻关闭服务端;

  • 可以设置一个字符串,如果输入了"byebye",那么表示结束本次的Echo操作。

范例: 实现服务器端

public class EchoServer {
	public static void main(String[] args) throws Exception {
		ServerSocket server = new ServerSocket(9527);
		Socket client = server.accept(); // 连接客户端
		// 得到客户端输入数据以及向客户端输出数据的对象
		Scanner scan = new Scanner(client.getInputStream());
		PrintStream out = new PrintStream(client.getOutputStream());
		boolean flag = true; // 控制多次接收操作
		while (flag) {
			if (scan.hasNext()) {
				String str = scan.next().trim(); // 得到客户端发送的内容
				if ("bye".equalsIgnoreCase(str)) { // 程序要结束
					flag = false;
					out.println("bye.");
				} else { // 应该回应消息
					out.println("[ECHO] " + str);
				}
			}
		}
		scan.close();
		out.close();
		client.close();
		server.close();
	}
}

范例: 定义客户端

public class EchoClient {
	public static void main(String[] args) throws Exception {
		Socket client = new Socket("localhost", 9527);
		Scanner input = new Scanner(System.in); // 键盘输入数据
		Scanner scan = new Scanner(client.getInputStream());
		PrintStream out = new PrintStream(client.getOutputStream());
		input.useDelimiter("\n");
		scan.useDelimiter("\n");
		boolean flag = true;
		while (flag) {
			System.out.print("> ");
			if (input.hasNext()) {
				String str = input.next().trim();
				out.println(str); // 发送服务器端数据
				if ("bye".equalsIgnoreCase(str)) {
					flag = false; // 结束循环
				}
				if (scan.hasNext()) {
					System.out.println(scan.next().trim()); // 输出回应数据
				}
			}
		}
		input.close();
		scan.close();
		out.close();
		client.close();
	}
}

此时就是实现了一个最简单的服务器端与客户端通讯。

此时的程序只能连接一个客户端,而不能够连接其他客户端,因为所有的操作都是在主线程上进行的开发,也就是说此时的程序属于单线程的网络应用,实际中不可能如此进行,所以为了能够让一个服务器可以同时处理多个客户端的操作,使用多线程描述。把每一个连接到服务器端的客户都作为一个独立的线程对象保留。

范例: 修改服务器端

class EchoThread implements Runnable {
	private Socket client = null;
	public EchoThread(Socket client) {
		this.client = client;
	}
	@Override
	public void run() {
		try {
			Scanner scan = new Scanner(client.getInputStream());
			PrintStream out = new PrintStream(client.getOutputStream());
			boolean flag = true; // 控制多次接收操作
			while (flag) {
				if (scan.hasNext()) {
					String str = scan.next().trim(); // 得到客户端发送的内容
					if ("bye".equalsIgnoreCase(str)) { // 程序要结束
						flag = false;
						out.println("bye.");
					} else { // 应该回应消息
						out.println("[ECHO] " + str);
					}
				}
			}
			scan.close();
			out.close();
			client.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
public class EchoServer {
	public static void main(String[] args) throws Exception {
		ServerSocket server = new ServerSocket(9527);
		boolean flag = true;
		while (flag) {
			Socket client = server.accept(); // 连接客户端
			new Thread(new EchoThread(client)).start();
		}
		server.close();
	}
}

服务开发的基础要素:网络支持类、IO、多线程。

数据报协议

之前的程序都属于TCP程序开发范畴,TCP程序最大的特点是可靠的网络连接,但是在网络程序开发之中还存在着一种UDP程序,称为用户数据报协议。实现UDP需要两个类:

  • DatagramPacket:数据内容;

  • DatagramSocket:网络发送与接收;

UDP通信常用在对传输效率高而可靠性低的场景,例如:网络直播、网络游戏连接等。

范例: 实现一个UDP客户端

public class UDPClient {
    public static void main(String[] args) throws Exception {
        DatagramSocket client = new DatagramSocket(9527);
        byte[] buf = new byte[1024];
        DatagramPacket packet = new DatagramPacket(buf, buf.length);
        System.out.println("waiting for connection...");
        client.receive(packet);
        System.out.println("[RECEIVE] " + new String(buf, 0, packet.getLength()));
        client.close();
    }
}

范例: 实现UDP服务端

public class UDPServer {
    public static void main(String[] args) throws Exception {
        DatagramSocket server = new DatagramSocket(9000);
        String str = "Hello World!";
        DatagramPacket packet = new DatagramPacket(str.getBytes(), 0, str.length(), 
                InetAddress.getLocalHost(), 9527);
        server.send(packet);
        System.out.println("Sent.");
        server.close();
    }
}
上一页第 21 节 IO高级应用下一页第 23 节 类集框架

最后更新于5年前

这有帮助吗?