当前位置: 首页 > 编程日记 > 正文

一个winform带你玩转rabbitMQ

源码已放出 https://github.com/dubing/MaoyaRabbit

本章分3部分

一、安装部署初探

二、进阶

三、api相关


安装 部署 初探

先上图


一. 安装部署

下载 rabbitMQ :http://www.rabbitmq.com/download.html

安装rabbitmq需要erlang,下载erlang:http://www.erlang.org/download.html

按照官网按照步骤,例如windows http://www.rabbitmq.com/install-windows.html

安装完rabbitMQ可以再启动插件扩展,其中包含了一个管理后台

最新版本的后台地址为 http://localhost:15672/

用户名和密码都为guest,输入完成进入主菜单

功能很丰富,可以查看当前服务器的交换机,队列,消息,连接,会话等得使用情况。

基本上到这里服务器的安装部署环节算是ok,很简单。


二.  简介

要了解rabbitMQ 首先要了解AMQP协议 百科上给的很详细 http://baike.baidu.com/view/4023136.htm?fr=aladdin

AMQP 有四个非常重要的概念:虚拟机(virtual host),通道(exchange),队列(queue)和绑定(binding)。

虚拟机: 通常是应用的外在边界,我们可以为不同的虚拟机分配访问权限。虚拟机可持有多个交换机、队列和绑定。
  交换机: 从连接通道(Channel)接收消息,并按照特定的路由规则发送给队列。
  队列: 消息最终的存储容器,直到消费客户端(Consumer)将其取走。
  绑定: 也就是所谓的路由规则,告诉交换机将何种类型的消息发送到某个队列中。

这个概念很重要 不然在学习rabbitmq的地方会碰到很多困难。想要进阶学习的可以参考 https://www.rabbitmq.com/tutorials/amqp-concepts.html

借用官方一个图来阐述AMQP

RabbitMQ是一个消息代理。它的核心原理非常简单:接收和发送消息。

你可以把它想像成一个邮局:你把信件放入邮箱,邮递员就会把信件投递到你的收件人处。在这个比喻中,RabbitMQ是一个邮箱、邮局、邮递员。RabbitMQ和邮局的主要区别是,它处理的不是纸,而是接收、存储和发送二进制的数据——消息。

对于rabbitMQ本身的特点 参考官网 http://www.rabbitmq.com/features.html

1、可靠性(Reliability)
  RabbitMQ提供很多特性供我们可以在性能和可靠性作出折中的选择,包括持久化、发送确认、发布者确认和高可用性等。
  2、弹性选路(Flexible Routing)
  消息在到达队列前通过交换(exchanges)来被选路。RabbitMQ为典型的选路逻辑设计了几个内置的交换类型。对于更加复杂的选路,我们可以将exchanges绑定在一起或者写属于自己的exchange类型插件。
  3、集群化(Clustering)
  在一个局域网内的几个RabbitMQ服务器可以集群起来,组成一个逻辑的代理人。
  4、联盟(Federation)
  对于那些需要比集群更加松散和非可靠连接的服务器来说,RabbitMQ提供一个联盟模型(Federation Model)
  5、高可用队列(High Available Queue)
  可以在一个集群里的几个机器里对队列做镜像,确保即时发生了硬件失效,你的消息也是安全的。
  6、多客户端(Many Clients)
  有各种语言的RabbitMQ客户端
  7、管理UI(Management UI)
  RabbitMQ提供一个易用的管理UI来监控和控制消息代理人的各个方面。
  8、跟踪(Tracing)
  如果你的消息系统行为异常,RabbitMQ提供跟踪支持来找出错误的根源。
  9、插件系统(Plugin System)
  RabbitMQ提供各种方式的插件扩展,我们可以实现自己的插件。

使用任务队列一个优点是能够轻易地并行处理任务。当处理大量积压的任务,只要增加工作队列,通过这个方式,能够实现轻易的缩放。


三. 初探

  文中的winform所采取的client为官方的.net版本 https://github.com/rabbitmq/rabbitmq-dotnet-client

首先是Connection和Channel的概念

Connection 建立与rabbitmq server的一个连接,由ConnectionFactory创建,Channel建立在connection基础上的一个频道,相对于connection来说,它是轻量级的。可以理解成一次会话。

