-
javaSE高级篇3 — 网络编程 — 更新完毕
网络编程基础知识
-
先来思考两个问题( 在这里先不解决 )
- 如何准确的找到一台 或 多台主机?
- 找到之后如何进行通讯?
-
网络编程中的几个要素
- IP 和 端口号
- 网络通讯协议:TCP / UDP
-
最后一句话
- 万物皆对象
1、IP介绍——英文:inetAdress——IP地址
-
作用:标记网络中每台计算机的身份,网络中每台计算机都有一个唯一的身份号码,就和人的身份证一样
- 举个例子:如127.0.0.1——指:本机地址( localhost )
-
IP的表示方法
-
ipv4 / ipv6
- ipv4:由一个4字节32位的整数构成( 如:192.168.100.1 ),每8位用0 ~ 255表示( 即:例子中的每一个数字不超过255 ),它们彼此之间用 " . " 隔开,所以这个ipv4能够表示42亿多个ip地址。但是有30多亿在北美,而亚洲只有4亿多点,而人这么多,所以这种表示方式根本不够用,因此:在2011年的时候这些ip地址就已经用完了——————咋个办?所以弄出了ipv6
-
ipv4 / ipv6
-
-
- ipv6:有一个16字节128位的整数构成( 如:Y.Y.Y.Y.Y.Y.Y.Y ),每段的范围是0 ~ 65535
-
-
IP分类
-
公网( 互联网) 、 私网( 局域网 )————直接看图
-
其中,不想详细了解的话,作为程序员只需要知道两个命令即可——ipconfig 和 ping
- ipconfig:是查看自己的计算机ip地址————即:在dos窗口中输入这个命令回车即可看到
- ping:是查看自己的计算机是否链接上知道ip地址的计算机————即:ping 接要查看的计算机ip地址
-
公网( 互联网) 、 私网( 局域网 )————直接看图
-
在java中怎么玩儿ip?
- 多提一句:java中和网络相关的都在java.net包下
-
-
java中已经封装好了一个类————inetAdress类:这个类没有构造方法,所以不能new对象,直接通过 类名. 调用方法( 方法也不多,就下图中的这几个,而且也没多大用 )
-
// 1、获取ip名字————参数是String host System.out.println( InetAddress.getByName("127.0.0.1") ); System.out.println( InetAddress.getByName("www.baidu.com") ); // 这个没啥好玩的
效果如下:
-
java中已经封装好了一个类————inetAdress类:这个类没有构造方法,所以不能new对象,直接通过 类名. 调用方法( 方法也不多,就下图中的这几个,而且也没多大用 )
2、端口
-
先来思考一个问题
- 一台计算机它是怎么读取数据的?————换句话说:它是怎么知道一个 / 一些数据是哪个软件发过来的?( 接收的时候对数据进行处理嘛 )
-
为了解决上述的问题————端口就来了
- 端口:指的是计算机上一个程序的进程
- 端口的范围: 0 ~ 65535
-
- 不同的应用程序,端口都不一样,这样就可以通过固定的端口进行收发数据了
-
常见的默认端口如下
-
MySQL ————> 3306
Tomcat ————> 8080
HTTP ————> 80
SSH ————> 22 这是linux下的安全传输协议端口
FTP ————> 21
-
多一点了解的话,就看下图
-
-
在java中怎么玩端口?————也是封装好了的,使用一个类InetSocketAddress————也没什么好玩的
3、通信协议——这才是重点
- 协议:就是一种约定嘛,就好比————我们说的普通话
- 网络通信协议:也就是网络之间进行通讯的约定嘛————管速率、传输码率、传输控制............
-
由网络通信协议看出:麻不麻烦?
-
当然麻烦涩,大事化小咯————分层,如下图所示
- 看起来好多啊,但是没事儿,又不是专门搞网络的,所以不需要整那么多,就几个而已
-
当然麻烦涩,大事化小咯————分层,如下图所示
-
1、TCP / UDP协议
- TCP:传输控制层协议( 用户传输协议 )
-
-
-
特点:
- 面向连接式协议:指 应用程序在使用TCP协议之前,必须先建立TCP连接,在传送数据完毕后,必须释放已经建立的TCP连接
- 每一条TCP连接只能有两个端点,即:A和B连接,A就不能再用TCP和其他的连接在一起 ( 点对点连接嘛 )
- TCP可靠,即:通过TCP连接传送的数据,无差错、不丢失、不重复、并且按序到达
- 提供全双工通信:即:TCP允许通信双方( 断开不行啊 )的应用进程在任何时候都能发送数据
-
面向字节流传输:即:传输的数据是字节流,关注点是:字节。什么意思?
- 假如:两个端点之间传输了一句话,但是这句话在TCP里面不是文字,而是这句话的每个字符对应的字节数字,如:a ———> 97
-
特点:
-
-
-
在这里需要了解两个东西:三次握手、四次挥手(四次分手)
-
先看这两个的图
-
三次握手
-
三次握手
-
先看这两个的图
-
在这里需要了解两个东西:三次握手、四次挥手(四次分手)
-
-
-
-
四次挥手( 四次分手 )
-
四次挥手( 四次分手 )
-
-
-
-
-
-
三次握手到底是什么意思?
-
如上图
- A:你瞅啥? ————> 客户端发送连接的请求,服务端对这个请求进行监听
- B:瞅你咋地 ————> 然后服务端回应客户端: 可以 / 不可以 进行传输
- A、B:走,干一架 ————> 最后客户端 进行 / 不进行 数据传输
-
如上图
-
三次握手到底是什么意思?
-
-
-
-
-
-
那四次挥手又到底是个啥子玩意儿?
-
不是备注了一下:四次分手吗,那就用分手来理解一下
- 男:我想跟你分手 ————> 客户端向服务端发送连接的请求
- 女:你要分手?—————> 服务端响应客服端
- 女:你真的要分手??? ————> 服务端询问客户端是否准备链接
- 男:老子确定分手 ————> 服务端 和 客户端建立连接
-
不是备注了一下:四次分手吗,那就用分手来理解一下
-
那四次挥手又到底是个啥子玩意儿?
-
-
-
-
UDP:用户数据报协议
-
特点:
- 面向无连接式协议:即:发送数据之前不需要建立连接
- UDP不可靠(不稳定):即:数据的传输中只是尽最大努力把数据送达,不保证一点不丢失( 如:停电了、断网了 ,哦豁 ~ 数据没穿得过去 )
- 支持一对一、一对多、多对多通信
-
特点:
-
UDP:用户数据报协议
-
-
TCP和UDP的对比
-
TCP( 好比:打电话 )
- 安全、可靠
- 连接稳定( 三次握手、四次挥手 )
- 客户端 和 服务端界限明确
- 缺点:要等传输完成,才能释放连接,效率低
-
TCP( 好比:打电话 )
-
TCP和UDP的对比
-
-
UDP( 好比:发短信、写信 )
- 不稳定、不靠谱
- 客户端 和 服务端界限不明确
- 不管有没有准备好,都可以发给你( 就好比:导弹,想整你的时候,还需要管你准没准备好吗 )
-
-
-
-
漏洞就来了
- 黑别人的时候,发布洪水攻击( 即:疯狂发送东西,看好的还是坏的信息啊 )————最后:直接把别人网络干趴
-
漏洞就来了
-
-
-
2、TCP协议编程———即:Socket编程
-
Socket就相当于是 服务端 和 客户端 之间的那个连接通道
-
Socket就相当于是 服务端 和 客户端 之间的那个连接通道
-
- 服务器端使用ServerSocket套接字 并绑定监听端口
- 服务端 阻塞等待连接
- 客户端使用 Socket 并指定服务端IP 和 端口
-
-
- 服务端
-
-
-
-
-
//1. 服务器端套接字 ServerSocket server = new ServerSocket(8848); //2. 监听客户端连接 Socket socket = server.accept();
-
-
-
-
-
-
客户端
-
//1. 创建客户端套接字 Socket socket = new Socket( "127.0.0.1" , 8848);
-
-
客户端
-
-
-
实操一手儿
-
1、客户端 给 服务端 发送数据
-
package cn.xieGongZi.test; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; // 服务端 public class Server { public static void main(String[] args) { Socket socket = null; BufferedReader br = null; // 1、需要建立一个连接的通道sorket————即:套接字 try { ServerSocket serverSocket = new ServerSocket(9999);// 需要一个端口号————即:这个链接通道的名字是什么 // 这个东西就是底层中封装的3次握手 // 2、有了这个通道之后就可以等着客户端来链接了——————使用accept()方法 System.out.println("正在等待链接:"); socket = serverSocket.accept(); // 等待客户端的链接————客户端和服务端真正建立了连接通道 // 3、如果客户端链接上就可以进行文件的 读 / 写了 // 读取文件————这里是传输的文字,所以直接一行一行的读取,快一点嘛 br = new BufferedReader( new InputStreamReader( socket.getInputStream() ) ); String buffer; while ( ( buffer = br.readLine() ) != null ){ System.out.println("服务端收到了:" + buffer ); } } catch (IOException e) { e.printStackTrace(); }finally { // 最后关闭流管道和网络链接通道————但是Socket 和 流管道 是在try中,这里拿不到,所以:提升作用域————全局变量 // 倒着关闭 if ( socket != null ){ try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } if ( br != null ){ try { br.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
-
package cn.xieGongZi.test; import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStreamWriter; import java.net.Socket; // 客户端 public class Client { public static void main(String[] args) { Socket clientSocket = null; BufferedWriter bw = null; // 1、建立链接通道————需要ip和端口号 try { clientSocket = new Socket("127.0.0.1", 9999); // 2、开始传输文件————建立流管道 bw = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream())); bw.write("不球晓得传输个啥子东西"); } catch (IOException e) { e.printStackTrace(); }finally { // 关闭流管道 和 网络链接通道 if ( bw != null ){ try { bw.close(); } catch (IOException e) { e.printStackTrace(); } } if ( clientSocket != null ){ try { clientSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
-
效果如下:
-
-
-
1、客户端 给 服务端 发送数据
-
实操一手儿
-
-
-
2、多个客户端 给 服务端发送数据
-
package cn.xieGongZi.testManyClientToServer; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; // 服务端————可以让多个客户端来进行链接 public class Server { public static void main(String[] args) { // 1、建立链接通道 try { ServerSocket serverSocket = new ServerSocket(2020); while ( true ){ // 保证服务端能够多开,不然只开启一个准备链接通道,那多个客户端链接只能链接第一个了 // 2、等待客户端来链接 System.out.println("等待连接"); Socket socket = serverSocket.accept(); // 3、但是:如果在这里直接进行数据的读写,那又不行 // 因为:万一第一个链接通道一致没有客户端传输数据过来,那不就堵着了吗 // 所以:开线程————让每一个客户端 和 服务端进行链接之后都去单独的一个线程中进行读写数据 // 开线程 new openThread(socket).start(); } } catch (IOException e) { e.printStackTrace(); } } } // 开线程 class openThread extends Thread{ private Socket socket; public openThread( Socket socket ){ this.socket = socket; } @Override public void run() { // 这个线程里面要干的事情:就是让服务端 和 客户端进行数据读写 // 但是:问题来了 // 怎么能够保证是哪一个连接通道进行读写数据? // 所以:需要把链接通道传进来————组合的方式 // 客户端 和 服务端 的链接通道正式开始进行读写数据 BufferedReader br = null; try { br = new BufferedReader(new InputStreamReader(socket.getInputStream())); String data; while ( ( data = br.readLine() ) != null ){ System.out.println(data); } } catch (IOException e) { e.printStackTrace(); }finally { if ( br != null ){ try { br.close(); } catch (IOException e) { e.printStackTrace(); } } if ( socket != null ){ try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
-
package cn.xieGongZi.testManyClientToServer; import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStreamWriter; import java.net.Socket; // 客户端 public class Client { public static void main(String[] args) { Socket clientSocket = null; BufferedWriter bw = null; // 1、建立链接通道————需要ip和端口号 try { clientSocket = new Socket("127.0.0.1", 2020); // 2、开始传输文件————建立流管道 bw = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream())); bw.write("不球晓得传输个啥子东西"); } catch (IOException e) { e.printStackTrace(); }finally { // 关闭流管道 和 网络链接通道 if ( bw != null ){ try { bw.close(); } catch (IOException e) { e.printStackTrace(); } } if ( clientSocket != null ){ try { clientSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
-
-
2、多个客户端 给 服务端发送数据
-
-
-
-
3、客户端给客户端发送数据( 即:多人聊天 )————注意:直接通过客户端 和 客户端交互是不可以的
-
package cn.xieGongZi.clientToClient; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.List; // 服务端————玩儿客户端 与 客户端进行聊天 public class Server { static List<Socket> socketList= new ArrayList<>(); public static void main(String[] args) { ServerSocket serverSocket = null; // 1、建立通信管道链接 try { serverSocket = new ServerSocket(3030); // 2、等待客户端来链接 System.out.println("正在等待链接:"); Socket acceptSocket = serverSocket.accept(); // 3、如果客户端链接上了,则:进行数据的读写 // 读取客户端的数据————照样的放在这里不好,应该单独让它们去一下线程里做事 // 所以:开线程 new openServerThread(acceptSocket).start(); // 最后搞一件事情————把从客户端接过来的链接通道这个客人给我放到集合中去 Server.socketList.add(acceptSocket); } catch (IOException e) { e.printStackTrace(); }finally { if (serverSocket != null ){ try { serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } } } // 开线程 class openServerThread extends Thread{ // 一样的保证:客户端 与 客户端在一个连接通道中————还是用组合 private Socket socket; public openServerThread( Socket socket ){ this.socket = socket; } // 线程该做的事 @Override public void run() { BufferedReader br = null; // 读取客户端的数据 try { br = new BufferedReader(new InputStreamReader(socket.getInputStream())); String data; while ( ( data = br.readLine() ) != null ){ // 在这里:服务端就接收到了客户端的数据 // 但是:要搞得事情不是把这个数据给打印出来看效果 // 而是:在这里借服务端的手,把客户端传过来的数据 转发 给其他客户端 // 可:问题又来了————服务端只是从客户端哪里接客了,但是接了哪些客,它不知道 // 因此:需要一个东西来记录一下————服务端接了哪些客————集合(因为:具体多少个客户端不知道) // 所以:定义一个全局的集合 // 然后:服务端接一个客户端,那就把这个客户端放到集合中去 // 最后需要搞一件事情涩————就是去集合中找除了自己这个客户端以外的其他客户端(即:另外的Socket通道) // 然后把接收过来的数据 转发 给其他客户端 for (int i = 0; i < Server.socketList.size(); i++) { // 遍历这个集合 Socket checkSocket = Server.socketList.get(i); // 看遍历出来的这个Socket是不是它自己本身————是的话就不转发了 if ( this.socket == checkSocket ) continue; // 否则:就是其他的Socket通道嘛————即:其他的客户端————那就转发数据( 输出数据嘛 ) new PrintWriter( checkSocket.getOutputStream() ).println(data); } } } catch (IOException e) { e.printStackTrace(); }finally { if ( br != null ){ try { br.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
-
package cn.xieGongZi.clientToClient; import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStreamWriter; import java.net.Socket; import java.util.Scanner; // 客服端 public class Client { public static void main(String[] args) { try { Socket clientSocket = new Socket("127.0.0.1", 3030); // 这里问题又来了,实现客户端 与 客户端 聊天嘛。所以传输的东西肯定不能写死啊 // 因此:再开线程 new openClientThread(clientSocket).start(); } catch (IOException e) { e.printStackTrace(); } } } // 开线程 class openClientThread extends Thread{ private Socket socket; public openClientThread( Socket socket ){ this.socket = socket; } @Override public void run() { // 线程该做的事 System.out.println("聊天开始"); Scanner input = new Scanner(System.in); // 进行数据传送 while (true){ try { BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); String text = input.nextLine(); bw.write(text); } catch (IOException e) { e.printStackTrace(); } } } }
-
-
3、客户端给客户端发送数据( 即:多人聊天 )————注意:直接通过客户端 和 客户端交互是不可以的
-
-
3、UDP协议编程———即:DatagramSocket编程
-
UDP编程————其实和TCP一样,玩法都一样,只是Socket变成了DatagramSocket而已
- 不需要连接,但是需要知道对方的地址
- 没有客户端 和 服务端的概念————可以互相发
- 就像:发包裹一样————只需要知道地址就可以了
-
UDP编程————其实和TCP一样,玩法都一样,只是Socket变成了DatagramSocket而已
-
-
直接上实例
-
package AboutUDP.SendFiles; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class SendFile { public static void main(String[] args) throws Exception { //1、和传文件的对象建立链接---> // 这个socket和Receive里的socket是同一个:起到链接的作用 DatagramSocket socket = new DatagramSocket(); //2、需要知道接收端的ip和端口号 InetAddress ip = InetAddress.getByName("localhost"); int port = 8888; //3、得有一个要发送的东西--->可以通过写程序让它去网上下东西,然后发过去 //在这里 用自定义一个内容发过去测试 String data= "你像个傻逼,还不晓得努力!"; //4、发什么内容,发的内容是从哪里开始---结束,发给什么Ip和端口 DatagramPacket packet = new DatagramPacket(data.getBytes(),0,data.getBytes().length,ip,port); //data.getBytes()把要传送的数据包转为字节型数组:是因为电脑底层的传送实质是以字节来传送的 //5、发送文件 socket.send(packet); //6、关闭链接 socket.close(); } }
-
-
直接上实例
-
-
-
package AboutUDP.SendFiles; import java.net.DatagramPacket; import java.net.DatagramSocket; public class ReceiveFile { public static void main(String[] args) throws Exception { //1、得有一个端口来让别人链接 DatagramSocket socket = new DatagramSocket(8888); //2、接收包文件 byte[] receiveFile = new byte[1024];//这个空的数据包是用来接收数据的:把接收的数据装在这里面 //DatagramPacket这才是接收数据的命令 DatagramPacket packet = new DatagramPacket(receiveFile,0,receiveFile.length); //3、接收 装好的包文件 socket.receive(packet); //看一下效果 System.out.println(new String(packet.getData(),0,packet.getLength())); //4、关闭链接--->实质为关闭端口,防止端口占用 socket.close(); } }
-
-
-
4、URL
- 这个就不玩了,这个玩意儿就是定位网上的资源嘛( 怎么定位,就是输入的网址呗 ),因为:这个url就是一个对象,代表的就是url地址,也就是浏览器( 输入网址弹出来的不就是相应的页面内容吗 )
-
-
这玩意儿在Java中怎么创建出来?
- 万物皆对象嘛,这句话在博客开篇不是白说的,因此:new一下就出来了,至于具体怎么玩自行看源码摸索( 提示:这个东西可以搞小爬虫,获取网上资源 )
-
这玩意儿在Java中怎么创建出来?
自此:Java相关的网络编程就整完了
最新更新
python爬虫及其可视化
使用python爬取豆瓣电影短评评论内容
nodejs爬虫
Python正则表达式完全指南
爬取豆瓣Top250图书数据
shp 地图文件批量添加字段
爬虫小试牛刀(爬取学校通知公告)
【python基础】函数-初识函数
【python基础】函数-返回值
HTTP请求:requests模块基础使用必知必会
SQL SERVER中递归
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
uniapp/H5 获取手机桌面壁纸 (静态壁纸)
[前端] DNS解析与优化
为什么在js中需要添加addEventListener()?
JS模块化系统
js通过Object.defineProperty() 定义和控制对象
这是目前我见过最好的跨域解决方案!
减少回流与重绘
减少回流与重绘
如何使用KrpanoToolJS在浏览器切图
performance.now() 与 Date.now() 对比