Java项目-网页聊天程序

目录

项目介绍

项目功能简介

项目创建

用户管理模块

1.数据库设计及代码实现

2.前后端交互接口的设计

3.服务器代码开发

好友管理模块

数据库设计

好友表设计的两个重要问题

设计前后端交互接口

服务器代码

会话管理模块

会话的数据库设计

获取会话信息

约定前后端接口

客户端代码

服务器代码

创建会话

约定前后端交互接口

客户端代码

服务器代码

消息的传输模块

获取指定会话的最后一条消息

服务器代码

获取指定会话的历史消息

约定前后端交互接口

服务器代码

客户端代码

消息的发送和接收

更好的方案WebSocket

WebSocket的报文格式

websocket握手过程

基于websocket编写代码

基于spring的websocket api,实现简单的hello world

服务器代码

客户端代码

使用websocket实现消息的接收和转发

约定消息传输的前后端交互接口

 实现客户端发送消息

客户端接收消息

服务器的接收和转发消息

添加好友功能

搜索功能

添加好友请求

收到好友请求之后,决定是接受还是拒绝

接受和拒绝好友


项目介绍

仿照网页微信实现用户之间的聊天通信.

项目功能简介

用户管理模块

注册:实现一个注册页面,输入用户名密码,进行用户注册.

登录:实现一个登录页面,输入用户名密码,进行用户登录.

主界面模块

个人信息模块:在左上角显示当前用户的信息(用户名)

会话列表模块:左侧罗列出当前的用户有哪些会话.

好友列表模块:左侧罗列出当前所有的好友信息.

消息区域模块:右侧显示消息区域,最上面显示会话名称,中间是消息列表,下方显示一个消息输入框,可以输入消息,并发送.

消息传输模块:能够真正的进行消息的发送和接收.

添加好友模块:左上角搜索框,搜索用户名,进行添加好友模块.

项目创建

用户管理模块

实现用户登录和用户注册两个功能.

注册操作就是给用户表插入新的记录,登录操作就是从用户表中进行查询.

1.数据库设计及代码实现

首先创建一个用户表,包含userId,username,password三个字段.

编写数据库实现代码

创建实体类,User.

编写mapper接口

编写sml,借助MyBatis自动生成数据库操作的实现.

这里的名字要符合配置文件中规定的名字.

在resources目录下创建mapper子目录,xml文件要以Mapper.xml为后缀.

2.前后端交互接口的设计

此处需要两个接口,一个是注册接口,一个是登录接口.

我们要提前规定好前端后端交互的具体细节.

3.服务器代码开发

4.客户端代码

客户端界面的设计在完整代码中,此处不过多介绍.

我们在前端使用ajax的方式向后端发起请求.

如果拿个对象,传给ajax方法的data属性,ajax就会默认按照form表单的格式来构造数据.

我们可以通过抓包来查看此处登录交互的过程.


在主界面获取当前登录用户

我们要在客户端主界面的左上角显示出当前登录用户的用户名.

在前端发送一个ajax的get请求,在后端实现一个路由为userInfo的接口.

在后端里,我们直接从此次请求的session里获取到当前的登录用户.因为我们在登录的时候,已经保存了当前的用户的session.


好友管理模块

数据库设计

好友表里应该包含两个实体,一个是用户,一个是好友.

实体之间的关系应该是多对多的关系:一个用户可以有多个好友,一个好友也可以被多个用户添加.

此处需要有一个关联表,通过关联表把另外两个表联系到一起.其实这里的两个表(用户表,好友表)是一个表,都是用户表.更准确的说是把用户表的两条记录联系到一起.

friend表作为关联表,有userId和friendId两个字段.

聊天软件里好友关系,都属于是强好友关系.A是B的好友,那么B也是A的好友.

好友表设计的两个重要问题

1.如果用户很多,每个用户的好友又有很多很多,此时这个好友表就会非常大,查询速度就会变得很慢很慢,那么此时应该怎么办?

处理方法就是分库分表.

一种典型的思路就是userId进行切分.比如针对userId来计算一个hashCode,然会在针对hashCode进行切分.假设分成100张表(friend0-friend99),此时hashCode%100,结果是几,就把这个记录放到哪个表里.我们这样做,同一个userId的记录是一定在同一张表里的.