代码示例 本机环境

1
2
3
4
5
6
7
    using (IConnection connection = factory.CreateConnection())
    {
        using (IModel channel = connection.CreateModel())
        {
//do something
        }
    }

exchange常用有三种类型:

Direct :处理路由键。需要将一个队列绑定到交换机上,要求该消息与一个特定的路由键完全匹配。这是一个完整的匹配。
  Fanout :不处理路由键。你只需要简单的将队列绑定到交换机上。一个发送到交换机的消息都会被转发到与该交换机绑定的所有队列上。
  Topic : 将路由键和某模式进行匹配。此时队列需要绑定要一个模式上。符号“#”匹配一个或多个词,符号“*”匹配不多不少一个词。

还有一种多重属性的类型headers,我们在下一章节讨论。

我们用winform分别造成三种类型的exchange来实际体验一下

这里所谓的限定exchange是在我们安装rabbitmq server的时候自动生成的一些 我们的测试不使用这些exchange。

然后我们新建3个Queue,这里我们会发现一个有趣的现象,rabbitmq server对于新生成的队列都会默认绑定在一个名称为“”的默认exchange上。

先试试direct类型,下面我们分别把Q1,Q2,Q3根据路由key为空,k1,k.#绑定在dEx上(direct exchange)。
  

然后我们根据路由key为空,k,k1,k2,k3来发送消息m1,m2,m3,m4,m5
  

再用3个队列接收消息试一下结果
  

因为发送确认标记ack,所以队列上读取过的消息会被删除,为了进一步认证,我在结尾又添加了一个routingkey为k.#的消息(对应绑定Q3),由图可见direct 模式下队列之收取他们完全对应的routingkey消息。

下面我们再试一下fanout类型,把Q1,Q2,Q3根据路由key为空,k1,k.#绑定在fEx上(fanout exchange)。


  同上步骤建立绑定关系

生产消息,然后看下队列接受消息的情况
  

效果很明显,fanout为广播模式。

再试试topic类型 把Q1,Q2,Q3根据路由key为空,k1,k.#绑定在tEx上(topic exchange)。

推送消息
  

接收消息
  
  通过3种模式 3个队列的消息读取 大家应该了解了这3中模式的区别。


进阶

一.  exchange属性

Type

前一章我们说了exchange的类型分为fanout,direct,topic.还有一种不常用的headers。
  headers这种类型的exchange绑定的时候会忽略掉routingkey,Headers是一个键值对,可以定义成成字典等。发送者在发送的时候定义一些键值对,接收者也可以再绑定时候传入一些键值对,两者匹配的话,则对应的队列就可以收到消息。匹配有两种方式all和any。这两种方式是在接收端必须要用键值"x-mactch"来定义。all代表定义的多个键值对都要满足,而any则代码只要满足一个就可以了。之前的几种exchange的routingKey都需要要字符串形式的,而headers exchange则没有这个要求,因为键值对的值可以是任何类型
  举个例子,发送端定义2个键值{k1,1},{k2,2},接收端绑定队列的时候定义{"x-match", "any"},那么接收端的键值属性里只要存在{k1,1}或{k2,2}都可以获取到消息。
  这样的类型扩展的程度很大,适合非常复杂的业务场景。

Durability

持久性,这是exchange的可选属性,如果你Durability设置为false,那些当前会话结束的时候,该exchange也会被销毁。 
  新建一个transient exchange 
  
  关闭当前连接再查看一下
  

刚才我们新建的transient已经销毁了。

Auto delete

  当没有队列或者其他exchange绑定到此exchange的时候,该exchange被销毁。这个很简单就不示例了。

Internal (比较简单 也不展示了)

  表示这个exchange不可以被client用来推送消息,仅用来进行exchange和exchange之间的绑定。

PS: 无法声明2个名称相同 但是类型却不同的exchange


二.  Queue属性  

  Durability 和exchange相同,未持久化的队列,服务重启后销毁。

Auto delete 当没有消费者连接到该队列的时候,队列自动销毁。

Exclusive 使队列成为私有队列,只有当前应用程序可用,当你需要限制队列只有一个消费者,这是很有用的。

