RabbitMq消息收发详解(转)

2023-10-27

消费者有两种接收消息的方法:

poll consumer,即拉模式,消费者主动去消息队列拉取消息。
push consumer,即推模式,消息队列主动往消费者推送消息。
一. 消费者通过推(PUSH)方式获取消息
实现push模式最简单的方式就是使用@EnableRabbit+@RabbitListener注解来指定某方法作为消息消费的方法。例如监听某个Queue的方法。

  1. 配置RabbitListenerContainerFactory
    这个bean只会在consumer端通过@RabbitListener注解的方式接收消息的时候使用。每个@RabbitListener注解方法都会由RabbitListenerContainerFactory创建一个MessageListenerContainer,负责接收消息。

@Bean( name = “singleListenerContainer” )
public SimpleRabbitListenerContainerFactory listenerContainerFactory()
{
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
/* setConnectionFactory:设置spring-amqp的ConnectionFactory。 /
factory.setConnectionFactory( connectionFactory() );
/
消息序列化类型 /
factory.setMessageConverter( new Jackson2JsonMessageConverter() );
/
setConcurrentConsumers:设置每个MessageListenerContainer将会创建的Consumer的最小数量,默认是1个。 /
factory.setConcurrentConsumers( 1 );
factory.setMaxConcurrentConsumers( 1 );
/
setPrefetchCount:设置每次请求发送给每个Consumer的消息数量。 /
factory.setPrefetchCount( 1 );
/
是否设置Channel的事务。 /
factory.setChannelTransacted( false );
/
setTxSize:设置事务当中可以处理的消息数量。 /
factory.setTxSize( 1 );
/
设置当rabbitmq收到nack/reject确认信息时的处理方式,设为true,扔回queue头部,设为false,丢弃。 /
factory.setDefaultRequeueRejected( true );
/

* setErrorHandler:实现ErrorHandler接口设置进去,所有未catch的异常都会由ErrorHandler处理。
* factory.setErrorHandler();
*/
factory.setAcknowledgeMode( AcknowledgeMode.AUTO );
return(factory);
}
factory.setConnectionFactory(connectionFactory());设置spring-amqp的connectionFactory。
factory.setMessageConverter(new Jackson2JsonMessageConverter());对于消费者,序列化方式也可以在这里配置。
factory.setAcknowledgeMode(AcknowledgeMode.AUTO);设置consumer端的应答模式。
public enum AcknowledgeMode {
NONE, //无应答。
MANUAL,
AUTO;
}
NONE:无应答,rabbitmq默认consumer正确处理所有请求。
AUTO:consumer自动应答,处理成功(注意:此处的成功确认是没有发生异常)发出ack,处理失败发出nack。rabbitmq发出消息后会等待consumer端应答,只有收到ack确定信息后才会将消息在rabbitmq清除掉。收到nack异常信息的处理方法由setDefaultRequeueReject()方法设置,这种模式下,发送错误的消息可以恢复。
MANUAL:基本等同于AUTO模式,区别是需要人为调用方法确认。
注意:没有任何消息超时限制;只有当消费者挂掉时,RabbitMQ才会重新投递。即使处理一条消息会花费很长的时间。

factory.setConcurrentConsumers(1);每个MessageListenerContainer将会创建的Consumer的最小数量,默认是1个。
factory.setMaxConcurrentConsumers(1);设置每个MessageListenerContainer将会创建的Consumer的最大数量,默认等于最小数量。
factory.setPrefetchCount(1);设置每次请求发送给每个Consumer的消息数量。
factory.setChannelTransacted(false);设置Channel的事务。
factory.setTxSize(1);设置事务当中可以处理的消息数量。
factory.setDefaultRequeueRejected(true);设置rabbitmq收到nack/reject消息时的处理方式,true,重新放回到queue头部,设置为false丢弃。
factory.setErrorHandler();实现ErrorHandler接口设置进去,所有未catch的异常都会由ErrorHandler处理。
2. 使用@RabbitListener注解
2.1 配置@EnableRabbit
@EnableRabbit //开启rabbitmq的listener监听
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);

}

}
2.2 配置@RabbitListener
上面配置了singleListenerContainer信息,将其加入到containerFactory中。

@RabbitListener(queues = "queue_direct", 
         containerFactory = "singleListenerContainer")