后续比如要查询某个用户的好友都有哪些,还是按照同样的方法来查.根据userId来计算hashCode,算出hashCode之后,hashCode%100,到对应的表里去查询.

2.在分库分表的背景下,我们是希望每个表的大小是相对均匀的,这样查询速度也没有太大的差异.

但是在用户中,可能存在一些用户,好友非常的多,这些大用户的存在就可能会导致表的大小不均衡了.

面对此种情况,我们要进行特殊处理.毕竟大用户还是少数的.所以我们可以针对这些大用户单独分表,这个表里只存大用户对应的好友关系,让大用户和普通用户的表分离开.这种处理方法,我们也叫做冷热数据分环处理.

但是在这里上述问题,我们暂时不考虑,我们没有那么的假数据.


设计前后端交互接口

请求

GET/friendList

响应

HTTP/1.1 200 OK

Content-Type:application/json

[{friendId:2 friendName:'李四'},{friendId:3 friendName:'王五'}]

body部分我们用一个json数组接收.


前端我们使用ajax发送get请求

此函数的第一件事就是要把好友列表里的原有内容给清空掉.

这样做有两个目的:第一就是把原有我们写死的内容给删除掉;第二就是假如页面触发了多次getFriendList()函数,如果不先清空原有的内容,就会把第二次查询的内容追加到好友列表中.

关于网络传输的注意点

网络上交互的数据都是字符串(二进制的字节流),换而言之就是网络传输中就没有对象的概念.

服务器返回响应的时候,需要先把返回的对象,通过json库,转成json格式的"字符串",然后才能进行网络传输.

浏览器收到的也是"字符串",正常来说,浏览器收到响应body中的字符串(json格式),需要先使用JSON.parse把字符串转换未js对象的数组.但是对于响应中Content-Type为application/json这种情况,不需要我们在代码里进行手动转换了,这个工作由jquery的ajax自动完成了,所以我们代码里的回调函数的参数body已经是JSON.parse转换之后的了,得到的已经是js对象数组了.


服务器代码

先实现一个friend的实体类.

实现FriendMapper,根据userId查询好友.

此处查询使用的是子查询.先根据传递的userId在friend表里查询其对应的好友id是多少,在根据查到的好友id在user表里查询其对应的用户是谁.


会话管理模块

会话管理包括获取会话信息和新增会话两个部分.

此处谈到的会话(session)特指在聊天过程中,产生的业务上的会话.

每次用户发起一个聊天,就相当于创建了一个会话,这个会话里就包括了"人"和"消息".

会话管理要想持久化存储,就必须在数据库中进行保存.

会话的数据库设计

设计的实体有3个:会话,用户和消息.

首先要创建一个会话表,包含sessionId和lastTime(上次访问事件,方便后续我们通过时间针对会话表进行排序)两个字段.

在这里会话和用户是多对多的关系.所以要创建一个会话和用户的关联表.

message_session_user表里就包含sessionId和userId两个字段.

会话和消息之间的关系是一对多的的关系.一个会话里包含多条消息,一条消息只能从属于一个会话.

所以我们还要创建一个消息表.

message表包含messageId,fromId(消息是谁发送的),sessionId(消息从属于哪个会话),content(消息的正文部分),postTime(消息的发送时间).

在会话管理模块,我们先实现关于获取会话信息和新增会话两个功能,关于消息的功能后续实现.

获取会话信息

约定前后端接口

请求:GET/sessionList

响应:

HTTP/1.1 200 OK

Content-Type:application/json

[

        {

                sessionId:1,

                friends:[{friendName:'lisi',friendId:2}],

                lastMessage:"hello"

        },

      {

                sessionId:1,

                friends:[{friendName:'wangwu',friendId:3}],

                lastMessage:"hi"

        }

]

//响应的body是一个json数组

返回出当前用户的所有会话,同时按照这些会话的最后访问时间进行降序排序.针对每个会话,都要获取到当前的会话是和哪些用户产生的,另外还要获取到这个会话里最后一条消息是什么,以便显示到界面上.

客户端代码