扩展属性如下对应源程序 RabbitMQ.Client.IModel.QueueDeclare(string, bool, bool, bool, System.Collections.Generic.IDictionary<string,object>)最后的参数

Message TTL 当一个消息被推送在该队列的时候 可以存在的时间 单位为ms,(对应扩展参数argument "x-message-ttl" )

Auto expire 在队列自动删除之前可以保留多长时间(对应扩展参数argument "x-expires")

Max length 一个队列可以容纳的已准备消息的数量(对应扩展参数argument "x-max-length")

... 更多参考 http://www.rabbitmq.com/extensions.html

ps:一旦创建了队列和交换机,就不能修改其标志了。例如,如果创建了一个non-durable的队列,然后想把它改变成durable的,唯一的办法就是删除这个队列然后重现创建。


三.  Message属性

  Durability 

  消息的持久在代码中设置的方法与exchange和queue不同,有2种方法

1.

1
2
3
4
IBasicProperties properties = channel.CreateBasicProperties();
properties.SetPersistent(true);
byte[] payload = Encoding.ASCII.GetBytes(message);
channel.BasicPublish(exchange.name, txtMessageRoutingKey.Text.Trim(), properties, payload);

2.

1
2
3
4
IBasicProperties properties = channel.CreateBasicProperties();
properties.DeliveryMode = 2;
byte[] payload = Encoding.ASCII.GetBytes(message);
channel.BasicPublish(exchange.name, txtMessageRoutingKey.Text.Trim(), properties, payload);

contentType: 标识消息内容的MIME,例如JSON用application/json

replayTo: 标识回调的queue的地址

correlationId:用于request和response的关联,确保消息的请求和响应的同一性

Message的2种状态:

Ready

此状态的消息存在于队列中待处理。

Unacknowledged

  此状态的消息表示已经在处理未确认。

说到Unacknowledged,这里需要了解一个ack的概念。当Consumer接收到消息、处理任务完成之后,会发送带有这个消息标示符的ack,来告诉server这个消息接收到并处理完成。RabbitMQ会一直等到处理某个消息的Consumer的链接失去之后,才确定这个消息没有正确处理,从而RabbitMQ重发这个消息。
  Message acknowledgment是默认关闭的。初始化Consumer时有个noAck参数,如果设置为true,这个Consumer在收到消息之后会马上返回ack。

string BasicConsume(string queue, bool noAck, RabbitMQ.Client.IBasicConsumer consumer)

一般来说,常用的场景noack一般就是设置成true,但是对于风险要求比较高的项目,例如支付。对于每一条消息我们都需要保证他的完整性和正确性。就需要获取消息后确认执行完正确的业务逻辑后再主动返回一个ack给server。可以通过rabbitmqctl list_queues name message_rady message_unacknowleded 命令来查看队列中的消息情况,也可以通过后台管理界面。

我们先hold住一条消息

然后我们再关闭链接或者重启服务


  数据还是完整的。

ps:message的消费还分为consume和baseget 下面讲到集群的时候再介绍。


四.  binding相关

如果你绑定了一个durable的队列和一个durable的交换机,RabbitMQ会自动保留这个绑定。类似的,如果删除了某个队列或交换机(无论是不是 durable),依赖它的绑定都会自动删除。

在声明一个队列的同时,server会默认让此队列绑定在默认的exchange上,这个exchange的名称为空。


五.  发布订阅

我们上一章的demo中实际上已经使用了发布订阅模式。

RabbitMQ消息模型的核心理念是:发布者(producer)不会直接发送任何消息给队列。事实上,发布者(producer)甚至不知道消息是否已经被投递到队列。发布者(producer)只需要把消息发送给一个exchange。exchange非常简单,它一边从发布者方接收消息,一边把消息推入队列。exchange必须知道如何处理它接收到的消息,是应该推送到指定的队列还是是多个队列,或者是直接忽略消息。这些规则是通过exchange type来定义的。



  发布订阅其实很简单,例如上章我所示例,假设我们一开始没有任何消息,现在有一个生产者P1,他是一个天气预报播放者。然后我们有2个消费者来订阅他的消息。
  P1通过广播类型的交换机fEx来发布他的天气消息,c1,c2分别建立一个队列为Q1,Q2. 并且订阅P1的fEx.

