网络编程
16.1 网络概述
16.1.1 概念
由点和线构成,表示诸多对象间的相互联系。
16.1.2 计算机网络
为实现资源共享和信息传递,通过通信线路连接起来的若干主机(Host)。
常见计算机网络:
- 互联网:(Internet)点与点相连。
- 万维网:(WWW – World Wide Web)端与端相连。
- 物联网:( IoT - Internet of things) 物与物相连。
- 网络编程:让计算机与计算机之间建立连接、进行通信。
16.1.3 网络模型
16.1.3.1 OSI参考模型
OSI(Open System Interconnect),即开放式系统互联。
每层功能:
- 第七层:应用层负责文件访问和管理、可靠运输服务、远程操作服务。(HTTP、FTP、SMTP)。
- 第六层:表示层负责定义转换数据格式及加密,允许选择以二进制或ASCII格式传输。
- 第五层:会话层负责使应用建立和维持会话,使通信在失效时继续恢复通信。(断点续传)。
- 第四层:传输层负责是否选择差错恢复协议、数据流重用、错误顺序重排。(TCP、UDP)。
- 第三层:网络层负责定义了能够标识所有网络节点的逻辑地址。(IP地址)。
- 第二层:链路层在物理层上,通过规程或协议(差错控制)来控制传输数据的正确性。(MAC)。
- 第一层:物理层为设备之间的数据通信提供传输信号和物理介质。(双绞线、光导纤维)。
16.1.3.2 TCP/IP模型
TCP/IP模型是因特网使用的参考模型,基于TCP/IP的参考模型将协议分成四个层次。
该模型中最重要的两个协议是TCP和IP协议。
每层功能:
- 第四层:应用层负责传送各种最终形态的数据,是直接与用户打交道的层,典型协议是HTTP、FTP等。
- 第三层:传输层负责传送文本数据,主要协议是TCP、UDP协议。
- 第二层:网络层负责分配地址和传送二进制数据,主要协议是IP协议。
- 第一层:接口层负责建立电路连接,是整个网络的物理基础,典型的协议包括以太网、ADSL等等。
16.1.4 网络编程总结
计算机网络:为实现资源共享、信息传递通过传出介质将若干台主机连接到一起的一个网络
计算机网络模型:
OSI
应用层 主要指的是程序 表示层 讲数据加密或者解密成二进制的数据 会话层 保持主机之间的连接 传输层 通过网络协议传输数据(TCP协议、UDP协议) 网络层 分配IP地址(IP地址) 网络数据链路层 保证准确性(MAC地址物理地址) 物理层 进行数据传输 TCP/IP
应用层 传输层 网络层 物理层 网络编程需要什么【重点 】
- 通信协议(TCP\UDP\HTTP)
- IP地址
- 端口号
网络编程三要素:协议、地址、端口号
16.2 常见协议
16.2.1 IP协议概述
IP协议:Internet Protocol Address 互联网协议地址/网际协议地址:
- 分配给互联网设备的数字标签(唯一标识)。
IP地址版本:
- IPV4:4字节32位整数,并分成4段8位的二进制数,每8位之间用圆点隔开,每8位整数可以转换为一个0~255的十进制整数。
格式:D.D.D.D 例如:255.255.255.255- IPV6:16字节128位整数,并分成8段十六进制数,每16位之间用圆点隔开,每16位整数可以转换为一个0~65535的十进制数。
格式:X.X.X.X.X.X.X.X 例如:FFFF.FFFF.FFFF.FFFF.FFFF.FFFF.FFFF.FFFF
IP地址分类:
A类地址 大型网络:网络地址.主机地址.主机地址.主机地址
B类地址 中型网络:网络地址.网络地址.主机地址.主机地址
C类地址 个人网络:网络地址.网络地址.网络地址.主机地址
- A类:政府机构,1.0.0.1 ~ 126.255.255.254
- B类:中型企业,128.0.0.1 ~ 191.255.255.254
- C类:个人用户,192.0.0.1 ~ 223.255.255.254
- D类:用于组播,224.0.0.1 ~ 239.255.255.254
- E类:用于实验,240.0.0.1 ~ 255.255.255.254
- 回环地址:127.0.0.1,指本机,一般用于测试使用。
查看IP命令:ipconfig
测试IP命令:ping D.D.D.D
/**
* 网络三要素之ip地址
* 1、概念
* a、什么是IP地址 (了解)
* 分配给每一台主机的唯一数字标识
*
* b、ipv4和ipv6 (了解)
* ipv4:4个字节32位组成,每一段由8位组成。使用0~255之间的数字表示(应用)
* ipv6:16个字节128位组成,每一段由32位组成。使用0~65535之间的数字表示
* c、ip地址的分类
A类地址 大型网络:网络地址.主机地址.主机地址.主机地址
B类地址 中型网络:网络地址.网络地址.主机地址.主机地址
C类地址 个人网络:网络地址.网络地址.网络地址.主机地址
* d、回路地址(自己与自己通信IP地址) (重要)
* 域名
* 127.0.0.1 localhost
*
* DNS域名解析器:将域名解析成ip地址。一个ip地址可以对应多个域名 一个域名职能对应一个ip地址
* 默认情况下:DNS解析回去找到C:\Windows\System32\drivers\etc\hosts文件去查找对应的域名解析,
* 如果找不到会去DNS服务器中取查找
* 常见的DNS域名器:114.114.114.114 8.8.8.8
*
* e、ip相关的命令 (重要)
* ipconfig(查看本机的ip地址信息) ifconfig(Linux操作系统,查看本机的ip地址信息)
* ping命令 (检查是否连接上了目标主机)
*
* https://www.baidu.com:80/
*
* 2、应用
* java是面向对象的编程语言,在java使用InetAddress类表示ip地址信息
*/
16.2.2 InetAddress类
概念:表示互联网协议(IP)地址对象,封装了与该IP地址相关的所有信息,并提供获取信息的常用方法。
常见方法:
方法名 | 描述 |
---|---|
public static InetAddress getLocalHost() | 获得本地主机地址对象 |
public static InetAddress getByName(String host) | 根据主机名称获得地址对象 |
public static InetAddress[] getAllByName(String host) | 获得所有相关地址对象 |
public String getHostAddress() | 获取IP地址字符串 |
public String getHostName() | 获得IP地址主机名 |
public class TestIP {
/**
*
* //方式一:获取本机的InetAddress对象
* //通过本地的ip地址信息获取InetAddress对象
* InetAddress ia = InetAddress.getLocalHost();
* //InetAddress对象的常用方法
* //获取主机名(域名)
* String hostName = ia.getHostName();
* System.out.println(hostName);
* //获取ip地址
* String hostAddress = ia.getHostAddress();
* System.out.println(hostAddress);
* //方式二:根据指定的主机名获取InetAddress对象
* InetAddress ia = InetAddress.getByName("www.baidu.com");
* //InetAddress对象的常用方法
* String hostName = ia.getHostName();
* System.out.println(hostName);
* String hostAddress = ia.getHostAddress();
* System.out.println(hostAddress);
* //方式三:根据指定的ip地址获取InetAddress对象
* InetAddress ia = InetAddress.getByName("14.215.177.38");
* System.out.println(ia.getHostName());
* System.out.println(ia.getHostAddress());
*/
public static void main(String[] args) throws UnknownHostException {
//创建InetAddress对象
//方式四:根据指定的主机名获取所有的InetAddress
InetAddress[] ias = InetAddress.getAllByName("www.baidu.com");
//使用lambda表达式遍历
/*Arrays.stream(ias).forEach(ia ->{
System.out.println(ia.getHostAddress());
System.out.println(ia.getHostName());
});*/
//使用foreach循环遍历
for (InetAddress ia : ias) {
System.out.println(ia.getHostAddress());
System.out.println(ia.getHostName());
}
}
}
16.3 端口号
16.3.1 端口号概述
端口号:在通信实体上进行网络通讯的程序的唯一标识。
端口分类(端口的范围:0~65535之间):
- 公认端口:0~1023
- 注册端口:1024~49151
- 动态或私有端口:49152~65535 (指的是程序没有设置端口号系统默认随机分配的端口号)
常用端口号:
- MySql:3306
- Oracle:1521
- redis:6379
- Tomcat:8080
- SMTP:25
- Web服务器:80
- FTP服务器:21
注意:以后自己编写的程序的端口号最好设置在1024~65535之间即可
16.4 通信协议
16.4.1 通信协议概述
-
概念:
TCP:传输控制协议
-
特点:面向连接、安全可靠、效率低、基于字节流进行通信、数据大小无限制。
-
建立连接三次握手、断开连接四次挥手
-
通俗解释:打电话
UDP:数据报协议
-
特点:面向无连接、不安全、效率高、基于数据报包的形式通信、数据包大概在64kb
在java中使用Socket类来进行网络编程
Socket:套接字、指的是网络间的一个通信设备
-
-
基于TCP协议进行通信
-
案例:客户端发送消息,服务端进行接收
-
案例: 客户端通过Scanner录入数据发送消息。服务端进行使用多线程接收
-
案例:客户端上传图片到服务端,服务端发送数据到客户端
-
-
基于UDP协议进行通信
-
案例:发送端发送消息,接收端进行接收
-
案例:使用udp协议给飞秋发送数据
-
16.5 基于TCP协议通信
Socket编程:
- Socket(套接字)是网络中的一个通信节点。
- 分为客户端Socket与服务器ServerSocket。
- 通信要求:IP地址 + 端口号。
开发步骤:
- 建立通信连接(会话):
- 创建ServerSocket,指定端口号。
- 调用accept等待客户端接入。
- 客户端请求服务器:
- 创建Socket,指定服务器IP + 端口号。
- 使用输出流,发送请求数据给服务器。
- 使用输入流,接收响应数据到客户端(等待)
- 服务器响应客户端。
- 使用输入流,接收请求数据到服务器(等待)。
- 使用输出流,发送响应数据给客户端。
16.5.1 案例1
通过客户端向服务端发送信息
/**
* 客户端程序
*/
public class Client {
public static void main(String[] args) throws IOException {
//1、创建客户端Socket对象
Socket socket = new Socket("127.0.0.1",6666);
//2、通过Socket对象获取输出流对象
OutputStream out = socket.getOutputStream();
//3、通过输出流对象写出数据
//将字符串转换成字节数组 字符串.getBytes("字符集");
out.write("hello,我是客户端!!!".getBytes());
//4、关闭资源
out.close();
socket.close();
}
}
/**
* 服务端程序
*/
public class Server {
public static void main(String[] args) throws IOException {
//1、创建服务端端Socket对象
ServerSocket ss = new ServerSocket(6666);
//2、通过ServerSocket对象获取Socket对象
//ss.accept()阻塞式方法。直到有客户端与之建立连接才会继续向下执行
Socket socket = ss.accept();
//3、通过Socket对象获取输入流对象
InputStream in = socket.getInputStream();
//4、通过输入流对象读出数据
int len; //表示读取到的字节的长度
byte[] buf = new byte[1024]; // 表示缓冲区
while((len = in.read(buf)) != -1){
//将字节数组转转成字符串
String str = new String(buf,0,len);
System.out.println(str);
}
//5、关闭资源
in.close();
socket.close();
ss.close();
}
}
16.5.2 案例2
基于多线程实现客户端服务端通信
/**
* 客户端程序
*/
public class Client {
public static void main(String[] args) throws IOException {
//创建Scanner对象
Scanner sc = new Scanner(System.in);
while(true){
//1、创建客户端Socket对象
Socket socket = new Socket("localhost",6677);
//2、获取输出流对象
OutputStream out = socket.getOutputStream();
//3、通过输出流对象写出数据
//获取输入的内容 next():用于获取输入的字符串(以空格为标记进行获取) nextLine():用于获取输入的字符串(以回车为标记进行获取)
String words = sc.next();
if("886".equals(words)||"over".equals(words)){
//4、释放资源
out.close();
socket.close();
break;
}
out.write(words.getBytes());
//4、释放资源
out.close();
socket.close();
}
}
}
/**
* 服务端程序
*/
public class Server {
public static void main(String[] args) throws IOException {
//1、创建服务端Socket对象
ServerSocket ss = new ServerSocket(6677);
System.out.println("服务端已开启等待客户端连接....");
while(true){
//2、获取Socket对象
Socket socket = ss.accept();
//获取客户端发送的信息
String ip = socket.getInetAddress().getHostAddress();
//创建线程来处理客户端的请求
new Thread(new Runnable() {
@Override
public void run() {
try {
//3、通过Socket对象获取输入流
InputStream in = socket.getInputStream();
//4、通过输入流读取内容
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String readLine = br.readLine();
System.out.println(ip+":"+readLine);
//5、释放资源
in.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
}
16.5.3 案例3
实现客户端文件上传功能,并从服务端向客户端发送数据
/**
* 客户端程序
*/
public class Client {
//客户端向服务端发送图片
public static void main(String[] args) throws IOException {
//1、创建Socket对象
Socket socket = new Socket("192.168.73.210",8899);
//2、通过Socket获取输出流对象
OutputStream out = socket.getOutputStream();
//思路:从本地将图片读取出来,然后通过socket输出流立马写出去
FileInputStream fis = new FileInputStream("d:\\41.jpg");
byte[] buf = new byte[1024];
int len;
while((len = fis.read(buf))!=-1){
//3、通过输出流写出数据
out.write(buf,0,len);
}
//告知服务器这边已经写完了
socket.shutdownOutput();
//从服务端接收到返回信息
InputStream in = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
System.out.println(br.readLine());
//4、释放资源
in.close();
fis.close();
out.close();
socket.close();
}
}
/**
* 服务端程序
*/
public class Server {
public static void main(String[] args) throws IOException {
//1、创建ServerSocket对象
ServerSocket ss = new ServerSocket(8899);
System.out.println("图片服务器已开启....");
while(true){
//2、获取Socket对象
Socket socket = ss.accept();
//开启线程执行上传图片操作
new Thread(new UploadThread(socket)).start();
}
}
}
class UploadThread implements Runnable{
Socket socket;
public UploadThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
//通过socket对象获取输入流
try {
InputStream in = socket.getInputStream();
//思路:文件上传,读取到图片之后将图片保存在服务器上的upload文件夹中
String newFilename = UUID.randomUUID().toString().replace("-","");
FileOutputStream fos = new FileOutputStream("upload\\"+newFilename+".jpg");
byte[] buf = new byte[1024];
int len ;
while((len = in.read(buf))!=-1){
fos.write(buf,0,len);
}
//获取输出流向客户端发送数据
OutputStream out = socket.getOutputStream();
out.write(("success!!!"+"upload\\"+newFilename+".jpg").getBytes());
//4、关闭资源
out.close();
fos.close();
in.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
16.6 基于UDP协议通信
16.6.1 案例1
发送端发送数据到接收端
public class Send {
public static void main(String[] args) throws Exception {
//1、基于UDP协议创建Socket对象 无需指定端口号ip地址
DatagramSocket ds = new DatagramSocket();
//2、创建数据包对象
byte[] buf = "你好接收端".getBytes();
DatagramPacket dp = new DatagramPacket(buf,buf.length, InetAddress.getByName("192.168.73.210"),9999);
//3、发送数据包
ds.send(dp);
//4、释放资源
ds.close();
}
}
public class Receive {
public static void main(String[] args) throws Exception {
//1、基于UDP协议创建Socket对象
DatagramSocket ds = new DatagramSocket(9999);
//2、创建数据包对象
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
//3、接受数据包 receive阻塞式的方法
ds.receive(dp);
//4、解析数据包的数据
//从数据包中获取数据
byte[] data = dp.getData();
//从数据包中获取InetAddress对象
InetAddress inetAddress = dp.getAddress();
//从数据包中获取端口号
int port = dp.getPort();
//获取数据包的数据字节数长度
int length = dp.getLength();
String str = new String(data,0,length);
System.out.println("ip:"+inetAddress.getHostAddress());
System.out.println("port:"+port);
System.out.println("data:"+str);
//5、释放资源
ds.close();
}
}
16.6.2 案例2
使用UDP协议向飞秋发送数据
public class Send {
public static void main(String[] args) throws Exception {
//分析:只要搞清楚飞秋的数据包的格式
//1:100:主机名:昵称:32:hello,飞秋
//1、创建Socket对象
DatagramSocket ds = new DatagramSocket();
//2、创数据包对象
byte[] buf = "1:100:主机名:昵称:32:hello,飞秋".getBytes("GBK");
DatagramPacket dp = new DatagramPacket(buf,buf.length, InetAddress.getByName("192.168.73.210"),2425);
//3、发送数据包
ds.send(dp);
//4、释放资源
ds.close();
}
}