分享

网络通信之Session的历史血脉

 编程一生 2022-03-09

Session经常被大家翻译为【会话】,在一个应用内部设计架构中,它通常指进程内保存的状态数据或者属性。

2007年

2007年我的本科毕业设计里,用了很多JSP里嵌Java代码的操作。比如登录是这么写的:

运行效果是这样的:

对的,我就是用这么原始的技术成功的混到了毕业文凭。

我周围的男同学技术比我要好一些,他们的用法也比我要高级,前端JSP里没有调用Java代码,有专门的后端来处理。

HttpSession hs = request.getSession();PrintWriter pw = response.getWriter();String msg = request.getParameter("ming");pw.println(msg);pw.println(hs.getId());

这两种方式本质上就是使用Java Servlet配合http协议标准来实现的。

HttpSession

服务器会为每一个用户 创建一个独立的HttpSession

原理

当用户第一次访问Servlet时,服务器端会给用户创建一个独立的Session

并且生成一个SessionID,这个SessionID在响应浏览器的时候会被装进cookie中,从而被保存到浏览器中

当用户再一次访问Servlet时,请求中会携带着cookie中的SessionID去访问

对于Servlet而言。服务器会根据这个SessionID去查看是否有对应的Session对象,有就拿出来使用;没有就创建一个Session(相当于用户第一次访问)。换句话说:若Servlet是客户端访问的第一个WEB应用的资源,则只有调用了request.getSession()或request.getSession(true) 才会创建HttpSession对象。

域的范围

    Context域 > Session域 > Request域

    Session域 只要会话不结束就会存在 但是Session有默认的存活时间(30分钟)

注意点

1>这时候的Session是跨线程的。

2>一个Session的概念需要包括特定的客户端,特定的服务器端以及不中断的操作时间。A用户和C服务器建立连接时所处的Session同B用户和C服务器建立连接时所处的Session是两个不同的Session。基于这个注意点,多数线上服务都是采用集群或者在扩展性上支持了集群,所以现在基本上没有人使用HttpSession了,当然只是做个毕设还是可以的。

总结

通过HttpSession主要是获取其中保存的状态数据或者属性,是一种状态的保持。

2015年

2015年我做了一个PHP的项目,发现在PHP里Session那个好用。其实PHP里的Session和Java Servlet的Session原理基本相同。在集群情况下也是会失效的。但是为什么都过去8年了,Java中基本已经淘汰了这种用法,在PHP里还在用呢?

我个人理解那就是PHP语言的本身适用范围了。PHP本身适用于简单轻量的小型系统,这种系统有些就是单服务器在运行的。对可用性要求也不是特别高,出了问题可以通过立即重启或者启用备份服务器解决。Session里的信息如用户信息丢了用户重新登录就好了。

总结

通过PHP里Session和HttpSession一样,主要是获取其中保存的状态数据或者属性,是一种状态的保持。

2016年

当时做项目用到ActiveMQ,它实现了JMS标准。先看一段简单代码:

public class JMSProducer {    public static void main(String[] args) {        //连接工厂        ConnectionFactory connectionFactory;        //连接        Connection connection  = null;        //会话,接受或者发送消息的线程        Session session;        //消息的目的地        Destination destination;        //消息生产者        MessageProducer messageProducer;        //实例化工厂        connectionFactory = new ActiveMQConnectionFactory(ConnectionConstants.BROKENURL);        try {            //获取连接            connection = connectionFactory.createConnection(ConnectionConstants.USERNAME, ConnectionConstants.PASSWORD);            //启动连接            connection.start();            //创建session            //参数1:1、true:支持事务            //为true时:paramB的值忽略, acknowledgment mode被jms服务器设置为SESSION_TRANSACTED 。              // 2、false:不支持事务             // 为false时:paramB的值可为Session.AUTO_ACKNOWLEDGE、Session.CLIENT_ACKNOWLEDGE、DUPS_OK_ACKNOWLEDGE其中一个,            // 为Session.SESSION_TRANSACTED时会报错!            //参数2:Session.AUTO_ACKNOWLEDGE为自动确认,客户端发送和接收消息不需要做额外的工作。异常也会确认消息,应该是在执行之前确认的            //Session.CLIENT_ACKNOWLEDGE为客户端确认。客户端接收到消息后,必须调用javax.jms.Message的acknowledge方法。jms服务器才会删除消息。可以在失败的            //时候不确认消息,不确认的话不会移出队列,一直存在,下次启动继续接受。接收消息的连接不断开,其他的消费者也不会接受(正常情况下队列模式不存在其他消费者)            //DUPS_OK_ACKNOWLEDGE允许副本的确认模式。一旦接收方应用程序的方法调用从处理消息处返回,会话对象就会确认消息的接收;而且允许重复确认。在需要考虑资源使用时,这种模式非常有效。            session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);            //创建一个消息队列            destination = session.createQueue("firstDemo");            //创建消息生成这            messageProducer = session.createProducer(destination);            //创建消息            TextMessage message = session.createTextMessage("ACTIVEMQ 生产者 生产消息,这是第"+i+"次生产");            //发出消息            messageProducer.send(message);
session.commit(); } catch (JMSException e) { // TODO Auto-generated catch block e.printStackTrace(); }    }}

注意在上面的connection连接中创建了session。在《深入理解MQ生产端的底层通信过程-理解channel》MQ中怎么使用Channel那一节,RabbitMQ的生产端 connection.createChannel()。对比之下,情不自禁就要问了,这里的Channel等价于Session?

自然不是啦,针对他们的区别。知乎上有个神回复:“Session是会话,比如打电话,从拨号到挂断这就是一个Session;Channel是通道,我的理解是比如打电话时,Channel表示是使用联通信号或者是移动信号或者是电信信号。”

Channel是文件的读取等操作的抽象,而Session我理解是连接中状态数据的保持或者复用。Channel在《深入理解MQ生产端的底层通信过程-理解channel》里讲过了。那Session这块怎么理解呢?

在上面JMSProducer的代码中,我可写了大段的注释。这些注释可不是白写的。我们列举一下在上面的Session中显式的保存了哪些东西:

  • 是否支持事务

  • 客户端收到消息是否自动确认

  • 一个消息队列firstDemo

  • 一个可以发消息给firstDemo的生产者

  • 一个消息内容

一般我们每次发消息时,消息内容会需要新建,但是生产者、消息队列、是否支持事务和客户端收到消息是否自动确认这些都可以复用。幸好人家设计的时候也设计了Session,每次直接用就可以了。

总结:MQ中的Session是连接中状态数据的保持或者复用

2020年

项目原因我研究了mybatis的源码,本来都计划为了满足项目需求自己重写一个mybatis了,后来重新规划设计没有做。在mybatis的本质和原理里我手撕了一个简易mybatis,里面有提到SqlSession。作用类似于一个 JDBC 中的 Connection 对象的代理,代表着一个连接资源的启用,它的作用有 3 个:

  • 获取 Mapper 接口。

  • 发送 SQL 给数据库。

  • 控制数据库事务。

本质上我理解也是连接中状态数据的保持或者复用。一段代码感受一下:

//定义 SqlSessionSqlSession sqlSession = null;try {    // 打开 SqlSession 会话    sqlSession = SqlSessionFactory.openSession();    // some code...    sqlSession.commit();    // 提交事务} catch (IOException e) {    sqlSession.rollback();  // 回滚事务}finally{    // 在 finally 语句中确保资源被顺利关闭    if(sqlSession != null){        sqlSession.close();    }}

上面在sqlSession对象中进行了事务的提交和回滚操作,非常类似于咱们在navicate等mysql客户端界面上的一个会话终端的操作。

在这同一个session下,因为就好像之前在HttpSession 登录有效期内用户的操作一样,只是界面不同。

总结

本文从个人的时间经历,分析了Session演进的血缘关系。这十几年的演进中,Session的概念越来越泛化,但是本质上还是保存的状态数据或者属性。

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多