基本可以如图所示
  
  我们P1利用fEx生成一条消息的时候,c1,c2通过Q1,Q2都可以获取到p1所发布的消息

我们发布3条消息
  
  查看队列情况
  Q1:
  
  Q2:

Q1,Q2都拿到了广播的消息,至于C1,C2如何消费这些消息,互相之间完全没有干扰。

ps:简单一句话 发布订阅中发布者所产生的消息通过exchange对所有绑定他的队列队形消息推送,每个队列获取绑定所对应的消息


六.  WorkQueue (可用于消费者集群)

区分于发布订阅,消费者集群主要解决横向服务器扩展问题,如果一个队列积压太多,如何均与的让不同的消费者来承担。

默认来说,RabbitMQ会按顺序得把消息发送给每个消费者(consumer)。平均每个消费者都会收到同等数量得消息。这种发送消息得方式叫做——轮询(round-robin)。

我们开3个程序,1个生产 2个消费。

如图所示绑定关系如下

2个消费者用同样的程序,这里记录进程pid以区分,实际项目中可以用不同服务器来区分

启动消息消费,使消费者处理work状态

然后我们不停的通过生产者这发布消息

然后我们看下2个消费者的消费情况

1.

2.
  

3.
  

4.
  

5.
  

默认地,RabbitMQ会逐一地向下一个Consumer发放消息,每一个Consumer会得到数目相同的消息。文中所示之所以是按照1条一条的轮询,是因为程序中控制了一个队列单次消费的数量。

void BasicQos(uint prefetchSize, ushort prefetchCount, bool global)


API CommandLine 以及其他功能

RabbitMQ API

RabbitMQ Server提供了丰富的http api。

举个列子

需要HTTP基本身份验证。默认的用户名/密码为guest/guest。

这些返回值得意义我从官网搬来解释,为了避免翻译的问题导致大家理解的误差这里直接给出原文

cluster_nameThe name of the entire cluster, as set with rabbitmqctl set_cluster_name.
erlang_full_versionA string with extended detail about the Erlang VM and how it was compiled, for the node connected to.
erlang_versionA string with the Erlang version of the node connected to. As clusters should all run the same version this can be taken as representing the cluster.
exchange_typesA list of all exchange types available.
listenersAll (non-HTTP) network listeners for all nodes in the cluster. (See contexts in /api/nodes for HTTP).
management_versionVersion of the management plugin in use.
message_statsA message_stats object for everything the user can see - for all vhosts regardless of permissions in the case of monitoring and administrator users, and for all vhosts the user has access to for other users.
nodeThe name of the cluster node this management plugin instance is running on.
object_totalsAn object containing global counts of all connections, channels, exchanges, queues and consumers, subject to the same visibility rules as for message_stats.
queue_totalsAn object containing sums of the messagesmessages_ready and messages_unacknowledged fields for all queues, again subject to the same visibility rules as for message_stats.
rabbitmq_versionVersion of RabbitMQ on the node which processed this request.
statistics_db_nodeName of the cluster node hosting the management statistics database.
statistics_levelWhether the node is running fine or coarse statistics.

又或者通过api查询虚拟主机
  
  许多api的URI需要一个虚拟主机路径的一部分的名字,因为名字只有唯一在一个虚拟主机识别物体。作为默认的虚拟主机称为“/”,这​​将需要被编码为“%2F”。

在我的demo程序中对应的api功能可以通过这里的功能来实现

其更丰富的功能可以参考官网说明文档 http://hg.rabbitmq.com/rabbitmq-management/raw-file/3646dee55e02/priv/www-api/help.html

以及 http://hg.rabbitmq.com/rabbitmq-management/raw-file/rabbitmq_v3_3_5/priv/www/api/index.html

一般来说我们常用的我在应用程序中已经给出 例如查看所有队列等


RabbitMQ CommandLine

除了丰富的http api,rabbitmq server自然也有其很全面命令行。

例如查询所有exchange。

查询所有队列以及他们包含的消息数目

rabbitmqctl更多的命令说明参考 http://www.rabbitmq.com/man/rabbitmqctl.1.man.html


Message的BasicGet于consume的区别