public void receive02(Message message, long deliveryTag, Channel channel) {
    //获取头信息
    int i = 1 / 0;
    System.out.println(message.getMessageProperties().getHeaders());
}

2.3 启动项目,查看结果
我们可以看到,因为我们配置的是发生错误后,重回队列,并且是“自动确认”模式,那么程序已经为死循环了。

MQ界面信息.png
日志代码.png
3. consumer配置进阶学习
3.1 @RabbitListener注解的属性
3.1.1 queues = “queue_direct”
声明绑定的队列,但队列必须存在。

3.1.2. containerFactory = “singleListenerContainer”
声明要使用的容器工厂,一般我们在configuration类中配置。

3.1.3. bindings属性
@RabbitListener注解中指明binding信息,就能自动创建queue、exchange并建立binding关系。
(1)在2.0版本之后,可以指定多个routingkey即key={“ord”,“con”}。
(2)exchange属性中,可以使用type = ExchangeTypes.DIRECT指定不同类型的交换机。
(3)arguments属性,可以用于指定headers类型的exchange。arguments = @Argument(name = “x-message-ttl”, value = “10000”, type= “java.lang.Integer”)),
(4)queue属性中exclusive,排他队列,只对创建这个queue的Connection可见,Connection关闭,那么这个queue删除。
(5)queue属性中的autoDelete,若是这个consumer下线,那么这个queue队列将会删除。
bindings注意事项:

  1. 对于(4)(5)这两种情况,durable=true队列持久化是不起作用的。
  2. 注意不能和queues属性同时使用。
  3. 特别注意:如果注解声明的queue和xchange以及binging关系都存在的情况下,但是我们在bindings属性中又进行配置,那么bindings新增或者修改的参数都不会生效。但是queue存在,exchange存在但是没有binding,那么应用程序启动后,会自动创建binding关系。

@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = “queue_direct”, durable = “true”),
arguments = {}, //可用于headers类型的exchange
exchange = @Exchange(value = “exchange_direct” ,type = ExchangeTypes.DIRECT), //声明交换机的类型
key = “ord” //声明路由主键
), containerFactory = “singleListenerContainer”)
public void rec(Message message, long deliveryTag, Channel channel) {
Map<String, Object> headers = message.getMessageProperties().getHeaders();
System.out.println(“消息体--------->” + message.getBody());
// //foreach遍历循环
for (Map.Entry<String, Object> entry : headers.entrySet()) {
System.out.println(“消息头:” + entry.getKey() + “—” + entry.getValue());
}
}
3.2 @Payload以及@Headers
这两个注解可以获取信息体和信息头。

@RabbitListener(queues = “queue_direct”, containerFactory = “singleListenerContainer”)
public void handleMessage(@Payload Book body, @Headers Map<String, Object> headers) {
System.out.println("–>信息域的值"+body);
for (Map.Entry<String, Object> entry : headers.entrySet()) {
System.out.println(“消息头:” + entry.getKey() + “—” + entry.getValue());
}
}
效果图.png
3.3 @RabbitListener以及 @RabbitHandler
@RabbitListener可以标注在类上,需要配合@RabbitHandler注解一起使用。当标注在类方法上时表示收到消息后,就转交给@RabbitHander的方法处理。但是具体那个方法,要看MessageConverter转换后的参数。

@Service
@RabbitListener(queues = “queue_direct”, containerFactory = “singleListenerContainer”)
public class BookService {
// @RabbitListener(queues = “queue_direct”, containerFactory = “singleListenerContainer”)
@RabbitHandler
public void handleBook(@Payload Book body) {
System.out.println("–>信息域的值" + body);

}

@RabbitHandler
public void handleStr(@Payload HashMap<String, Object> body) {
    System.out.println("-->信息域2的值" + body);

}

}
3.4. 序列化方式MessageConverter
只要在RabbitTemplate中配置了MessageConverter在发送和接收消息时候就能自动完成Message和自定义java对象类的自动转换。

@Autowired
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory,MessageConverter messageConverter) {
//客户端开启confirm模式
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMandatory(true);
rabbitTemplate.setMessageConverter(messageConverter);
rabbitTemplate.setConfirmCallback(new ConfirmCallback() {
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
log.info(“消息发送成功:correlationData({}),ack({}),cause({})”, correlationData, ack, cause);
}
});
rabbitTemplate.setReturnCallback(new ReturnCallback() {
@Override
public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
log.info(“消息丢失:exchange({}),route({}),replyCode({}),replyText({}),message:{}”, exchange, routingKey, replyCode, replyText, message);
}
});
return rabbitTemplate;
}

