系统温习------黑马程序员Java+AI智能辅助编程全套视频教程
JAVA网络编程
网络编程三要素
IP地址:设备在网络中的地址 ,是设备在网络中的唯一标识 ,用来定位网络上的设备.
IPV4使用32 位地址,通常以点分十进制表示。
IPV6使用128 位地址,IPV6分成8段 ,每段每四位编码成一个十六进制位表示 ,每段之间用冒号(:)分开 ,将这种方式成为冒分十六进制。
IP 域名(Domain Name) 用于在互联网上识别和定位网站的人类可读的名称。
DNS域名解析(Domain Name System) 是互联网中用于将域名转换为对应IP地址 的分布式命名系统。它充当了互联网的电话簿,将易记的域名映射到数字化的IP地址 ,使得用户可以通过域名来访问网站和其他网络资源。
公网IP :连接到互联网的IP地址;
内网IP :局域网IP ,只能组织机构内部使用的IP地址 。以192.168开头的就是常见的局域网地址,范围为192.168.0.0 -- 192.168.255.255,专门为组织机构内部使用。
本机IP :127.0.0.1或localhost :代表本机IP,只会寻找当前程序所在的主机。
IP 常用命令 :ipconfig:查看本机IP地址 。Ping IP地址:检查网络是否连通。
InetAddress 类代表IP地址(获取本机IP对象和对方IP对象)

端口:应用程序在设备中的唯一标识。
端口用来标记正在计算机设备上运行的应用程序,被规定为一个16位的二进制,范围是0~65535.
端口分类:
周知端口:0~1023,被预先定义的知名应用占用。
注册端口:1024~49151,分配给用户进程或某些应用程序。
动态端口:49152~65535,一般不固定分配 某种进程,动态分配。
自己开发程序一般选择注册端口,一个设备不能出现两个程序的端口号一样,否则报错.
协议:网络上通信的设备事先规定的连接规则 ,数据在网络中传输的规则。
UDP协议(用户数据报协议)特点:无连接、不可靠通信。
UDP协议不事先建立连接 ,数据按包发(限制在64KB内) ,发送方不管对方是否在线 ,数据在中间丢失也不管 ,如果接收方收到数据也不返回确认。适用于视频直播和网络通话。
TCP协议(传输控制协议)特点:面向连接、可靠通信。
TCP要保证在不可靠的信道上实现可靠的数据传输。
TCP主要通过①三次握手建立连接(可靠连接:确保通信双方收发消息都是没问题的(全双工)) 。②传输数据进行确认 。③四次挥手断开连接(确保消息全部收发完毕)。实现可靠传输。适合做网页、文件下载、支付。


UDP通信
无连接、不可靠通信
Java提供了DatagramSocket类 实现UDP通信。
DatagramSocket :用于创建客户端、服务端

客户端实现步骤:
①创建DatagramSocket对象(客户端对象)//只发不收则可以采用系统的随机端口号
②创建DatagramPacket对象封装需要发送的数据(数据包对象)
③使用DatagramSocket对象的send方法,传入DatagramPacket对象
④释放资源
服务端实现步骤:
①创建DatagramSocket对象并指定端口(服务端对象)
②创建DatagramPacket对象接收数据(数据包对象)
③使用DatagramSocket对象的receive方法,传入DatagramPacket对象。
④释放资源
客户端可以反复发数据:

服务端可以反复接收数据:

UDP的接收端可以接收很多发送端的消息 ,因为它只负责接收数据包 ,无所谓是哪个发送端的数据包。
TCP通信
面向连接、可靠通信
Java提供了Socket类 来实现TCP通信。
客户端:


客户端步骤:
①创建客户端的Socket对象,请求与服务端的连接。
②使用socket对象调用getOutputStream( )方法得到字节输出流。
③使用字节输出流完成数据的发送。
④释放资源:关闭socket管道。
服务端通过ServerSocket类来实现。

服务端开发:
①创建ServerSocket对象,注册服务端端口。
②调用ServerSocket对象的accept( )方法,等待客户端的连接 ,并得到Socket管道对象。
③通过Socket对象调用getInputStream( )方法得到字节输入流、完成数据的接收。
④释放资源:关闭socket管道。
使用TCP通信实现多发多收消息

客户端发送数据注意发出去后并没有关闭管道 ,所以需要刷新管道:flush( )。
TCP通信同时接收多个客户端消息
之前开发的服务端只有一个主线程 ,只能处理一个客户端的消息。
方案:主线程负责循环接收客户端管道的连接 ,每接收到一个Socket通信管道后,把该客户端管道交给独立的子线程专门负责接收这个客户端管道的消息。

主线程通过有参构造器将socket传递给子线程 ,子线程定义私有成员变量来接收。
当主线程接收到一个socket对象 后,可以记录该管道对应客户端的IP地址和端口号并打印出来提示上线 。在子线程中当客户端下线,run方法会抛出异常 ,此时在catch语句中捕获并打印出该管道对应IP地址的客户端下线。
B/S架构的原理
客户端使用浏览器发起请求 (不需要开发客户端)。服务器必须给浏览器响应HTTP协议规定的数据格式 ,否则浏览器不识别返回的数据.

这个格式更适合用打印流PrintStream来进入输出,因为打印流自带换行。
网站的请求往往数量多且工作时间短 ,适合使用线程池来做网站的处理。
使用线程池优化:把所有客户端socket管道包装成任务对象让它们都成为任务,进入任务队列。线程池提供核心线程处理所有请求。
线程类本身实现了Runnable接口,故可以当作任务对象用。