consume的功能上一张介绍过,basicget更偏向于我们平时用过的其他类型的MessageQueue,它就是最基本的接受消息,consume的消费针对basicget来说属于一个长连接于短连接的区别。

消费者关系一旦确定,基本上默认它就是在侦听通道的消息是否在生产。而basicget则是由客户端手动来控制。

在demo中在下图所示处区分

如果你选择了消费消息,那么基本上代码层面是这样来完成的

1
2
3
4
5
6
7
8
9
var consumer = new QueueingBasicConsumer(channel);
channel.BasicQos(0, 1, false);
channel.BasicConsume(queue.name, rbAckTrue.Checked, consumer);
while (true)
{
    var e = consumer.Queue.Dequeue();
    MessageBox.Show(string.Format("队列{0}获取消息{1},线程id为{2}", queue.name, Encoding.ASCII.GetString(e.Body), Process.GetCurrentProcess().Id));
    Thread.Sleep(1000);
}

本篇先到此,希望对大家有帮助

转载于:https://www.cnblogs.com/zwb7926/p/6029196.html

相关文章:

03-dispatch_after

1 dispatch_after 概念 在指定时间之后将任务追加到主队列中。严格来说&#xff0c;这个时间并不是绝对准确的&#xff0c;但想要大致延迟执行任务&#xff0c;dispatch_after函数是很有效的。 NSLog("currentThread---%",[NSThread currentThread]); // 打印当前线…

C#模糊查询绑定datagridview

private CollectionViewSource wgdData new CollectionViewSource(); private DataTable Ds_wgd { get { return this.dgv_wgd.ItemsSource as DataTable; } set { wgdData.Source value; this.dgv_wgd.ItemsSource ((DataTable)wgdData.Source).DefaultView; } } //文本框修…

今日头条反爬措施形同虚设,论多平台协同在安全方面的重要性

点击上方↑↑↑蓝字[协议分析与还原]关注我们“ 玩头条练技能。”大家好&#xff0c;看到标题一定猜到了&#xff0c;我又来玩今日头条了&#xff0c;谁让它是东半球文明的杀时间神器呢。 想当年&#xff0c;头条刚问世&#xff0c;正愁长辈看新闻没合适且方便的工具&#xff0…

ueditor编辑器和at.js集成

源码&#xff1a; <% page language"java" import"java.util.*" pageEncoding"UTF-8"%> <%//禁止jsp解析${} %> <% page isELIgnored"true"%> <%String path request.getContextPath();String basePath reques…

Java缓存学习之五:spring 对缓存的支持

&#xff08;注意标题&#xff0c;Spring对缓存的支持 这里不单单指Ehcache &#xff09;   从3.1开始&#xff0c;Spring引入了对Cache的支持。其使用方法和原理都类似于Spring对事务管理的支持。Spring Cache是作用在方法上的&#xff0c;其核心思想是这样的&#xff1a;当…

04-dispatch_group

dispatch_group 实现线程同步 比如说&#xff0c;第一步我想先下载三张图片&#xff0c;然后第二步再去主线程刷新imgview 显示图片。 利用dispatch_group 来进行实现 &#xff0c;简单来讲就四行代码. 就可以让代码按照你想要的顺序进行发生。 使用步骤 创建一个dispatch_g…

fiddler教程:抓包带锁的怎么办?HTTPS抓包介绍。

点击上方↑↑↑蓝字[协议分析与还原]关注我们“ 介绍Fiddler的HTTPS抓包功能。” 这里首先回答下标题中的疑问&#xff0c;fiddler抓包带锁的原因是HTTPS流量抓包功能开启&#xff0c;但解密功能未开启导致&#xff0c;只需要将HTTPS流量解密功能开启就能解决问题。01—作为一款…

如何实现后台向前台传数据

技术交流群&#xff1a;233513714 这两天正在研究如何让后天主动向前台展现数据&#xff0c;只要后台有数据上传的时候就向前台上传(因为公司有个项目&#xff0c;硬件设备会不断的上传数据&#xff0c;服务端将接收到的数据向前台展示)。在网上查了一下&#xff0c;下面将介绍…

05-dispatch_semphore