服务器代码

获取会话信息,首先我们要根据userId查询出当前用户都存在哪些会话.

在通过查询到的sessionId查询出每个会话包含的用户(刨除自己).

在这里我们使用一个子查询来实现.其实根据userId查询sessionId用不到message_session表,但是由于我们希望返回的会话是按照时间的降序排序的,这一点很容易理解,因为界面上会话的排序肯定是时间降序排序的.由于关于会话时间的字段实在message_session里的,所以我们要进行一个子查询.(联合查询也可以实现).

此sql用来根据sessionId查询会话里存在的好友都有谁.

在这里要注意的是,虽说是好友,但也是用户,所以直接在user表里查询.要给列名取别名对应friend实体类.


创建会话

当用户点击了好友列表的某个好友的时候,此时就会触发创建会话的操作.

点击一个好友触发的操作包含两种情况:

1.如果会话不存在,就创建会话:

1)需要在客户端上创建出一个对应li标签,放到会话列表中,并且将此标签置顶且处于高亮状态,同时还要从好友列表切换到会话列表标签页.

2)还要给服务器发送一个创建会话的请求,让服务器将此新创建的会话的信息保存在数据库中.

2.如果会话已经存在,则把之前的会话找到:

1)把标签页切换到会话列表标签页,找到指定的会话,将此会话置顶并使其高亮.

2)给服务器发送请求,获取到该会话的历史消息,并且显示到右侧消息区域.(此功能在后续实现消息功能的时候实现)


约定前后端交互接口

请求:POST/session?toUserId=2

POST请求的参数,不仅仅可以放到body中,还可以放到查询字符串中.

响应:

HTTP/1.1 200 OK

Content-Type:application/json

{sessionId : 1}

响应的body中返回一个sessionId,将得到的sessionId保存到li标签的属性中.


客户端代码

在之前写的getFriendList函数中,给每个好友标签都添加一个点击事件.

这个客户端代码里,并不只是单纯的界面操作了,也不是单纯的前后端交互,而是包含了业务逻辑.


服务器代码

创建会话的服务器方面,涉及到三个操作:

1.先在messag_session表里新增一条记录,表示新建了一个会话记录.同时获取到新会话的自增主键.

2.给message_session_user表中插入记录.张三向李四创建新会话:5,1

3.给message_session_user表中插入记录.张三向李四创建新会话5,2


在这里使用spring提供的@Transactional标签,开启事务.

因为这三个操作都是连续的,其中任何的一个出了异常,整个的操作都不能执行.


消息的传输模块

前面在会话功能那里,我们已经设计好了message表应该包含哪些字段.

message表包含messageId,fromId(消息是谁发送的),sessionId(消息从属于哪个会话),content(消息的正文部分),postTime(消息的发送时间).

接下来我们来实现会话功能里的一个遗留的问题:获取指定会话的最后一条消息.

前面我们在实现会话功能的时候,服务器返回的消息是写死的,在这里,我们要在数据库里查询当前会话的最后一条消息.

获取指定会话的最后一条消息

服务器代码

按照事件的降序,把最新的消息显示到界面上.

把之前的代码修改掉.


获取指定会话的历史消息

这个操作肯定是要和服务器进行交互的,毕竟消息是存储在数据库中的,就需要前端先访问服务器,再让服务器来查询数据库.

约定前后端交互接口


服务器代码

我们规定的响应里除了message表的字段之外,还要包括发送消息的人的名字,所以要和user表进行一个联合查询.需要名字因为前端的消息区域里消息气泡上要带名字.

获取最近的一百条消息,所以用降序排序.


客户端代码

当消息足够多的时候,我们要将右侧消息区域滚动到最下方,所以还要做一个滚动条的设置.


消息的发送和接收

这是整个项目最核心的部分,但是这个部分的编写,需要依赖我们之前实现各大模块.

这里要明确一点,发送和接收消息,是需要"实时进行传输"的.

比如张三发了一条信息,李四是能立即收到消息的.

张三和李四之间能不能不通过服务器直接进行通信?
不能!因为NAT动态地址转换机制,不在同一局域网的两个内网的设备无法直接进行通信.