我们可以在RabbitTemplate源码中看到:

private volatile MessageConverter messageConverter = new SimpleMessageConverter();
默认采用的是SimpleMessageConverter他就直接将java对象序列化。但是并不推荐直接使用,因为会只限于java平台。

推荐使用JsonMessageConverter、Jackson2JsonMessageConverter,这两个是都将java对象转化为json再转为byte[]来构造Message对象,前一个用的是jackson json lib,后一个用的是jackson 2 json lib。

@Bean
public MessageConverter messageConverter() {
return new Jackson2JsonMessageConverter();
}
3.5. consumer端的异常处理
有两个error handler类可以对@RabbitListener注解方法中抛出的异常进行异常处理。

3.5.1 RabbitListenerErrorHandler接口
配置类代码:

@Bean
public RabbitListenerErrorHandler rabbitListenerErrorHandler(){
    return new RabbitListenerErrorHandler() {
        @Override
        public Object handleError(Message amqpMessage, org.springframework.messaging.Message<?> message, ListenerExecutionFailedException exception) throws Exception {

            System.out.println("-------------------------------------"+message);

            throw exception;
        }
    };
}

监听类代码:

@RabbitListener(queues = "queue_direct", containerFactory = "singleListenerContainer",errorHandler = "rabbitListenerErrorHandler")
public void handleBook(@Payload Book body) throws Exception {
    int i = 1 / 0;
    System.out.println("-->信息域的值" + body);
}

效果图:

异常处理回调代码.png
3.5.2 ErrorHandler接口
这一个值是设置在RabbitListenerContainerFactory连接工厂的。

生产者生产了Book类型的消息:

@Test
public void contextLoads() {
    Book book = new Book("西游记", "120.00");
    rabbitTemplate.convertAndSend("exchange_direct", "ord", book);
}

配置类配置了ErrorHandler处理:
注意消息到达ErrorHandler则意味着处理失败,不需要在抛出异常。并且这个含有ConditionalRejectingErrorHandler默认配置,可以识别特定的不可挽回的异常拒绝requeue队列,防止消息处理的死循环。

