目录
一、网络的相关概念
1.网络通信
2.网络
3.ip 地址
4.ipv4 地址分类
5.域名
6.网络通信协议
7.TCP 和 UDP
二、InetAddress类
1.相关方法
2.代码示例如下:
三、Socket
1.基本介绍
四、TCP 网络通信编程
1.基本介绍
2.应用示例:
2.1题目一(字节流)要求如下:
2.1.1服务端代码如下:
2.1.2客户端代码如下:
2.2题目二(字节流)要求如下:
2.2.1服务端代码如下:
2.2.2客户端代码如下:
2.3题目三 (字符流)要求如下:
2.3.1服务端代码如下:
2.3.2客户端代码如下:
2.4题目四(网络上传文件-字节流)要求如下:
2.4.1工具包StreamUtils代码如下:
2.4.2服务端代码如下:
2.4.3客户端代码如下:
五、UDP 网络通信编程[了解]
1.基本介绍
2. 基本流程
3.应用案例
3.1要求如下:
3.2接受端代码如下:
3.3发送端代码如下:
一、网络的相关概念
1.网络通信
- 概念:两台设备之间通过网络实现数据传输
- 网络通信:将数据通过网络从一台设备传输到另一台设备
- java.net包下提供了一系列的类或接口,供程序员使用,完成网络通信
2.网络
- 概念:两台或多台设备通过一定物理设备连接起来构成了网络
- 根据网络的覆盖范围不同,对网络进行分类:
- 局域网:覆盖范围最小,仅仅覆盖一个教室或一个机房
- 城域网:覆盖范围较大,可以覆盖一个城市
- 广域网:覆盖范围最大,可以覆盖全国,甚至全球,万维网是广域网的代
3.ip 地址
- 概念:用于唯一标识网络中的每台计算机 / 主机
- 查看 ip 地址:ipconfig
- ip 地址的表示形式:点分十进制 xx.xx.xx.xx
- 每一个十进制数的范围:0~255
- ip 地址的组成 = 网络地址 + 主机地址,比如:192.168.16.69
- IPv6 是互联网工程任务组设计的用于替代 IPv4 的下一代 IP 协议,其地址数量号称可以为全世界的每一粒沙子编上一个地址 [1] 。
- 由于 IPv4 最大的问题在于网络地址资源有限,严重制约了互联网的应用和发展。IPv6 的使用,不仅能解决网络地址资源数量的问题,而且也解决了多种接入设备连入互联网的障碍
4.ipv4 地址分类
IPv4 地址是 32 位二进制数,通常以点分十进制表示(如 192.168.1.1)。传统分类基于第一个八位组的前缀,分为A、B、C、D、E 五类,其中 A、B、C 类为常用单播地址,D 类为组播,E 类保留。以下是详细分类:
5.域名
- www.baidu.com
- 好处:为了方便记忆,解决记 ip 的困难
- 概念:将 ip 地址映射成域名,这里怎么映射上,HTTP 协议
・端口号
- 概念:用于标识计算机上某个特定的网络程序
- 表示形式:以整数形式,端口范围 0~65535 [2 个字节表示端口 0~2^16-1]
- 0~1024 已经被占用,比如 ssh 22,ftp 21,smtp 25,http 80
- 常见的网络程序端口号:
• tomcat :8080
• mysql:3306
• oracle:1521
• sqlserver:1433
6.网络通信协议
协议 (tcp/ip)
TCP/IP(Transmission Control Protocol/Internet Protocol)的简写,中文译名为传输控制协议 / 因特网互联协议,又叫网络通讯协议,这个协议是 Internet 最基本的协议、Internet 国际互联网络的基础,简单地说,就是由网络层的 IP 协议和传输层的 TCP 协议组成的。[示意图如下:]
7.TCP 和 UDP
- TCP 协议:传输控制协议
- 使用 TCP 协议前,须先建立 TCP 连接,形成传输数据通道
- 传输前,采用 “三次握手” 方式,是可靠的
- TCP 协议进行通信的两个应用进程:客户端、服务端
- 在连接中可进行大数据量的传输
- 传输完毕,需释放已建立的连接,效率低
- UDP 协议:用户数据协议
- 将数据、源、目的封装成数据包,不需要建立连接
- 每个数据报的大小限制在 64K 内,不适合传输大量数据
- 因无需连接,故是不可靠的
- 发送数据结束时无需释放资源 (因为不是面向连接的),速度快
- 举例:厕所通知;发短信
二、InetAddress类
1.相关方法
- 获取本机 InetAddress 对象 getLocalHost
- 根据指定主机名 / 域名获取 ip 地址对象 getByName
- 获取 InetAddress 对象的主机名 getHostName
- 获取 InetAddress 对象的地址 getHostAddress
2.代码示例如下:
import java.net.InetAddress;
import java.net.UnknownHostException;public class API001 {public static void main(String[] args) throws UnknownHostException {//1.获取本机InetAddress对象getLocalHostInetAddress localHost=InetAddress.getLocalHost(); //LAPTOP-BC9N4EFF/113.54.254.61System.out.println(localHost);//2.根据指定主机名/域名获取ip地址对象getByNameInetAddress host2=InetAddress.getByName("LAPTOP-BC9N4EFF");System.out.println(host2);//3.根据域名返回InetAddress对象,比如:"www.baidu.com"InetAddress host3=InetAddress.getByName("www.baidu.com");System.out.println(host3);//4.通过InetAddress对象,获取对应的地址String hostAddress=host3.getHostAddress();//IPSystem.out.println(hostAddress);//5.通过InetAddress对象,获取对应的主机名/或者的域名String host3Name=host3.getHostName();System.out.println(host3Name);}
}
三、Socket
1.基本介绍
- 套接字 (Socket) 开发网络应用程序被广泛采用,以至于成为事实上的标准。
- 通信的两端都要有 Socket,是两台机器间通信的端点
- 网络通信其实就是 Socket 间的通信。
- Socket 允许程序把网络连接当成一个流,数据在两个 Socket 间通过 IO 传输。
- 一般主动发起通信的应用程序属客户端,等待通信请求的为服务端
四、TCP 网络通信编程
1.基本介绍
- 基于客户端 — 服务端的网络通信
- 底层使用的是 TCP/IP 协议
- 应用场景举例:客户端发送数据,服务端接受并显示控制台
- 基于 Socket 的 TCP 编程
2.应用示例:
2.1题目一(字节流)要求如下:
- 编写一个服务器端,和一个客户端
- 服务器端在 9999 端口监听
- 客户端连接到服务器端,发送 "hello, server",然后退出
- 服务器端接收到 客户端发送的 信息,输出,并退出
创建2个Java文件,并先运行服务端代码(运行后不要关闭),在运行客户端代码。(如果条件允许,最好在两台电脑进行)。
2.1.1服务端代码如下:
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class SocketTCP01Server01 {public static void main(String[] args) throws IOException {//思路//1.在本机的9999端口监听,等待连接//细节:要求在本机没有其它服务在监听9999//细节:这个ServerSocket可以通过accept()返回多个Socket[多个客户端连接服务器的并发]ServerSocket serverSocket=new ServerSocket(9999);System.out.println("服务端,在 9999 端口监听,等待连接..");//2. 当没有客户端连接9999端口时,程序会 阻塞, 等待连接// 如果有客户端连接,则会返回Socket对象,程序继续Socket socket = serverSocket.accept();System.out.println("服务端 socket =" + socket.getClass());//3. 通过socket.getInputStream() 读取客户端写入到数据通道的数据, 显示InputStream inputStream = socket.getInputStream();//4. IO 读取byte[] buf = new byte[1024];int readLen = 0;while ((readLen = inputStream.read(buf)) !=-1) {System.out.println(new String(buf, 0, readLen));//根据读取到的实际长度,显示内容.}//5.关闭流和socketinputStream.close();socket.close();serverSocket.close();//关闭}
}
2.1.2客户端代码如下:
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;//客户端,发送 "hello,server" 给服务端
public class SocketTCP01Client01 {public static void main(String[] args) throws IOException {//思路//1. 连接服务端 (ip, 端口)//解读: 连接本机的 9999端口, 如果连接成功,返回Socket对象Socket socket = new Socket(InetAddress.getLocalHost(), 9999);//这里使用的是本机,如果是远程服务器改为对应的IP或域名System.out.println("客户端 socket 返回=" + socket.getClass());//2. 连接上后,生成Socket, 通过socket.getOutputStream()//得到 和 socket对象关联的输出流对象OutputStream outputStream = socket.getOutputStream();//3. 通过输出流,写入数据到 数据通道outputStream.write("hello, server".getBytes());//4. 关闭流对象和socket, 必须关闭outputStream.close();socket.close();System.out.println("客户端退出.....");}
}
2.2题目二(字节流)要求如下:
- 编写一个服务端,和一个客户端
- 服务器端在 9999 端口监听
- 客户端连接到服务端,发送 "hello, server", 并接收服务器端回发的 "hello,client", 再退出
- 服务器端接收到客户端发送的信息,输出,并发送 "hello, client", 再退出
创建2个Java文件,并先运行服务端代码(运行后不要关闭),在运行客户端代码。(如果条件允许,最好在两台电脑进行)。
注意:相比于上个案例,需要设置结束标记,就类似于对讲机中的完毕,告诉别人我说完了
2.2.1服务端代码如下:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;public class SocketTCP01Server02 {public static void main(String[] args) throws IOException {//1.在本机的9999端口监听,等待连接//细节:要求在本机没有其它服务在监听9999//细节:这个ServerSocket可以通过accept()返回多个Socket[多个客户端连接服务器的并发]ServerSocket serverSocket=new ServerSocket(9999);System.out.println("服务端,在 9999 端口监听,等待连接..");//2. 当没有客户端连接9999端口时,程序会 阻塞, 等待连接// 如果有客户端连接,则会返回Socket对象,程序继续Socket socket = serverSocket.accept();System.out.println("服务端 socket =" + socket.getClass());//3. 通过socket.getInputStream() 读取客户端写入到数据通道的数据, 显示InputStream inputStream = socket.getInputStream();//4. IO 读取byte[] buf = new byte[1024];int readLen = 0;while ((readLen = inputStream.read(buf)) !=-1) {System.out.println(new String(buf, 0, readLen));//根据读取到的实际长度,显示内容.}System.out.println("======================源代码增加处===========================");OutputStream outputStream = socket.getOutputStream();//5. 通过输出流,写入数据到 数据通道outputStream.write("hello, client".getBytes());///设置结束标记socket.shutdownOutput();//5.关闭流和socketoutputStream.close();inputStream.close();socket.close();serverSocket.close();//关闭}
}
2.2.2客户端代码如下:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;public class SocketTCP01Client02 {public static void main(String[] args) throws IOException {//1. 连接服务端 (ip, 端口)//解读: 连接本机的 9999端口, 如果连接成功,返回Socket对象Socket socket = new Socket(InetAddress.getLocalHost(), 9999);//这里使用的是本机,如果是远程服务器改为对应的IP或域名System.out.println("客户端 socket 返回=" + socket.getClass());//2. 连接上后,生成Socket, 通过socket.getOutputStream()//得到 和 socket对象关联的输出流对象OutputStream outputStream = socket.getOutputStream();//3. 通过输出流,写入数据到 数据通道outputStream.write("hello, server".getBytes());System.out.println("======================源代码增加处===========================");设置结束标记socket.shutdownOutput();InputStream inputStream = socket.getInputStream();//4. IO 读取byte[] buf = new byte[1024];int readLen = 0;while ((readLen = inputStream.read(buf)) !=-1) {System.out.println(new String(buf, 0, readLen));//根据读取到的实际长度,显示内容.}inputStream.close();outputStream.close();socket.close();}
}
2.3题目三 (字符流)要求如下:
- 编写一个服务端,和一个客户端
- 服务端在 9999 端口监听
- 客户端连接到服务端,发送 "hello, server", 并接收服务端回发的 "hello,client", 再退出
- 服务端接收到客户端发送的信息,输出,并发送 "hello, client", 再退出
提示:可以直接在上一个案例修改即可
2.3.1服务端代码如下:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;public class SocketTCP01Server03 {public static void main(String[] args) throws IOException {//1.在本机的9999端口监听,等待连接//细节:要求在本机没有其它服务在监听9999//细节:这个ServerSocket可以通过accept()返回多个Socket[多个客户端连接服务器的并发]ServerSocket serverSocket=new ServerSocket(9999);System.out.println("服务端,在 9999 端口监听,等待连接..");//2. 当没有客户端连接9999端口时,程序会 阻塞, 等待连接// 如果有客户端连接,则会返回Socket对象,程序继续Socket socket = serverSocket.accept();System.out.println("服务端 socket =" + socket.getClass());//3. 通过socket.getInputStream() 读取客户端写入到数据通道的数据, 显示InputStream inputStream = socket.getInputStream();//将字节流转换成字符流BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));String str = bufferedReader.readLine();System.out.println(str);OutputStream outputStream = socket.getOutputStream();//字节流转换成字符流BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));bufferedWriter.write("hello, client 字符流");bufferedWriter.newLine();//插入一个换行符,表示写入的内容结束, 注意,要求对方使用readLine()!!!!bufferedWriter.flush(); //如果使用的字符流,需要手动刷新,否则数据不会写入数据通道//5.关闭流和socketbufferedWriter.close();bufferedReader.close();socket.close();serverSocket.close();//关闭}
}
2.3.2客户端代码如下:
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;public class SocketTCP01Client03 {public static void main(String[] args) throws IOException {//1. 连接服务端 (ip, 端口)//解读: 连接本机的 9999端口, 如果连接成功,返回Socket对象Socket socket = new Socket(InetAddress.getLocalHost(), 9999);//这里使用的是本机,如果是远程服务器改为对应的IP或域名System.out.println("客户端 socket 返回=" + socket.getClass());//2. 连接上后,生成Socket, 通过socket.getOutputStream()//得到 和 socket对象关联的输出流对象OutputStream outputStream = socket.getOutputStream();//字节流转换成字符流BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));bufferedWriter.write("hello server 字符流");bufferedWriter.newLine();//插入一个换行符,表示写入的内容结束, 注意,要求对方使用readLine()!!!!bufferedWriter.flush(); //如果使用的字符流,需要手动刷新,否则数据不会写入数据通道无上一个案例的结束标记 InputStream inputStream = socket.getInputStream();//将字节流转换成字符流BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));String str = bufferedReader.readLine();System.out.println(str);bufferedReader.close();bufferedWriter.close();socket.close();}
}
2.4题目四(网络上传文件-字节流)要求如下:
- 编写一个服务端,和一个客户端
- 服务器端在 8888 端口监听
- 客户端连接到服务端,发送一张图片 e:\qie.png
- 服务器端接收到客户端发送的图片,保存到 src 下,发送 “收到图片” 再退出
- 客户端接收到服务端发送的 “收到图片”,再退出
- 该程序要求使用 StreamUtils.java,我们直接使用
2.4.1工具包StreamUtils代码如下:
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;/*** 此类用于演示关于流的读写方法**/
public class StreamUtils {/*** 功能:将输入流转换成byte[], 即可以把文件的内容读入到byte[]* @param is* @return* @throws Exception*/public static byte[] streamToByteArray(InputStream is) throws Exception{ByteArrayOutputStream bos = new ByteArrayOutputStream();//创建输出流对象byte[] b = new byte[1024];//字节数组int len;while((len=is.read(b))!=-1){//循环读取bos.write(b, 0, len);//把读取到的数据,写入bos }byte[] array = bos.toByteArray();//然后将bos 转成字节数组bos.close();return array;}/*** 功能:将InputStream转换成String* @param is* @return* @throws Exception*/public static String streamToString(InputStream is) throws Exception{BufferedReader reader = new BufferedReader(new InputStreamReader(is));StringBuilder builder= new StringBuilder();String line;while((line=reader.readLine())!=null){builder.append(line+"\r\n");}return builder.toString();}}
2.4.2服务端代码如下:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;//文件上传的服务端
public class TCPFileUploadServer001 {public static void main(String[] args) throws Exception {//1.服务端在本机监听8888ServerSocket serverSocket = new ServerSocket(8888);System.out.println("服务端在8888端口监听....");//2.等待连接Socket socket=serverSocket.accept();//3. 读取客户端发送的数据//通过Socket 得到输入流BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());byte[] bytes = StreamUtils.streamToByteArray(bis);//4. 将得到 bytes 数组,写入到指定的路径,就得到一个文件了String destFilePath = "D:\\IDEA\\project\\chapter21\\Java002.png";BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFilePath));bos.write(bytes);bos.close();// 向客户端回复 "收到图片"// 通过socket 获取到输出流(字符)BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));writer.write("收到图片");writer.flush();//把内容刷新到数据通道socket.shutdownOutput();//设置写入结束标记//关闭其他资源//writer.close();bis.close();socket.close();serverSocket.close();}
}
2.4.3客户端代码如下:
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;//文件上传的客户端
public class TCPFileUploadClient001 {public static void main(String[] args) throws Exception {//客户端连接服务端 8888,得到Socket对象Socket socket = new Socket(InetAddress.getLocalHost(), 8888);//创建读取磁盘文件的输入流String filePath = "D:\\IDEA\\project\\chapter21\\Java.png";//String filePath = "e:\\abc.mp4";BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));//bytes 就是 filePath 对应的字节数组byte[] bytes = StreamUtils.streamToByteArray(bis);//通过socket 获取到输出流, 将bytes数据发送给服务端BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());bos.write(bytes);//将文件对应的字节数组的内容,写入到数据通道bis.close();socket.shutdownOutput();//设置写入数据的结束标记//=====接收从服务端回复的消息=====InputStream inputStream = socket.getInputStream();//使用StreamUtils 的方法,直接将 inputStream 读取到的内容 转成字符串String s = StreamUtils.streamToString(inputStream);System.out.println(s);//关闭相关的流inputStream.close();bos.close();socket.close();}
}
五、UDP 网络通信编程[了解]
1.基本介绍
- 类 DatagramSocket 和 DatagramPacket [数据包 / 数据报] 实现了基于 UDP 协议网络程序。
- UDP 数据报通过数据报套接字 DatagramSocket 发送和接收,系统不保证 UDP 数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。
- DatagramPacket 对象封装了 UDP 数据报,在数据报中包含了发送端的 IP 地址和端口号以及接收端的 IP 地址和端口号。
- UDP 协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接收方的连接
2. 基本流程
- 核心的两个类 / 对象 DatagramSocket 与 DatagramPacket
- 建立发送端,接收端 (没有服务端和客户端概念)
- 发送数据前,建立数据包 / 报 DatagramPacket 对象
- 调用 DatagramSocket 的发送、接收方法
- 关闭 DatagramSocket
3.应用案例
3.1要求如下:
- 编写一个接收端 A, 和一个发送端 B
- 接收端 A 在 9999 端口等待接收数据 (receive)
- 发送端 B 向接收端 A 发送 数据 "hello,明天吃火锅~"
- 接收端 A 接收到 发送端 B 发送的数据, 回复 "好的,明天见", 再退出
- 发送端接收 回复的数据,再退出
3.2接受端代码如下:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;public class UDPReceiverA {public static void main(String[] args) throws IOException {//1. 创建一个 DatagramSocket 对象,准备在9999接收数据DatagramSocket socket = new DatagramSocket(9999);//UDP 协议数据包最大 64k//2. 构建一个 DatagramPacket 对象,准备接收数据byte[] buf = new byte[1024];// 在前面讲解UDP 协议时,老师说过一个数据包最大 64kDatagramPacket packet = new DatagramPacket(buf, buf.length);//3. 调用 接收方法, 将通过网络传输的 DatagramPacket 对象// 填充到 packet对象// 当有数据包发送到 本机的9999端口时,就会接收到数据//如果没有数据包发送到 本机的9999端口, 就会阻塞等待.System.out.println("接收端 A 等待接收数据..");socket.receive(packet);//4. 可以把packet 进行拆包,取出数据,并显示.int length = packet.getLength();//实际接收到的数据字节长度byte[] data = packet.getData();//接收到数据String s = new String(data, 0, length);System.out.println(s);///==========回复代码====================//2. 将需要发送的数据,封装到 DatagramPacket对象byte[] data1 = "好的,明天见".getBytes();//说明: 封装的 DatagramPacket 对象 data 内容字节数组 ,data.length , 主机(IP), 端口DatagramPacket packet1 = new DatagramPacket(data1, data1.length, InetAddress.getByName("113.54.254.61"), 9998);socket.send(packet1);socket.close();System.out.println("A端退出");}
}
3.3发送端代码如下:
import java.io.IOException;
import java.net.*;public class UDPSenderB {public static void main(String[] args) throws IOException {//1.创建 DatagramSocket 对象,准备在9998端口 接收数据DatagramSocket socket = new DatagramSocket(9998); //端口不一样是要理解没有连接的概念,每次通过端口来接收数据//2. 将需要发送的数据,封装到 DatagramPacket对象byte[] data = "hello 明天吃火锅~".getBytes();//说明: 封装的 DatagramPacket 对象 data 内容字节数组 ,data.length , 主机(IP), 端口DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getByName("113.54.254.61"), 9999);socket.send(packet);==============收到回复======================//UDP 协议数据包最大 64k//2. 构建一个 DatagramPacket 对象,准备接收数据byte[] buf = new byte[1024];// 在前面讲解UDP 协议时,老师说过一个数据包最大 64kDatagramPacket packet1 = new DatagramPacket(buf, buf.length);//3. 调用 接收方法, 将通过网络传输的 DatagramPacket 对象// 填充到 packet对象// 当有数据包发送到 本机的9999端口时,就会接收到数据//如果没有数据包发送到 本机的9999端口, 就会阻塞等待.System.out.println("接收端 B等待回复..");socket.receive(packet1);//4. 可以把packet 进行拆包,取出数据,并显示.int length = packet1.getLength();//实际接收到的数据字节长度byte[] data1 = packet1.getData();//接收到数据String s = new String(data1, 0, length);System.out.println(s);//关闭资源socket.close();System.out.println("B端退出");}
}