dispatch_semphore 信号量 dispatch_semaphore信号量为基于计数器的一种多线程同步机制。如果semaphore计数大于等于1&#xff0c;计数-1&#xff0c;返回&#xff0c;程序继续运行。如果计数为0&#xff0c;则等待。dispatch_semaphore_signal(semaphore)为计数1操作,dispatc…

[leetcode]_Integer to Roman

题目&#xff1a;对应之前那道将罗马数字转换整型数字的题目。反过来。 思路&#xff1a;刚开始做的时候&#xff0c;想着用程序进行判断&#xff0c;复杂的要死。网络了别人代码&#xff0c;非常清晰。 代码&#xff1a; 1 public String intToRoman(int num) {2 S…

fiddler使用技巧进阶,如何抓包修改数据?——AutoResponder重定向

“ 介绍Fiddler的AutoResponder重定向功能。” Fiddler功能十分强大&#xff0c;既能抓取报文&#xff0c;也能构造报文&#xff0c;本文继续介绍fiddler的功能&#xff0c;这次的功能与构造报文相关&#xff0c;用来回答标题中的疑问&#xff0c;即修改数据的方法&#xff0c;…

nginx基于IP的虚拟主机

知识点&#xff1a; server的语法&#xff1a; upstream语法&#xff1a; upstream中192.168.100.1不是ip只是个标识&#xff0c;只要和下面的proxy_pass 对应即可。 基于IP的虚拟主机&#xff1a; listen和server_name中多加上端口也没问题 listen可以监听在虚拟ip上面 代码&a…

读《人月神话》所感

《人月神话》 读书心得&#xff1a;因为现在还是学生&#xff0c;且没有什么真正在应用项目的开发经验&#xff0c;所以读《人月神话》这本书&#xff0c;与其说是在学习这位计算机先驱的经验&#xff0c;不如说是在了解一个大型软件系统的开发过程以及在开发过程中将会遇到的…

Android逆向之调试smali代码基础

点击上方↑↑↑蓝字[协议分析与还原]关注我们 “ 介绍Android逆向中调试smali代码的方法。” 最近在重整Android逆向分析环境&#xff0c;一切都在从零开始&#xff0c;做下记录&#xff0c;给大家分享。 本文介绍Android逆向中smali代码的调试及环境的准备。 事先准备如下工具…

Python之路【第五篇】:面向对象及相关

Python之路【第五篇】&#xff1a;面向对象及相关 Python之路【第五篇】&#xff1a;面向对象及相关 面向对象基础 基础内容介绍详见一下两篇博文&#xff1a; 面向对象初级篇面向对象进阶篇其他相关 一、isinstance(obj, cls) 检查是否obj是否是类 cls 的对象 123456class Foo…

关于安卓版的eclipse连接数据库并誓言增删改查

在安卓环境下连接数据库下面是主要代码极其作用&#xff1a; 1.编写 The Class类把课程表courses.db当做一个实体类&#xff0c;hashcode和equals这两个类是为了判断输入的查询内容和Excel表中的内容是否一致。 并在java里面区别两个对象是否一致 1 public class TheClass {2 …

07-主队列和全局队列

GCD 会主动的提供一个队列供开发者使用。 主队列 系统提供的串行队列 是在主线程执行的队列&#xff0c;所以是串行的队列。任务一个个执行。 dispatch_get_main_queue() 全局队列 系统提供的并发队列 全局队列是所有应用程序都能够使用的并发队列&#xff0c;不需要手动的创…

Android逆向--如何调试smali代码?

最近在重整Android逆向分析环境&#xff0c;一切都在从零开始&#xff0c;做下记录&#xff0c;给大家分享。 本文介绍Android逆向中smali代码的调试及环境的准备。 事先准备如下工具&#xff1a; Android killer&#xff1a;反编译APK应用为smali源码的工具 Android studi…

python -socket -client

socket client 发起连接。 流程为&#xff1a; 创建接口 发起连接 创建接口参数同socket server相同 发起连接的函数为socket.connect(ip,port) 这个地方的ip与port为socket server端的ip和监听port。 代码示例&#xff1a; # -*- coding: utf-8 -*-This is a testing program …

mysql的binlog太多太大占用了空间的解决办法