线程池调用execute( )方法处理任务 ,处理任务时会调用任务对象的run方法响应网页数据回去。
完成局域网内沟通软件的开发
时间相关的获取方案:


JDK8之前使用Date 获取此刻日期时间 ,使用SimpleDateFormat简单日期格式化:格式化日期对象成为我们喜欢的格式。Date日期类线程不安全。
JDK8之后的方案,LocalDate、LocalTime、LocalDateTime获取此刻日期时间 。使用DateTimeFormatter来格式化日期。

字符串的高效操作方案:
当需要大量拼接字符串内容时,+号拼接字符串内容的效率极差 。因为String的对象是不可变变量 。每次拼接都要放弃原来的对象而指向新的对象 ,内存中不断堆积拼接过程中的对象。String对象共享数据性能可以 ,但是修改数据性能差。
StringBuilder代表可变字符串对象,相当于是一个容器 ,它里面装的字符串是可以改变的,就是用来操作字符串 的。StringBuilder支持链式编程。

定义字符串可以使用String类型 ,但是操作字符串适合用StringBuilder性能好。
StringBuilder只是拼接字符串的手段 ,结果还是要恢复成字符串(通过调用其toString( )方法)。
BigDecimal
BigDecimal用于解决浮点型运算时,出现结果失真的问题 。计算机底层通过二进制存小数 ,小数部分的结果是由2的-1次方、2的-2次方......拼出来的。
把小数包装成BigDecimal对象来运算。

必须使用public BigDecimal(String val)字符串构造器才能解决失真问题。

需求:
展示一个用户的登录界面 ,这个界面只要求用户输入自己聊天的昵称就可以了。
登录进入后,展示一个群聊的窗口 ,这个窗口,展示在线人数 ,展示消息展示框 ,消息输入框 ,发送按钮。可以实现群聊,实现实时展示在线人数。完全做到即时通讯的项目。
技术选型:
GUI编程技术 -- Swing
网络编程
面向对象设计
常用API
思路分析:
①创建一个模块,代表项目:chat-system
②拿到系统需要的界面:Swing的代码
--登录界面:用户只输入聊天的昵称即可
AI Prompt:我是Java开发人员,请你使用Swing代码设计一个美观的局域网聊天的进入界面,这个界面上只有昵称,输入框,进入和取消按钮。
--获取系统需要的聊天界面
AI Prompt:我是Java开发人员,请你使用Swing代码设计一个美观的局域网群聊的聊天界面,不需要有私聊的界面。 这个界面上参照上面的图片进行设计,中间黑的是聊天区域,下部是输入框区域,右侧上面是展示在线用户的区域,下部是一个发送按钮.
③定义一个App启动类:创建进入界面对象并展示。
④分析系统的整体架构
4.1:开发服务端要做的事情:
--接收客户端的管道链接。
--接收登录消息,接收昵称信息。
--服务端也可能是接收客户端发送过来的群聊消息。
--服务端存储全部在线的socket管道 ,以便到时候知道哪些客户端在线 ,以便为这些客户端转发消息。
--如果服务端收到了登录消息 ,接收昵称 ,然后更新所有客户端的在线人数列表。
--如果服务端收到了群聊消息 ,接收这个人的消息 ,再转发给所有客户端展示这个消息。
4.2.客户端界面已经准备好了。
⑤开发完整的服务端
5.1.创建一个服务端的项目:chat-server
5.2.创建一个服务端启动类 :启动服务器等待客户端的连接。
定义一个常量包来配置端口号。
5.3.把这个管道交给一个独立的线程来处理:以便支持很多客户端可以同时进来通信。
5.4.定义一个集合容器存储所有登录进来的客户端管道,以便将来群发消息给他们。这个集合只需要一个记住所有的在线的客户端socket。
//将来收到管道发来的消息时,要知道这是哪个用户的管道,以便群发消息时指明是谁发的消息,因此应该用一个Map集合
//Map集合的键是客户端的Socket,值是该Socket所对应的用户名
public static final Map<Socket, String> onlineSockets= new HashMap<>();
5.5.服务端线程开始接收登录消息/群聊消息
//接收的消息可能有很多种类型:1、登录消息(包含昵称)2、群聊消息
//客户端必须声明协议来发送消息
//比如客户端先发1、代表接下来是登录消息。2、代表接下来是群聊消息
先接收一个整数,再判断,区别对待。
5.6.实现服务器端的登录消息接收
5.7.接收客户端的群聊消息:线程每接收到一个客户端的群聊消息,就应该把这个消息转发给全部在线的客户端对应的socket管道。
⑥完善整个客户端程序的代码
6.1.从登陆界面开始:完成了登录,完成了socket管道传给消息聊天界面。
给这个进入按钮绑定一个点击事件监听器 ,让它可以点击,一旦点击,获取到昵称,然后立即请求与服务器端的socket管道连接 。并立即发送登录信息:发送1,发送昵称。再展示客户端的聊天界面:接收到了昵称,接收到了属于自己客户端的socket通信管道。
6.2.立即在消息聊天界面读取客户端socket管道从服务端发来的在线人数更新消息/群聊消息
*交给一个独立的线程专门负责读取客户端socket从服务端收到的在线人数更新数据和群聊数据。
*收到消息,先判断消息的类型,判断是在线人数更新消息还是群聊消息,分开处理。
6.3.接收群聊消息
*接收消息类型2,接收群聊数据,展示到界面的面板上去即可。
6.4.发送群聊消息
*给发送按钮绑定一个点击事件,获取输入框的消息内容,再先发送2,再把群聊内容发送给服务器就完事了。