factory.setErrorHandler(new ErrorHandler() {
@Override
public void handleError(Throwable throwable) {
System.out.println("------------------------->丢弃消息啦"+throwable);
//
}
消费者只接受String类型的消息:

@RabbitListener(queues = "queue_direct", 
      containerFactory = "singleListenerContainer",
      errorHandler = "rabbitListenerErrorHandler")
public void handleBook(String body) throws Exception {
    System.out.println("----------------->信息域的值" + body);
}

执行结果:

在发送异常后并未重新放入队列,而是直接丢弃消息。

执行结果
注意事项:

@RabbitListener和@RabbitHandler组合使用时,RabbitListenerErrorHandler配置无效。
@RabbitListenerErrorHandler作用域只是配置@RabbitListener注解上的,这个注解只对当前方法发生异常时有效。而ErrorHandler对所有@RabbitListener注解方法有效。
@RabbitListener注解的方法中抛出的异常,首先会进入RabbitListenerErrorHandler,这里如果没有能力处理这个异常,需要将其重新抛出(否则不会进入rrorHandler),然后异常将会进入ErrorHandler,一旦异常进入ErrorHandler就意味着消息消费失败了(所以不需要重新抛出异常)。
RabbitListenerErrorHandler没有默认配置,而ErrorHandler有一个默认的ConditionalRejectingErrorHandler类,他的作用打印日志,辨别特定的异常。将其包装成AmqpRejectAndDontRequeueException抛出,这个异常的作用是,忽略defaultRequeueRejected(前文已经讲过)的设置,强制让rabbitmq丢弃此条处理失败消息,不放回queue。
需要丢弃的异常:

o.s.amqp…MessageConversionException

o.s.messaging…MessageConversionException

o.s.messaging…MethodArgumentNotValidException

o.s.messaging…MethodArgumentTypeMismatchException

java.lang.NoSuchMethodException

java.lang.ClassCastException
3.5.3 设置死信队列
为了避免消息异常造成的死循环,也可以将requeue(上文配置参数)设置为false。消息被拒绝(basic.reject/ basic.nack)并且requeue=false时,消息会进入死信队列。于是我们可以监听死信队列来处理异常消息。

消息进入死信队列的途径:

消息被拒绝(basic.reject/ basic.nack)并且requeue=false。
消息TTL过期(参考:RabbitMQ之TTL(Time-To-Live 过期时间))。
队列达到最大长度。
小结:
自动确认模式下,可以使用3.5.1和3.5.2方式的异常处理机制即可。
手动确认模式下,推荐是使用死信队列的方式,即3.5.3处理。
需要注意3.5.1和3.5.2在手动确认模式下,若是异常未被捕获,也是可以生效的。
手动确定模式:

@RabbitListener(queues = “queue_direct”, containerFactory = “singleListenerContainer”, errorHandler = “rabbitListenerErrorHandler”)
public void handleBook(Message message, Book book, Channel channel) throws Exception {
try {
int i = 1 / 0;
} catch (Exception e) {
//告诉MQ删除这一条消息,若是true,则是删除所有小于tags的消息
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
System.out.println(“book------>” + book);
}
System.out.println("----------------->信息域的值" + book);
}
3.6 消费者端去重
我们在生产者保证消息不丢失 中,可以知道,为了保证消息不丢失,生产者会将ack=false的消息重新发送,那么可能会导致消费端的消息重复,那怎么去重?

可以为每一条消息设置一个messageId,用于消费者端的去重。

生产者代码:

@Autowired
private MessageConverter messageConverter;

@Test
public void contextLoads() {
    Map<String, Object> map = new HashMap<>();
    Book book = new Book("西游记", "120.00");
    //使用继承扩展的CorrelationData
    CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());  //消息流水号
    correlationData.setMessage(book);
    correlationData.setExchange("exchange_direct_no");
    correlationData.setRoutingKey("ord");
    ///关键代码
    MessageProperties messageProperties = new MessageProperties();
    //设置messageId
    messageProperties.setMessageId("123456");
    Message message = messageConverter.toMessage(book, messageProperties);
    
    try {
        rabbitTemplate.convertAndSend("exchange_direct", "ord", message, correlationData);
    } catch (AmqpConnectException e) {
        System.out.println("保存信息编号:" + correlationData);
    }
}

消费者代码:

@RabbitListener(queues = “queue_direct”, containerFactory = “singleListenerContainer”, errorHandler = “rabbitListenerErrorHandler”)
public void handleBook(Message message, Book book, Channel channel) throws Exception {

    System.out.println("book------>" + book);
    System.out.println("--------------------->"+message.getMessageProperties().getMessageId());
    //告诉MQ删除这一条消息,若是true,则是删除所有小于tags的消息
    channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    System.out.println("----------------->信息域的值" + book);
}

效果图:
获取消息编号
3.6 多个消费者消费一个queue
若是多个@RabbitListener消费一个queue,那么一个消息只会被一个方法调用。如果RabbitListenerContainerFactory中设置concurrentConsumer为3,意味着每个方法产生3个consumer。也可以分布在不同的应用程序中,那么就会在不同的Connection中。

二. 消费者通过拉(POLL)方式获取消息
可以通过AmqpTemplate或者RabbitMqTemplate拉取消息,当queue没有消息时,会立刻返回null,传入timeoutMillis参数可阻塞等待一段时间。

Message receive() throws AmqpException;

Message receive(String queueName) throws AmqpException;

Message receive(long timeoutMillis) throws AmqpException;

Message receive(String queueName, long timeoutMillis) throws AmqpException;
若是想直接在queue获取到java对象,可以调用receiveAndConvert方法。

测试代码:

@Test
public void receive() {
Object o = rabbitTemplate.receiveAndConvert(“queue_direct”);
System.out.println(o.hashCode());
System.out.println(o);
}
效果图:

我们可以看到,调用这个方法,实际上只是取出一条消息:
poll效果图.png
MQ控制图.png
MQ中消息调用receiveAndConvert效果图:

作者:小胖学编程
链接:https://www.jianshu.com/p/090ed51006d5
来源:简书添加链接描述
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

RabbitMq消息收发详解(转) 的相关文章

  • 过期的消息不会从 RabbitMQ 中删除

    我通过生产者向 RabbitMQ 发送一条普通消息 然后发送第二条消息expiration属性分配给一个值 然后使用rabbitmqctl list queues命令我监视消息的状态 我发现如果我先发送一条普通消息 然后发送一条消息expi
  • 谁能告诉我 python 中的 pika 和 kombu 消息传递库有什么区别?

    我想在我的应用程序中使用消息传递库与rabbitmq交互 谁能解释一下 pika 和 kombu 库之间的区别吗 Kombu 和 pika 是两个不同的 Python 库 它们从根本上服务于相同的目的 向消息代理发布消息和使用消息代理发送消
  • Spring AMQP Java 客户端中的队列大小

    我使用 Spring amqp 1 1 版本作为我的 java 客户端 我有一个大约有 2000 条消息的队列 我想要一个服务来检查这个队列大小 如果它是空的 它会发出一条消息说 所有项目已处理 我不知道如何获取当前队列大小 请帮忙 我用谷
  • 每次发布后我应该关闭通道/连接吗?

    我在 Node js 中使用 amqplib 但我不清楚代码中的最佳实践 基本上 我当前的代码调用amqp connect 当 Node 服务器启动时 然后为每个生产者和每个消费者使用不同的通道 而不会真正关闭它们中的任何一个 我想知道这是
  • RabbitMQ 启动失败

    RabbitMQ Windows 服务将无法启动 C Program Files x86 RabbitMQ Server rabbitmq server 3 0 4 sbin gt rabbitmq service bat start C
  • RabbitMQ - 升级到新版本并收到很多“PRECONDITION_FAILED Unknown Delivery Tag 1”

    刚刚升级到新版本的 RabbitMQ 2 3 1 现在出现以下错误 PRECONDITION FAILED unknown delivery tag 1 随后通道关闭 这适用于较旧的 RabbitMQ 无需客户端更改 在应用程序行为方面 当
  • 如何使用 Celery、RabbitMQ 和 Django 确保每个用户的任务执行顺序?

    我正在运行 Django Celery 和 RabbitMQ 我想要实现的是确保与一个用户相关的任务按顺序执行 具体来说 一次执行一个 我不希望每个用户执行任务并发 每当为用户添加新任务时 它应该取决于最近添加的任务 如果此类型的任务已为此
  • 使用 RabbitMq 锁定和批量获取消息

    我正在尝试以一种更非常规的方式使用 RabbitMq 尽管此时我可以根据需要选择任何其他消息队列实现 消费者不会将 Rabbit 推送消息留给我的消费者 而是连接到一个队列并获取一批 N 条消息 在此期间它会消费一些消息 并可能拒绝一些消息
  • 在 Windows 10 和 PHP 7.3 中安装 AMQP

    我想在 Windows 10 中使用 PHP 7 3 安装 AMQP 以便在 symfony 4 中使用 Windows 不使用任何 apache iis nginx 并直接由 symfony 运行 一切还好 直到 我决定在项目中使用rab
  • RabbitMQ 上的 Nack 和拒绝

    我想处理消费者从队列中获取的不成功的消息并将它们重新排队 想象一下我有这样的情况 P gt foo bar baz gt C 其中 foo bar 和 baz 是消息 如果消费者读到baz但出了问题 我可以使用basic reject or
  • 定义具有多种消息类型的消息传递域

    到目前为止 我见过的大多数 F 消息传递示例都使用 2 4 种消息类型 并且能够利用模式匹配将每条消息定向到其正确的处理函数 对于我的应用程序 由于处理和所需参数的不同性质 我需要数百种独特的消息类型 到目前为止 每个消息类型都是其自己的记
  • Erl 无法连接到本地 EPMD。为什么?

    Erlang R14B04 erts 5 8 5 source 64 bit rq 1 async threads 0 kernel poll false Eshell V5 8 5 abort with G root ip 10 101
  • AMQP如何克服直接使用TCP的困难?

    AMQP如何克服直接使用TCP发送消息时的困难 或者更具体地说 在发布 订阅场景中 在 AMQP 中 有一个代理 该代理接收消息 然后完成将消息路由到交换器和队列的困难部分 您还可以设置持久队列 即使客户端断开连接 也可以为客户端保存消息
  • RabbitMQ 管理插件窗口呈现为空白页面

    I have installed Erlang RabbitMQ and configured the management plugin as per the instructions on the website https www r
  • RabbitMQ - 无法联系统计数据库。消息速率和队列长度将不会显示

    我已经设置了一个兔子经纪人集群 并且在管理门户插件中我收到以下消息 无法联系统计数据库 消息速率和队列长度将不会显示 我已经搜索过这个错误 但谷歌并不友善 任何人都可以阐明这一点吗 我最近在旧安装的RabbitMQ 2 8 7 上遇到了同样
  • RabbitMQ:无法启动rabbitmq_management插件

    Version gt sudo rabbitmqctl status grep rabbit RabbitMQ rabbit RabbitMQ 3 5 6 Error gt sudo rabbitmq plugins enable rabb
  • RabbitMQ 等待消息超时

    我想向 RabbitMQ 服务器发送一条消息 然后等待回复消息 在 回复 队列上 当然 我不想永远等待 以防处理这些消息的应用程序出现故障 需要有一个超时 这听起来像是一项非常基本的任务 但我找不到方法来做到这一点 我现在在使用 Java
  • RabbitMQ 中 Pub/Sub 与工作队列的混合

    我正在评估使用 RabbitMQ 作为消息队列 消息总线 并一直在查看示例教程 https www rabbitmq com getstarted html在 RabbitMQ 页面上 我正在寻找教程中未涵盖的特定场景 并且我不确定是否以及
  • RabbitMq 和“致命错误:握手失败 -handshake_decode_error”

    我正在使用 Windows Server 2012 Erlang 19 2 和 RabbitMq 3 6 6 我在使用 TLS 配置端点之间的连接时遇到问题 我已经尝试了所有关于 SO 的答案 以及所有 RabbitMq 文档here ht
  • PHPUnit RabbitMQ:为创建连接函数编写测试

    我面临以下问题 我编写了一个函数 根据所需参数创建连接对象 AMQPConnection 现在我想编写相应的单元测试 我只是不知道在没有运行 RabbitMQ 代理的情况下如何做到这一点 这是有问题的函数 public function g

随机推荐

  • 表白墙程序

    目录 一 页面代码部分 二 设计程序 二 实现 doPost 编辑 三 实现 doGet 四 前端代码部分 五 使用数据库存储数据 一 页面代码部分 在之前的一篇博客中 已经写过了表白墙的页面代码实现 这里就不再重复了 页面代码如下 div
  • 大数据技术:Spark相关问题汇总

    问题导读 1 Spark有几种部署方式 请分别简要论述 2 Spark任务使用什么方式进行任务提交 3 Spark常用算子reduceByKey与groupByKey的区别 哪一种更具优势 4 简述SparkSQL中RDD DataFram
  • Spring源码(十六)bean实例化过程CreateBeanInstance方法

    Spring源码 十六 bean实例化过程CreateBeanInstance方法 实例化过程以及创建对象的方式 总结 实例化过程以及创建对象的方式 protected Object doCreateBean String beanName
  • java之socket的OOBInline和UrgentData和发送心跳包研究

    UrgentData可以理解为紧急发送数据方式 如果我们客户端先用write方法写入数据 再用UrgentData发送数据 再去执行flush操作 我们可以得到服务端先打印UrgentData发送的数据 然后再打印write写入的数据 客户
  • 注意力提高神经回路的突触功效和信噪比(Farran Briggs, George R. Mangun& W. Martin Usrey)

    注意力是知觉的一个重要组成部分 然而 注意调节神经沟通来指导行为的机制却知之甚少 为了阐明注意力的突触机制 我们开发了一种神经沟通注意调节的敏感测定 在执行视觉空间注意任务的警戒键中 我们通过电刺激丘脑外侧膝状体神经元中的神经元 同时记录来
  • 我为什么鼓励你读计算机博士

    看过 水浒传 的朋友都知道 梁山的一百单八将因为各种理由加入了水寨 走上了劫富济贫 替天行道的路 我2006年从南京大学本科毕业以后 耳闻目睹了数百位计算机专业的博士 生 他们选择读博士的理由可以说比梁山好汉更为复杂 gt gt gt gt
  • 企业运维实战--ELK日志分析平台之elasticsearch实战

    企业运维实战 ELK日志分析平台之elasticsearch实战 ELK日志分析平台 简介 安装elasticsearch elasticsearch集群部署 为集群添加监控管理 监控1 监控2 ELK日志分析平台 简介 ELK由Elast
  • Python 元类实现ORM

    目录 ORM概念 new init call 的介绍 通过元类简单实现ORM中的insert功能 抽取到基类中 ORM概念 ORM Object Ralational Mapping 对象关系映射 用来把对象模型表示的对象映射到基于 SQL
  • 基于51单片机的电烤箱微波炉数码管显示proteus仿真

    硬件设计 MCU基于51单片机 ADC采用TLC2543 芯片简介如下 1 12位分辩率A D转换器 2 在工作温度范围内10 s转换时间 3 11个模拟输入通道 4 3路内置自测试方式 5 采样率为66kbps 6 线性误差 1LSBma
  • 解决Windows提示缺少mfc140.dll文件的问题

    其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题 如果是新手第一时间会认为是软件或游戏出错了 其实并不是这样 其主要原因就是你电脑系统的该dll文件丢失了或者损坏了 这时你只需下载这个mfc140 dll文件进行安装 前提是找到适合
  • Ant Design Vue(2.2.8) 组件样式覆盖 -- 非弹窗和弹窗 -- 全局非全局

    1 简单覆盖 非弹窗 deep 类名 div class deviceFirmManage common box div class search box div div
  • 动态通讯录

    目录 1 修改联系人结构体 2 修改初始化功能 3 增加判断通讯录是否需要扩容 4 修改删除功能 在静态内存的基础之上 我们试着用动态内存开辟空间的方式去修改通讯录 动态通讯录是对静态通讯录的补充 只需要修改部分代码就可行 1 修改联系人结
  • 人工智能中蕴含的情商

    古语云 人之初 性本善 性相近 习相远指的是生于天地之间的为人处事之道 善良并不意味着胆小与懦弱 格物斯坦认为善良的人往往具有较高的情商和组织协调能力 善待世间的一切天地万物 一切是非恩怨 一切明争暗斗 且听吾分析到来 有句话是这样说的 情
  • Building an MFC project for a non-Unicode character set is deprecated

    VS2013多字节工程问题 使用VS2013编译旧版VC 程序时 提示Building an MFC project for a non Unicode character set is deprecated 微软提供了解决方案 一 错误信
  • 关于cmake qmake make makeile之间的关系问题

    总之 qmake是根据 pro文件生成makefile文件 同理cmake是根据CMakeList txt生成的makefile文件 make再根据makefile文件来编译工程文件 来完成 预编译 gt 编译 gt 汇编 gt 链接 中的
  • 使用命令行将Windows上的Git升级到最新版本

    关于Git的命令有很多 这里简单说一下和版本升级有关的几条吧 查看版本信息 git version 在2 14 2和2 16 1之间的版本中 命令是git update 从Git 2 16 1开始 您可以使用git update git f
  • Struts2中关于"There is no Action mapped for namespace / and action name"的总结

    参考 http www cnblogs com gulvzhe archive 2011 11 21 2256632 html 今天在调试一个基础的Struts2框架小程序 总是提示 There is no Action mapped fo
  • 深度学习六、图像风格迁移

    所谓图像风格迁移 是指利用算法学习著名画作的风格 然后再把这种风格应用到另外一张图片上的技术 1 图像风格迁移的原理 在学习原始的图像风格迁移之前 可以先回忆一下ImageNet图像识别模型VGGNet 事实上 可以这样理解VGGNet的结
  • 云学python (第5章对象带你飞之储存 上下文管理器pickle 包)《vamei-从Python开始学编程》 笔记

    2 上下文管理器 文件操作常常和上下文管理器一起使用 上下文管理器 context manager 用于规定某个对象的使用范围 一旦进入或者离开该使用范围 则会有特殊操作被调用 比如为对象分配或者释放内存 下面是一段常规的文件操作程序 常规
  • RabbitMq消息收发详解(转)

    消费者有两种接收消息的方法 poll consumer 即拉模式 消费者主动去消息队列拉取消息 push consumer 即推模式 消息队列主动往消费者推送消息 一 消费者通过推 PUSH 方式获取消息 实现push模式最简单的方式就是使