张三和李四都是普通的客户端,它们的设备大概率是没有外网IP的,只有内网IP.如果没有外网IP则不能直接被访问到.而我们的服务器是带有外网IP的,张三和李四都能够访问到服务器,因此就可以让服务器进行消息的中转.

使用服务器中转的另一个原因就是更容易在服务器记录历史消息,随时方便用户获取历史消息.


服务器如何主动推送消息给客户端?

张三发给服务器,张三是客户端,聊天程序是服务器,客户端主动发送消息给服务器,这很正常.(本来客户端就是主动发起请求的一方).但是服务器把消息转发给李四,李四也是客户端,服务器主动发响应给客户端,这对http来说是不太容易实现的.

这一点也可以理解,因为Http早期设计出来就是用户在静态网页上看报纸,用户需要哪个,就给服务器发送对应的请求.

那么采用轮询的方式可行吗?

用HTTP模拟实现消息推送的效果.就是让李四每隔一定的时间就给服务器发送请求,看看是否有自己的消息,如果有,就获取消息,如果没有,就继续等待到下次询问周期的到来.

轮询存在两个问题:

1.消耗更多的系统资源.

接收方在等待过程中,需要频繁的给服务器发起请求,然而这些请求里,大部分都是"空转"的.

2.获取消息不够及时.

需要等到下个请求周期才能拿到数据.

如果提高轮询的频率,此时获取消息就更及时了,但是消耗的系统资源也就更多了.

如果降低轮询的频率,此时消耗的系统资源相对较少了,但是同时获取消息就更不及时了.


更好的方案WebSocket

WebSocket是解决消息推送问题更好的方案.

WebSocket是一个应用层协议,和HTTP的地位是对等的,都是基于传输层的TCP实现的一个广泛使用的应用层协议.

WebSocket的报文格式

FIN表示是否要关闭WebSocket .

RSV是保留位,在这里有三个保留位.

opcode操作码,描述了当前的websocket数据帧具有什么作用.取值为0x1表示是个文本数据;取值为0x2表示是二进制数据.websocket协议既可以传输二进制数据,也可以传输文本数据.

MASK是否开启掩码操作.

payload length表示载荷的长度.payload就是载荷,也就是数据报上携带的具体数据.7个bit表示的范围,单位是字节,那是不是意味着一个websocket最多只能保存127字节?

其实不然,我们可以看到后面还有额外的载荷长度的表示,payload length有三种模式:
1)7bit,此时能表示的范围比较小

2)16bit,能表示的范围更大了

3)64bit,能表示的范围就更大了

最初的7bit的payload length<126,此时模式1生效;如果7bit的值为126,此时是模式2,16个bit位生效;如果7bit的值为127,此时是模式3,64个bit都生效了.

payload data是真正要传输的数据.


websocket握手过程

浏览器借助HTTP,向服务器发送请求,这个请求里会带有特殊的header.

Connection: upgrade(升级)和Upgrade:websocket.

如果服务器同意协议升级为websocket,会在响应中返回101的HTTP状态码,表示协议转换,同时也会在header中带有Connection: upgrade(升级)和Upgrade:websocket.

接下来,浏览器和服务器之间就相当于建立好了websocket的连接了,接下来就可以使用websocket进行数据传输了.


基于websocket编写代码

在java中有两种形式来使用websocket:

1.直接使用tomcat提供的原生websocket api.

2.使用spring提供的websocket api.

基于spring的websocket api,实现简单的hello world
服务器代码

1.先创建一个类,作为WebSocketHandler,来处理websocket中的各个通信流程.

此类要继承自TextWebSocketHandler(此类是Spring内置的).

给这个类加上@Component注解,注册到spring中去,确保程序启动,就能加载此类.

此处继承父类,主要是为了重写父类中的方法.

在这里主要重写这四个方法.

对于方法中形参的理解

WebSocketSession是websocket连接中对应的会话,此会话中就持有了此次websocket的通信连接,记录了通信双发都是谁.

TextMessage就是收到的具体消息.

Throwable exception记录了异常信息.

CloseStatus status记录了连接关闭时的状态.


2.将上述类的实例,注册到spring里面,并配置路由.