现象&#xff1a;网站访问越来越慢&#xff0c;最后无法访问了&#xff0c;经过检查发现磁盘满了 分析过程及解决方案&#xff1a;通常出现这种问题都应该登录服务器检查磁盘、内存和进程使用的情况&#xff0c;通过top、df –h和free –m来检查&#xff0c;发现磁盘空间满了。…

08-dispatch_apply

1 dispatch_apply dispatch_apply 是按照指定的次数将指定的block 添加到指定的queue当中去。 可以用于快速的迭代 // 获取全局并发队列dispatch_queue_t queue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);// 迭代数组NSLog("begin");NSArra…

记一次知乎维权过程——严肃批评某非法引流商

“ 我的文章被人盗版了。” 首先请关注本号的云技术君的马甲赶快取关&#xff0c;这里不欢迎你&#xff0c;你如果再抄我的文章去干坏事&#xff0c;你全家得新冠肺炎。 文章被盗版&#xff0c;被洗稿&#xff0c;且用来给菠菜党引流&#xff0c;我很生气。 好了&#xff0c…

《代码大全2》读后感czz

经老师推荐&#xff0c;买了一本《代码大全2》&#xff0c;花了近3个月的时间看完了&#xff0c;看完后觉得还有很多值得回味的地方&#xff0c;而且每部分之后作者还推荐了不少经典书籍。所以&#xff0c;作个读书心得。全书的主题是软件构建&#xff0c;关于软件构建问题的方…

09-dispatch_source

dispatch_source 是BSD系内核惯有的kqueue的包装&#xff0c;kqueue 是XNU内核中发生各种事件时&#xff0c;在应用程序编程中执行处理的技术。 CPU 负荷非常小&#xff0c;尽量不占用资源。 dispatch_queue 和dispatch_source dispatch_source 是可以取消的&#xff0c;取…

如何获取boss直聘搜索牛人被屏蔽的姓名

点击上方↑↑↑蓝字[协议分析与还原]关注我们“ 玩玩boss直聘。”最近在用boss直聘&#xff0c;活跃度估计蛮高的。在使用牛人搜索的时候&#xff0c;却遇到了一个问题&#xff0c;就是搜出的牛人姓名是被屏蔽的&#xff0c;让我很是焦虑&#xff0c;虽然知道这种设计是直聘推广…

【Python之路】第二篇--初识Python

Python简介 Python可以应用于众多领域&#xff0c;如&#xff1a;数据分析、组件集成、网络服务、图像处理、数值计算和科学计算等众多领域。目前业内几乎所有大中型互联网企业都在使用Python&#xff0c;如&#xff1a;Youtube、Dropbox、BT、Quora&#xff08;中国知乎&…

如何实现phpcms v9_4X版本tag的伪静态?

这两个月来写的文章越来越少了&#xff0c;不是懒&#xff0c;因为太忙了--为客户赶做网站。因为客户指定要使用phpcms v9,还要求使用phpcms v9_42版本实现tag伪静态&#xff0c;在接手的时候phpcms v9_42是最新版本&#xff0c;而现在phpcms官方已经发布phpcms v9_5.X了。对于…

OC对象内存布局

OC对象的内存布局 1 每一个实例对象&#xff08;Instance&#xff09;内部都有一个isa指针&#xff0c;指向它的类对象&#xff0c;类对象存放着本对象的实例方法列表和成员变量列表。 2 类对象(Class)内部也有一个isa指针指向元类对象(MetaClass)&#xff0c;元类对象存放的事…

连信的protobuf数据格式

点击上方↑↑↑蓝字[协议分析与还原]关注我们“ 连信里用到的protobuf结构。”在看本文之前&#xff0c;可以先进行一下回顾&#xff0c;之前已经对协议的框架进行了整体的介绍&#xff1a;连信协议整体框架看了后结合自己的分析过程&#xff0c;应该有个初步的了解。后续会陆续…

fileupload控件在ajax中无法使用

google得到的方法&#xff1a;1。http://geekswithblogs.net/ranganh/archive/2008/04/01/file-upload-in-updatepanel-asp.net-ajax.aspxThere is a better way of doing it with Ajax Control Toolkit version 3.0.30930 which works with .NET 3.5 SP1 and Visual Studio 20…