Java高级程序设计笔记 • 【第4章 网络编程】
全部章节 >>>>
本章目录
4.1 网络基础知识
- 计算机网络,就是将分布在不同地域的计算机与专门的外部设备用通信线路互联成一个规模庞大、功能强大的网络系统,从而使众多计算机可以方便地互相传递信息,共享数据信息资源
- 网络中不可避免的就是信息交互,而多台计算机终端之间的信息交互就必须依靠网络编程实现,Java中也针对网络通信提供了大量的API,使开发网络通信应用变的更为简单
4.1.1 IP地址
- IP 地址用于唯一标识网络中的一台计算机,也可以是一台打印机或一部智能手机等终端设备,网络中每台计算机都有独立唯一IP地址
- IP 地址是一个 32 位整数,通常将其分为 4 个 8 位的二进制数据,每位之间用圆点隔开,每个8 位整数可以转换成一个 0 ~ 255 的十进制整数,如局域网IP通常为192.168.0.XXX
技巧:在windows操作系统的命令提示符下,输入ipconfig可以查看本机ip地址
4.1.2 端口号
提问:
- 通过IP地址可以定位到具体设备,电脑中有很多软件,如何能把信息数据发送给指定软件接收
- 端口是一个 16 位的整数,用于表示数据交给哪个计算机中的通信程序(微信、QQ 或 LOL 等)处理,不同的应用程序处理不同端口上的数据,同一台计算机上不能有两个程序使用同一个端口,端口号为 0 ~ 65535
提醒:
前1024个端口已被系统占用,使用时尽量避开常用端口
4.1.3 使用InetAddress
Java 提供了 InetAddress 类代表 IP 地址,InetAddress 下还有两个子类 Inet4Address 和 Inet6Address,它们分别代表 IPv4 和 IPv6 地址 InetAddress 类没有提供构造方法,而是提供了静态方法来获取 InetAddress 实例
方法名 |
作用 |
public static InetAddress getName(String host) |
根据主机获取对应的 InetAddress 对象 |
Public static InetAddress getLocalHost() |
获取本机 IP 地址所对应的 InetAddress 实例 |
public String getHostAddress() |
返回该 InetAddress 实例所对应的 IP 地址字符串 |
public String getHostName() |
返回此 IP 地址的主机名称 |
4.1.4 InetAddress 类的具体操作
示例:根据主机名获取对应的 InetAddress 对象
// 根据主机名获取对应的 InetAddress 对象
InetAddress ip = InetAddress.getByName("www.sina.com");
// 获取该 InetAddress 实例的 IP 地址字符串
String ipStr = ip.getHostAddress();
System.out.println(" 新浪网地址 :" + ipStr);
// 获取该 InetAddress 实例的主机名称
String hostName = ip.getHostName();
System.out.println(" 新浪主机名 :" + hostName);
4.1.5 实践练习
4.2 基于TCP协议的网络编程
4.2.1 TCP 协议基础
- TCP/IP 通信协议是一种可靠的网络协议,它在通信的两端各建立一个 Socket,从而在通信的两端之间形成网络的虚拟链路,两端的程序就可以通过虚拟链路进行通信
- Java 对基于 TCP 协议的网络通信提供了良好的封装,Java 使用 Socket 来代表连接的通信端口,并通过 Socket 产生的 I/O 流来进行网络通信
- 使用 TCP 协议编写网络程序,需要提供服务端程序和客户端程序
- Java 中的 ServerSocket 类作用类似于114 查号台总机,Socket 类可以实现普通电话和 114 查号台的分机通话功能,整个交互过程如下图
基于TCP协议服务端和客户端建立连接步骤
- 服务端程序创建 ServerSocket 对象,调用 accept() 方法,等待客户端连接
- 客户端程序创建 Socket 对象并请求与服务端建立连接
- 服务端接收客户端的连接请求,并创建新的 Socket 对象与客户端建立专线连接
- 实现(2)和(3)步骤中建立连接的两个 Socket 类在同一线程上对话
- 服务端重新等待新的连接请求
4.2.2 创建服务端套接字
在 Java 中使用的 ServerSocket 对象用户监听是来自客户端的 Socket 类连接,如果没有连接,它将一直处于等待状态,ServerSocket 类包含一个来自客户端的连接请求的监听方法
ServerSocket 类的常用方法
方法名 |
作用 |
public ServerSocket(int port) |
构造方法,用指定端口创建 ServerSocket 实例 |
public Socket accept() |
接收客户端的 Socket 类请求 |
public InetAddress getInetAddress() |
返回服务端主机 IP 地址 |
public void close() |
关闭 ServerSocket 对象 |
serverSocket实例调用accept方法后,就处于等待状态
示例:使用ServerSocket创建服务端
// 创建 ServerScoket 实例,并在 8888 端口监听客户端
ServerSocket server = new ServerSocket(8888);
// 调用 accep() 方法等待客户端的连接,该方法是一个阻塞方法,如果没有客户端请求服务,该方法下的代码将不会执行
System.out.println(" 服务端套接字已经创建,开始等待来自客户端的连接 ");
Socket socket = server.accept();
System.out.println(" 有客户端已成功连接 ");
4.2.3 创建客户端套接字
客户端使用 Socket 类连接到指定的服务端,每个 Socket 对象代表一个客户端,Socket 类的常用方法如下表
方法名 |
作用 |
public Socket(String host,int port) |
public Socket(String host,int port) 构造方法,创建连接到指定远程主机和端口的 Socket 实例 |
public InputStream getInputStream() |
返回该 Socket 对象对应的输入流 |
public OutputStream getOutputStream() |
返回该 Socket 对象对应的输出流 |
public void close() |
关闭 ServerSocket 对象 |
int port Ip和端口必须和服务端保持一致
示例:使用Socket创建客户端和服务端连接
// 创建客户端 Socket 实例,连接指定 IP 地址和指定端口的服务端
Socket socket = new Socket("127.0.0.1", 8888);
说明:
- 示例中的127.0.0.1代表本机,也可以使用本地IP地址,如果连接网络中其他电脑,则更改为对应IP即可
- 代码执行过程中注意进行合理的异常处理,网络编程中可能出现的异常较多
4.2.4 基于TCP的通信
提问:
刚才实现的仅仅为两台设备通过TCP方式建立连接,如何进行通信?
在建立连接的基础之上,可以通过前面学习的输入流、输出流进行信息的发送和接收,从Socket中可以获取输入流、输出流
示例:使用输入输出流进行信息发送和接收
客户端程序发送数据
// 创建 ServerSocket 类,用于监听客户端 Socket 类的请求连接
ServerSocket server = new ServerSocket(8888);
// 等待客户端的连接,客户端连接后,与客户端对应一个 Socket 管道
Socket socket = server.accept();
// 获得 Socket 管道输入的数据的字节输入流
OutputStream out = socket.getOutputStream();
// 使用打印流包装字节输出流,更为方便输出内容
PrintWriter writer = new PrintWriter(out);
writer.println(“ 欢迎您的访问 ”); //发送信息
writer.close();
server.close();
客户端程序读取数据
// 客户端连接到本机端口号是 8888 的服务端
Socket socket = new Socket("127.0.0.1", 8888);
// 获得 Socket 管道中获取读取数据的字节输入流
InputStream in = (InputStream) socket.getInputStream();
// 为了便于读取数据,将 in 转换成字符流
InputStreamReader isr = new InputStreamReader(in);
// 用 BufferdReader 包装转换后的字符流
BufferedReader reader = new BufferedReader(isr);
String data = reader.readLine();
System.out.println(" 服务端对客户端说 :" + data);
reader.close();
socket.close();
4.2.5 实践练习
4.3 使用 Socket 类进行单向通信
使用 Socket 类套接字,可以进行服务端和客户端的通信。Socket 类通信主要分为单向通信和多向通信两种
单向通信就是指只有一端发送数据,另一端只需接收数据,比如,服务端发送数据到客户端,客户端不需要发送数据到服务端
4.3.1 服务端读取数据
示例代码:
// 创建服务端套接字,监听 8888 接口
server = new ServerSocket(8888);
// 保存客户端发送的数据
String data = null;
while (true) {
// 等待客户端的连接,返回用来通信的 Socket 对象
Socket socket = server.accept();
// 获取客户端的输入流,用来读取传来的数据
InputStream in = socket.getInputStream();
// 将字节流包装成字符流
reader = new BufferedReader(new InputStreamReader(in));
// 判断输入流内的数据是否读取完毕
while ((data = reader.readLine()) != null) {
System.out.println(" 来自客户端的问候:" + data);}
break;
使用while(true)接收多个客户端连接
第二个while循环读取客户端发送的内容
4.3.2 客户端发送数据
示例代码:
// 创建客户端套接字,并连接到服务端
Socket client = new Socket("127.0.0.1", 8888);
// 创建一个可以向服务端发送数据的输出流对象
PrintWriter writer = new PrintWriter(client.getOutputStream());
// 向服务端写入数据
writer.write("hello,server!");
// 清空输出流缓存
writer.flush();
这里可以使用循环模拟不停发送数据
4.3.3 实践练习
4.4 使用Socket类进行双向通信
双向通信是指服务端和客户端都可以发送和接收数据,但是如果服务端需要同时接收多个客户端并且通信,复杂度将大大提高
ECHO 程序是网络编程通信交互的一个经典案例,称为回应程序,即客户端输入哪些内容,服务端会在这些内容前加上“ECHO”并将信息发回给客户端
4.4.1 双向通信服务端
服务端关键代码
// 创建服务端套接字对象
ServerSocket this.server = new ServerSocket(8888);
// 是否关闭服务端连接
boolean flag = true;
while (flag) {
// 获取连接的客户端套接字对象
socket = server.accept();
// 获取 socket 相关的输入流和输出流
BufferedReader reader = getReader(socket);
BufferedWriter writer = getWriter(socket);
// 保存客户端发送的数据
String data = null;
}
while ((data = reader.readLine()) != null) {
// 当获取的信息是“bye”时,关闭流
if ("bye".equals(data)) {
flag = false; //退出的标志
//关闭相关资源 并且 break;}
else {System.out.println(" 来自客户端的数据:" + data);
// 回写给客户端的数据
writer.write("echo:" + data);
// 插入一个行分隔符,readLine() 方法用来判定字符串有没有结束
writer.newLine();
// 刷新输出缓冲区
writer.flush();
}
}
循环读取客户端发送数据,直到发送的是bye退出
4.4.2 双向通信客户端
客户端关键代码
// 创建服务端套接字对象
ServerSocket this.server = new ServerSocket(8888);
// 是否关闭服务端连接
boolean flag = true;
while (flag) {
// 获取连接的客户端套接字对象
socket = server.accept();
// 获取 socket 相关的输入流和输出流
BufferedReader reader = getReader(socket);
BufferedWriter writer = getWriter(socket);
// 保存客户端发送的数据
String data = null;
}
else {
// readLine() 方法必须读取到行分隔符才返回读取。所以传递给输入流的字符串必须
包含行分隔符
System.out.println(" 客户端输出的数据 --->\t" + data);
writer.write(data);
// 插入一个行分隔符作为内容结束的标识
writer.newLine();
// 清空缓冲区
writer.flush();
// 读取服务端返回的数据
System.out.println(" 服务器响应的数据 --->\t " + reader.readLine());
}
4.4.3 TCP双向通信
说明:
- 以上双向通信案例仅仅是客户端发送一条,然后马上接收(读取)服务端返回的数据,并不能实现自由聊天,随意发送和接收
- 这是因为读取和发送数据时受制于主线程约束,因为读取数据时采用循环读取,会占据主线程资源,此时无法进行其他操作
- 如果想实现自由双向通信功能,需要在服务端和客户端分别结合多线程功能进行实现,但是难度相应增加很多
4.4.4 实践练习
总结:
网络中通过IP地址可以定位到具体设备,通过端口可以和设备上的不同软件进行通信,Java中使用InetAddress类代表IP地址
基于TCP通信服务端步骤为
- 服务端创建ServerSocket,并指明通信端口号
- 调用serverSocket对象accept方法,等待客户端连接,返回Socket对象
- 从Socket对象中获取输入流、输出流进行读取或发送数据
- 关闭相关资源
基于TCP通信客户端步骤为
- 创建Socket对象,指明连接的服务端IP和端口
- 从Socket对象中获取输入流、输出流进行读取或发送数据
- 关闭相关资源
Java高级程序设计笔记 • 【第4章 网络编程】的更多相关文章
- Java高级程序设计笔记 • 【目录】
持续更新中- 我的大学笔记>>> 章节 内容 实践练习 Java高级程序设计作业目录(作业笔记) 第1章 Java高级程序设计笔记 • [第1章 IO流] 第2章 Java高级程序设 ...
- [CSAPP笔记][第十一章网络编程]
第十一章 网络编程 我们需要理解基本的客户端-服务端编程模型,以及如何编写使用因特网提供的服务的客户端-服务端程序. 最后,我们将把所有这些概念结合起来,开发一个小的但功能齐全的Web服务器,能够为真 ...
- 《python核心编程》读书笔记--第16章 网络编程
在进行网络编程之前,先对网络以及互联网协议做一个了解. 推荐阮一峰的博客:(感谢) http://www.ruanyifeng.com/blog/2012/05/internet_protocol_s ...
- Java高级程序设计笔记 • 【第1章 IO流】
全部章节 >>>> 本章目录 1.1 File类访问文件 1.1.1 File 类 1.1.2 File 类方法 1.1.3 实践练习 1.2 文件过滤器 1.2.1 Fi ...
- Java高级程序设计笔记 • 【第6章 设计模式】
全部章节 >>>> 本章目录 6.1 设计模式 6.1.1 设计模式概述和分类 6.1.2 单列模式介绍 6.1.3 单例模式的实现 6.1.4 实践练习 6.2 单例模式 ...
- Java高级程序设计笔记 • 【第5章 XML解析】
全部章节 >>>> 本章目录 5.1 XML 文档概述 5.1.1 XML文档结构 5.1.1 XML结构说明 5.1.1 XML文档元素 5.1.2 XML文档语法规范 ...
- Java高级程序设计笔记 • 【第3章 多线程(二)】
全部章节 >>>> 本章目录 3.1 同步代码块 3.1 线程安全 3.1.1 模拟银行取款 3.1.2 同步代码块的使用 3.1.3 实践练习 3.2 同步方法 3.2. ...
- Java高级程序设计笔记 • 【第2章 多线程(一)】
全部章节 >>>> 本章目录 2.1 线程的概述 2.1.1 进程 2.1.2 多线程优势 2.1.3 Thread 类 2.1.4 实践练习 2.2 Runnable接口 ...
- Javascript高级程序设计笔记 <第五章> 引用类型
一.object类型 创建object实例的方式有两种: //第一种使用new操作符跟构造函数 var person= new Object(); person.name="小王" ...
随机推荐
- 【swift】用Xib实现自定义警告框(Alert)(安卓叫法:Dialog对话框)
在写这篇博客前,先感谢两篇博客 [如何自定义的思路]:https://www.cnblogs.com/apprendre-10-28/p/10507794.html [如何绑定Xib并且使用]:htt ...
- 转 序列化Serializable和Parcelable的区别详解
什么是序列化,为什么要进行序列化 答:对象要进行传输(如:activity 与activity间 ,网络间 进程间等等).存储到本地就必须进行序列化 . 这种可传输的状态就是序列化. 怎么序列化??两 ...
- Dubbo服务调用超时
服务降级的发生,其实是由于消费者调用服务超时引起的,即从发出调用请求到获取到提供者的响应结果这个时间超出了设定的时限.默认服务调用超时时限为1秒.可以在消费者端与提供者端设置超时时限. 一.创建提供者 ...
- Python 3 字典(Dictionary)
字典是另一种可变容器模型,且可存储任意类型对象. 字典的每个键值 key=>value 对用冒号 : 分割,每个键值对之间用逗号 , 分割,整个字典包括在花括号 {} 中 ,格式如下所示: d ...
- python爬取实习僧招聘信息字体反爬
参考博客:http://www.cnblogs.com/eastonliu/p/9925652.html 实习僧招聘的网站采用了字体反爬,在页面上显示正常,查看源码关键信息乱码,如下图所示: 查看网页 ...
- centos部署配置gogs代码仓库
目录 一.简介 二.部署 三.网页配置 一.简介 Gogs的目标是打造一个最简单.最快速和最轻松的方式搭建自助Git服务.使用Go语言开发使得Gogs能够通过独立的二进制分发,并且支持Go语言支持的 ...
- 由一次 UPDATE 过慢 SQL 优化而总结出的经验
最近,线上的 ETL 数据归档 SQL 发生了点问题,有一个 UPDATE SQL 跑了两天还没跑出来: update t_order_record set archive_id = '420a7fe ...
- LuoguP7379 [COCI2018-2019#6] Lun 题解
Content 判断使一个长度为 \(n\) 的银行卡号码(有一个空缺)合法,空缺里面填入的最小数字. 数据范围:\(n\in[1,100]\). Solution 由于只有一个空缺,因此我们可以考虑 ...
- .NET Core基础篇之:白话管道中间件
在.Net Core中,管道往往伴随着请求一起出现.客户端发起Http请求,服务端去响应这个请求,之间的过程都在管道内进行. 举一个生活中比较常见的例子:旅游景区. 我们都知道,有些景区大门离景区很远 ...
- npm 包发布,自己本机发布,前端内部发布,全网发布
第一步,安装 sinopia npm install -g sinopia 开启终端一: 第二步,启动 sinopia -l 127.0.0.1:4873 开启终端二: cd 到某个指定仓库 mkdi ...