客户端代码

websocket的客户端和服务器都是分成四个阶段来进行处理:

连接建立成功后,收到消息后,连接关闭后,连接异常后.


启动程序,建立连接

抓包来看一下升级协议的交互过程


使用websocket实现消息的接收和转发

约定消息传输的前后端交互接口

此处已经不是http了,所以直接使用json格式来作为payload表示传输的内容.

请求

响应 


 实现客户端发送消息

要想发送消息,我们就要针对右侧消息的输入框和发送按钮进行处理.

此时构造完请求之后,不能直接通过websocket进行发送.

此时的req对象在js里的类型是object而 websocket.send()的参数必须是一个字符串,所以此处需要手动的将json对象转成json格式的字符串.

req = JSON.stringify(req);

JSON.stringfy是js自带的方法,功能就是把js对象转为json格式的字符串,类似于jackson的objectMapper.writeValueAsString().

JSON.parse,也是js自带的方法,功能是把json格式的字符串转为json对象.

类似于jackson的objectMapper.readValue().


客户端接收消息


服务器的接收和转发消息

实现服务器转发逻辑的时候,需要能够维护一个重要的映射关系:userId->WebSocketSession.

每个和服务器连接好的客户端,都会在服务器这边有一个对应的webSocketSession对象,服务器想要给谁发消息,就得通过哪个对象来send.

张三给服务器发送消息,服务器要将消息发送给李四,就必须获取到李四对应的websocketSession.

所以我们使用一个hashMap来记录,key是userId,value是WebSocketSession.

在客户端建立连接的时候,在afterConnectionEstablished方法中,将映射关系插入到哈希表中,意味着用户上线.

在客户端断开连接的时候,在handleTransportError和afterConnectionClosed方法中将映射关系从哈希表中删除,意味着用户下线.

此时已经可以确认,键值对中的value已经准备就绪了,在方法的参数中带有,那么key,userId应该怎么获取呢?

由于当前进行的不是http通信,所以不能直接获取到HttpSession中我们已经保存的用户信息.

既然信息在HttpSession里,那么在当前的websocket代码里,怎么获取到HTTP Session呢?

加入拦截器,我们只需要在最初注册WebSocketHandler的时候,在指定一个特殊的拦截器即可.

通过这样的手段,就能将用户在登录的时候,在HttpSession中存的user->User对象的键值对拷贝到websocketSession中来.

创建一个类,来记录映射关系

在WebSocketController这个handler类里实现具体的用户上线下线和消息转发和接收逻辑.


添加好友功能

搜索功能

在搜索框内输入一个用户名,点击搜索按钮,此时就会给服务器发起一个ajax请求,服务器就会根据用户名进行匹配,把名字符合的结果都显示到界面上.

先将搜索按钮进行初始化,点击搜索按钮,会向服务器发起请求,来获取搜索结果.

在这里使用一个模糊查询,注意在mybatis中,模糊查询要使用concat函数,用来进行字符串的拼接.

添加好友请求

获取到好友结果后,将结果显示到右侧消息区域.

输入理由之后,点击添加好友按钮,向服务器发起一个好友请求.

服务器收到之后,现针对此好友请求进行判定.

如果当前要添加的好友已经存在,就直接返回;如果已经向该用户发起过好友请求了,也直接返回.

如果判定通过,将此次的好友请求插入到数据库表中.

在数据库中,我们使用friend_request表来记录好友请求.

收到好友请求之后,决定是接受还是拒绝

收到请求可能是用户在线收到的,也可能是离线后下次上线收到的.

如果该用户是在线的,就直接通过websocket进行好友请求的实时传输.

如果用户不在线,那么在下次上线的时候,获取历史的好友请求.


接受和拒绝好友

在左侧会话列表里构造出一个好友请求,其中包含接受和拒绝按钮.

点击接受,就发起ajax请求,服务器收到之后,就把对应的好友关系加入到数据库friend表里,同时把friend_request表里对应的记录删除掉.

点击拒绝,发起ajax请求给服务器,只是把friend_request表里对应的好友请求删除掉,不修改好友关系表.


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/164946.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

开启Linux之旅:用VMware安装CentOS7

