[TOC]

无论在哪里都要树立远大的目标,只要这个目标这个蓝图是好的,那就要踏踏实实一步步走下去,终有一天会实现。

习大大说过:实现中华民族的伟大复兴,就是中华民族近代最伟大的梦想。最近因为一些其他的原因一直在看习语录,真心觉得里面很多都是有道理的,里面的话语说的都很实在,古诗、各种排比比比皆是,多读两下确实挺好的。说多了,总归既要仰望星空,又要脚踏实地。

今天准备毕业相关材料,科研证明第一作者不是学校的不算,空有两个专利却一个也不能写,好多人都在去准备专利,这样做的意义何在呢?上学到底是为了什么,成就是成,做什么都做到问心无愧。能力到了就好,通过其他方式就不能证明吗?这样吧答辩应该还是会让答辩的。

今天想实现一个点对点通信的软件,AB两台电脑可以互相发数据,查看了相关资料,里面有介绍Socket实现、或者消息队列实现。

Socket实现

Socket实现我理解的在本机实现比较容易,有服务端和客户端,两个可以互相发消息。使用TCP或者UDP协议都行,但是AB两个不在一个局域网内,如何寻找对方的地址呢,这个我就有点晕乎了,所以需要服务器做转发,所以还在思考怎么做。

使用消息队列

A往服务器上消息队列中发消息,消息队列将消息送到B中就可以了。感觉上还是可行的,所以来实现一下。

什么是消息队列

官方解释:

消息队列是一种进程间通信或同一进程的不同线程间的通信方式,软件的贮列用来处理一系列的输入,通常来自用户。消息队列提供了异步的通信协议,每一个贮列中的记录包含详细说明的数据,包含发生的时间,输入设备的种类,以及特定的输入参数,也就是说:消息的发送者和接收者不需要同时与消息队列交换,消息会保存在队列中,直至接收者取回它。

可能看上面的定义有些无聊,我理解的就是一个管道,你放入东西就可以走了,过会就会有人来取,当然这样理解有些狭隘,继续看下去就可以了。

使用场景

这里推荐一篇来自简书的消息队列技术介绍,中间介绍了使用场景,其中就有聊天室的使用。

Hello World

从上面的文章中,我们看到有许多不同的消息队列实现,这里选一个RabbitMQ,跟着教程走一下。

消息队列中有三个角色 :生产者、消费者和消息队列,RabbitMQ是一个消息中间人,它接受消息并且转发消息。你可以将消息队列看成一个邮局,当你想发邮件的时候你就将信放入邮局,你能确定的是邮差能够将邮件送给你想要送给的人。与邮局不同的是,RabbitMQ不处理,它仅仅是接受、存储和转发。

  1. 成功安装RabbitMq服务

  2. 创建一个Java项目,添加RabbitMQ jar包

  3. 添加Send.java

    public class Send {
        private final static String QUEUE_NAME = "hello";
    
        public static void main(String[] argv) throws Exception {
            // 创建连接工厂
            ConnectionFactory factory = new ConnectionFactory();
            // 设置连接地址
            factory.setHost("localhost");
            // 创建连接
            com.rabbitmq.client.Connection connection = factory.newConnection();
            // 创建频道
            Channel channel = connection.createChannel();
    
            // 声明一个队列 --
            // 在RabbitMQ中,队列声明是幂等性的(一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同)
            // ,也就是说,如果不存在,就创建,如果存在,不会对已经存在的队列产生任何影响
            channel.queueDeclare(QUEUE_NAME, false, false, false, null);
            String message = "Hello World!";
            //发送消息到队列中
            channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8"));
            System.out.println(" [x] Sent '" + message + "'");
    
            channel.close();
            connection.close();
        }
    }


  4. Recv.java

    public class Recv {
    
      private final static String QUEUE_NAME = "hello";
    
      public static void main(String[] argv) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
    
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
    
        Consumer consumer = new DefaultConsumer(channel) {
          @Override
          public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
              throws IOException {
            String message = new String(body, "UTF-8");
            System.out.println(" [x] Received '" + message + "'");
          }
        };
        channel.basicConsume(QUEUE_NAME, true, consumer);
      }
    }


  5. 这样运行接收端和发送端,能收到消息了。

介绍一些API

可以看到里面有些方法,还不是非常熟悉,我也要学习记录一下。

  1. channel.queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)

    Queue:代表队列

    durable:true或false,true的话在服务器重启时,能够存活。是否持久化用

    exclusive:是否是当前连接的专用队列,在连接断开后,会自动删除该队列。一般等于true的话用于一个队列只能有一个消费者来消费的场景

    autodelete:当没有任何消费者使用时,会自动删除该队列。

  2. channel.basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body)

    Exchange:名称

    routingKey:路由键,在topic exchange 做消息转发用

    Props:需要注意的是 BasicProperties.deliveryMode,1:不持久化 2:持久化,这里指的是消息的持久化。

    body:发送消息的内容

  3. basicConsume(QUEUE_NAME,true,consumer)

    autoAck:是否自动ack

目前实现了点对点通信,具体例子看一下官网上的相关例程就可以了。