最近我的阿里云服务器到期了&#xff0c;不想续费&#xff0c;所以就深入研究了一下虚拟机搭建Linux系统&#xff0c;感觉还不错&#xff0c;所以在这篇博客中分享一下。下面我将带领大家开启全新的Linux之旅&#xff0c;用VMware安装CentOS 7&#xff0c;具体操作步骤如下所示…

IDEA中SpringBoot项目的yml多环境配置

SpringBoot的yml多环境配置 创建多个配置文件 application.yml #主配置文件 application-dev.yml #开发环境的配置 application-test.yml #测试环境的配置在application.yml中添加多环境配置属性 spring:profiles:active: profiles.active项目启动可能不会识别&#x…

AbortController中止请求通信[模糊搜索案例]

AbortController中止请求通信[模糊搜索案例] AbortController中止请求通信(模糊搜索案例) AbortController中止请求通信(模糊搜索案例) 这里用模糊搜索来做示例&#xff0c;这里是调用后端模糊搜索接口 该案例的中止请求可以用于很多地方&#xff0c;比如取消上传/下载文件等 完…

SpringCloud链路追踪——Spring Cloud Sleuth 和 Zipkin 介绍 Windows 下使用初步

前言 在微服务中&#xff0c;随着服务越来越多&#xff0c;对调用链的分析越来越复杂。如何能够分析调用链&#xff0c;定位微服务中的调用瓶颈&#xff0c;并对其进行解决。 本篇博客介绍springCloud中用到的链路追踪的组件&#xff0c;Spring Cloud Sleuth和Zipkin&#xf…

Shopee买家通自养号系统可批量注册、自动下单

Shopee买家通自养号系统是一款专门针对虾皮买家号所开发的软件&#xff0c;目前支持菲律宾、印度尼西亚、泰国、巴西、马来西亚等国家使用&#xff0c;可批量注册、自动下单。 如果想拥有大量的买家号&#xff0c;那么可以使用批量注册账号功能&#xff0c;把账号所需要的资料准…

购药不烦恼:线上购药小程序的快捷方式

在这个数字化时代&#xff0c;线上购药小程序的快捷方式正在改变着我们购药的方式。本文将介绍如何通过使用Python和Flask框架创建一个简单的线上购药小程序的原型&#xff0c;为用户提供购药的便利和快捷体验。 安装和设置 首先&#xff0c;确保你已经安装了Python和Flask。…

《C语言图形界面-系统开发》专栏介绍 专栏目录

《C语言图形界面-系统开发》介绍及目录 基本介绍 本项目是一个基于EasyX图形库的C语言图书管理系统。 界面优美高级代码结构设计合理注释详尽清晰 本专栏是一个详尽到完全贴近C语言初学者的教程&#xff0c;完整代码 配套教程&#xff0c;完全不用担心学不会的问题。 项目展…

危险化工品出口注意事项及法规要求_箱讯科技

随着全球化工品市场的不断发展&#xff0c;危险化工品出口业务逐渐成为国际贸易的重要组成部分。然而&#xff0c;由于危险化工品具有潜在的危险性&#xff0c;出口过程中需严格遵守相关法规和注意事项&#xff0c;以确保运输安全和顺畅。本文将详细介绍危险化工品出口注意事项…

RabbitMQ入门到实战教程,MQ消息中间件,消息队列实战

消息队列是目前最常见的微服务中间件之一&#xff0c;而RabbitMq在全球范围内的使用率也是名列前茅。它以稳定性强、并发高、低时延的特点深受广大企业开发者的喜爱。然而市面上一致缺乏一个专门的RabbitMQ课程&#xff0c;所以这套课程应运而生。 微服务一旦拆分&#xff0c;必…

go-fastdfs安装(国产分布式文件系统)

开源协议&#xff1a; Unlicense官网地址&#xff1a; https://sjqzhang.github.io/go-fastdfs/#vision安装: wget --no-check-certificate https://github.com/sjqzhang/go-fastdfs/releases/download/v1.3.1/fileserver -O fileserver && chmod x fileserver &…

c++入门(命名空间, c++输入输出, 缺省参数)

文章目录 1. 命名空间正确的命名定义命名空间的使用 2. c输入与输出标准输入输出对象向流写入 读取数据 3. 缺省参数缺省参数分类缺省参数声明缺省参数初始值 c的简单介绍 C语言是结构化和模块化的语言&#xff0c;适合处理较小规模的程序。对于复杂的问题&#xff0c;规模较大…

【图解RabbitMQ-5】RabbitMQ Web管控台图文介绍

&#x1f9d1;‍&#x1f4bb;作者名称&#xff1a;DaenCode &#x1f3a4;作者简介&#xff1a;CSDN实力新星&#xff0c;后端开发两年经验&#xff0c;曾担任甲方技术代表&#xff0c;业余独自创办智源恩创网络科技工作室。会点点Java相关技术栈、帆软报表、低代码平台快速开…

02_diffusion_models_from_scratch_CN

从零开始的扩散模型 有时&#xff0c;只考虑一些事务最简单的情况会有助于更好地理解其工作原理。我们将在本笔记本中尝试这一点&#xff0c;从“玩具”扩散模型开始&#xff0c;看看不同的部分是如何工作的&#xff0c;然后再检查它们与更复杂的实现有何不同。 我们将学习 …

Linux篇 五、Ubuntu与Linux板卡建立NFS服务

Linux系列文章目录 一、香橙派Zero2设置开机连接wifi 二、香橙派Zero2获取Linux SDK源码 三、香橙派Zero2搭建Qt环境 四、Linux修改用户名 文章目录 Linux系列文章目录前言一、连接到局域网互ping测试 二、安装NFS服务配置NFS更新exports配置三、板卡安装NFS客户端四、板卡临时…

microcom串口调试工具使用

microcom串口助手使用介绍 microcom是一个在终端中使用的串口助手&#xff0c;类似平常使用SSCOM一样的东西&#xff0c;不过是在终端中使用而已。 使用的是busybox构建的文件系统 microcom源码路径&#xff1a;busybox/miscutils/microcom.c microcom 参数&#xff1a; [r…

伊朗相关的OilRig组织在为期8个月的网络攻击中针对中东政府

导语 伊朗相关的OilRig组织最近在中东政府中展开了一场长达8个月的网络攻击行动。这次攻击导致了文件和密码的被窃取&#xff0c;并且在其中一次攻击中&#xff0c;攻击者还使用了一种名为PowerExchange的PowerShell后门。据Symantec的威胁猎人团队称&#xff0c;他们在一份与T…

【软考】6.2 网络安全技术

《网络安全技术》 防火墙 一道大门&#xff0c;隔离内网和外网主要分隔外网的威胁&#xff0c;对内网的直接攻击无能为力 入侵检测系统&#xff08;IDS&#xff09; 位于防火墙后的第二道屏障监听设备&#xff1a;监控当前系统 / 用户行为&#xff0c;无需网络流量即可工作尽…

【分布式】入门级NCCL多机并行实践 - 02

# 背景知识 大模型和分布式训练对数据的吞吐量以及并行度都有很高的要求&#xff0c;NCCL就是在这个背景下诞生的。 如果你是一个只会写写Python&#xff0c;调用PyTorch和Horovod的算法萌新&#xff0c;可能对于分布式底层的东西不太了解&#xff0c;在下岗热潮中被主管逼着…

换低挡装置(Kickdown, ACM/ICPC NEERC 2006, UVa1588)rust解法

给出两个长度分别为n1&#xff0c;n2&#xff08;n1&#xff0c;n2≤100&#xff09;且每列高度只为1或2的长条。需要将它们放入一个高度为3的容器&#xff08;如图3-8所示&#xff09;&#xff0c;问能够容纳它们的最短容器长度。 样例 2112112112 2212112 1012121212 2121…

MIT6.5830 Lab0-Go tutorial实验记录(四)

MIT6.5830 Lab0-Go tutorial实验记录&#xff08;四&#xff09; – WhiteNights Site Lab0的最后一步–对.csv文件进行查询。 实验步骤 更改handlers.go 那么首先修改下handlers中的方法&#xff0c;毕竟现在不是从sqlite中查询数据了。 // TODO: some code goes here // Ge…