网络编程之python zeromq学习系列之一
简介:
zeromq中间件,他是一个轻量级的消息中间件,传说是世界上最快的消息中间件,为什么这么说呢?
因为一般的消息中间件都需要启动消息服务器,但是zeromq这厮尽然没有消息服务器,他压根没有消息中间件的架子,但是这并不能掩盖他的强大。
通过和activemq,rabbitmq对比,显然功能上没有前两者这么强大,他不支持消息的持久化,但是有消息copy功能,他也不支持崩溃恢复,而且由于他太快了,可能客户端还没启动,服务端的消息就已经发出去了,这个就容易丢消息了,但是zeromq自由他的办法,就先说这么多了。先来看看怎么在python中引入这个强大的利器。
我自己之所以,学习体会一下,主要原因,是想在练习过程中体会其中的应用原理及逻辑,最好是能感知到其中的设计思想,为以后,自己做东西积攒点经验.
另外最近也比较关注自动化运维的一些东西.网上说saltstack本身就用的zeromq做消息队列.所以更引起了我的兴趣.
安装:
我的操作系统是ubuntu 14.04的 python zeromq 环境安装参考这里的官网
下面测试:
一,C/S模式:
server 端代码:
#!/usr/bin/env python
# coding:utf8
#author: wangqiankun@lashou-inc.com
import zmq
#调用zmq相关类方法,邦定端口
context = zmq.Context()
socket = context.socket(zmq.REP)
socket.bind('tcp://*:10001')
while True:
#循环接受客户端发来的消息
msg = socket.recv()
print "Msg info:%s" %msg
#向客户端服务器发端需要执行的命令
cmd_info = raw_input("client cmd info:").strip()
socket.send(cmd_info)
socket.close()
client 端代码:
import zmq
import time
import commands
context = zmq.Context()
socket = context.socket(zmq.REQ)
socket.connect('tcp://127.0.0.1:10001')
def execut_cmd(cmd):
s,v = commands.getstatusoutput(cmd)
return v
while True:
#获取当前时间
now_time = time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())
socket.send("now time info:[%s] request execution command:'\n',%s"%(now_time,result))
recov_msg = socket.recv()
#调用execut_cmd函数,执行服务器发过来的命令
result = execut_cmd(recov_msg)
print recov_msg,'\n',result,
time.sleep(1)
#print "now time info:%s cmd status:[%s],result:[%s]" %(now_time,s,v)
continue
socket.close()
注意:此模式是经典的应答模式,不能同时send多个数据,
这种模式说是主要用于远程调用和任务分配,但我愚笨,还是理解不透.后面有时间,再回过来好好看看,
测试:
req端
# python zmq-server-cs-v01.py
rep端
# python zmq-client-cs-v01.py
二,发布订阅模式(pub/sub)
pub 发布端代码如下:
#!/usr/bin/env python
# coding:utf8
#author: wangqiankun@lashou-inc.com
import itertools
import sys,time,zmq
def main():
if len(sys.argv) != 2:
print 'Usage: publisher'
sys.exit(1)
bind_to = sys.argv[1]
all_topics = ['sports.general','sports.football','sports.basketball','stocks.general','stocks.GOOG','stocks.AAPL','weather']
ctx = zmq.Context()
s = ctx.socket(zmq.PUB)
s.bind(bind_to)
print "Starting broadcast on topics:"
print "%s" %all_topics
print "Hit Ctrl-c to stop broadcasting."
print "waiting so subscriber sockets can connect...."
print
time.sleep(1)
msg_counter = itertools.count()
try:
for topic in itertools.cycle(all_topics):
msg_body = str(msg_counter.next())
#print msg_body,
print 'Topic:%s,msg:%s' %(topic,msg_body)
s.send_multipart([topic,msg_body])
#s.send_pyobj([topic,msg_body])
time.sleep(0.1)
except KeyboardInterrupt:
pass
print "Wating for message queues to flush"
time.sleep(0.5)
s.close()
print "Done"
if __name__ == "__main__":
main()
sub 端代码:
#!/usr/bin/env python
# coding:utf8
#author: wangqiankun@lashou-inc.com
import zmq
import time,sys
def main():
if len(sys.argv) < 2:
print "Usage: subscriber [topic topic]"
sys.exit(1)
connect_to = sys.argv[1]
topics = sys.argv[2:]
ctx = zmq.Context()
s = ctx.socket(zmq.SUB)
s.connect(connect_to)
#manage subscriptions
if not topics:
print "Receiving messages on ALL topics...."
s.setsockopt(zmq.SUBSCRIBE,'')
else:
print "Receiving messages on topics: %s..." %topics
for t in topics:
s.setsockopt(zmq.SUBSCRIBE,t)
print
try:
while True:
topics,msg = s.recv_multipart()
print 'Topic:%s,msg:%s' %(topics,msg)
except KeyboardInterrupt:
pass
print "Done...."
if __name__ == "__main__":
main()
注意:
这里的发布与订阅角色是绝对的,即发布者无法使用recv,订阅者不能使用send,官网还提供了一种可能出现的问题:当订阅者消费慢于发布,
此时就会出现数据的堆积,而且还是在发布端的堆积(有朋友指出是堆积在消费端,或许是新版本改进,需要读者的尝试和反馈,thx!),显然,
这是不可以被接受的。至于解决方案,或许后面的"分而治之"就是吧
测试:
pub端: 发布端
#python zmq-server-pubsub-v02.py tcp://127.0.0.1:10001
sub端:订阅端
#python zmq-server-cs-v01.py tcp://127.0.0.1:10001 sports.football
三,push/pull 分而治之模式.
任务发布端代码
#!/usr/bin/env python
# coding:utf8
#author: wangqiankun@lashou-inc.com
import zmq
import random
import time
context = zmq.Context()
#socket to send messages on
sender = context.socket(zmq.PUSH)
sender.bind('tcp://*:5557')
print 'Press Enter when the workers are ready:'
_ = raw_input()
print "Sending tasks to workers...."
#The first messages is "0" and signals start to batch
sender.send('0')
#Initialize random mumber generator
random.seed()
#send 100 tasks
total_msec = 0
for task_nbr in range(100):
#Random workload from 1 to 100 msecs
#print task_nbr,
workload = random.randint(1,100)
total_msec += workload
sender.send(str(workload))
print "Total expected cost:%s msec:%s workload:%s" %(total_msec,task_nbr,workload)
work端代码如下:
#!/usr/bin/env python
# coding:utf8
#author: wangqiankun@lashou-inc.com
import sys,time,zmq
import commands
context = zmq.Context()
#socket to receive messages on
receiver = context.socket(zmq.PULL)
receiver.connect('tcp://127.0.0.1:5557')
#Socket to send messages to
sender = context.socket(zmq.PUSH)
sender.connect("tcp://127.0.0.1:5558")
#Process tasks forever
while True:
s = receiver.recv()
#Simple progress indicator for the viewer
print s,
sys.stdout.write("%s '\t' "%s)
sys.stdout.flush()
#Do the work
time.sleep(int(s)*0.001)
#Send results to sink
sender.send(s)
pull端代码如下:
#!/usr/bin/env python
# coding:utf8
#author: wangqiankun@lashou-inc.com
import sys
import time
import zmq
context = zmq.Context()
#Socket to receive messages on
receiver = context.socket(zmq.PULL)
receiver.bind("tcp://*:5558")
#Wait for start of batch
s = receiver.recv()
#Start our clock now
tstart = time.time()
#Process 100 confirmations
total_msec = 0
for task_nbr in range(100):
s = receiver.recv()
if task_nbr % 10 == 0:
print task_nbr,
print s,
sys.stdout.write(':')
else:
print s,
#print task_nbr,
sys.stdout.write('.')
#Calculate and report duration of batch
tend = time.time()
print "Total elapsed time:%d msec "%((tend-tstart)*1000)
注意点:
这种模式与pub/sub模式一样都是单向的,区别有两点:
1,该模式下在没有消费者的情况下,发布者的信息是不会消耗的(由发布者进程维护)
2,多个消费者消费的是同一列信息,假设A得到了一条信息,则B将不再得到
这种模式主要针对在消费者能力不够的情况下,提供的多消费者并行消费解决方案(也算是之前的pub/sub模式的
那个"堵塞问题"的一个解决策略吧)
其实所谓的分就是pull端去抢push端发出来的任务.谁抢着算谁的.
测试:
#python zmq-server-pushpull-v03.py
#python zmq-work-pushpull-v03.py
#python zmq-client-pushpull-v03.py
网络编程之python zeromq学习系列之一的更多相关文章
- Python网络编程之TCP套接字简单用法示例
Python网络编程之TCP套接字简单用法示例 本文实例讲述了Python网络编程之TCP套接字简单用法.分享给大家供大家参考,具体如下: 上学期学的计算机网络,因为之前还未学习python,而jav ...
- unix下网络编程之I/O复用(三)
poll函数 在上文unix下网络编程之I/O复用(二)中已经介绍了select函数的相关使用,本文将介绍另一个常用的I/O复用函数poll.poll提供的功能与select类似,不过在处理流设备时, ...
- 网络编程之C10K
网络编程之C10K 虽然在过去的十几年里C10K问题已经可以很好的解决,但学习网络编程时研究C10K问题仍然价值巨大,因为技术的发展都是有规律和线索可循的,了解C10K问题及其解决思路,通过举一反三, ...
- 网络编程之socket
网络编程之socket socket:在网络编程中的一个基本组件,也称套接字. 一个套接字就是socket模块中的socket类的一个实例. 套接字包括两个: 服务器套接字和客户机套接字 套接字的实例 ...
- python3网络编程之socketserver
本节主要是讲解python3网络编程之socketserver,在上一节中我们讲到了socket.由于socket无法支持多用户和多并发,于是就有了socket server. socket serv ...
- 网络编程之socketserver
网络编程之socketserver """ socketserver.py 中的5个基础类 +------------+ | BaseServer | +-------- ...
- 网络编程之socketserver初识
网络编程之socketserver初识 Server #!/usr/bin/env python # @Author : "Wjl" # @Date : 2017/12/22 # ...
- Java网络编程之UDP
Java网络编程之UDP 一.C/S架构中UDP网络通信流程 ①创建DatagramSocket与DatagramPacket对象 ②建立发送端,接收端 ③建立数据包 ④调用Socket的发送.接收方 ...
- Java网络编程之URLConnection
Java网络编程之URLConnecton 一.URLConnection简介 URLConnection是一个抽象类,表示指向URL指定资源的活动连接.URLConnection有两个不同但相关的用 ...
随机推荐
- __weak与__block修饰符区别
API Reference对__block变量修饰符的解释,大概意思: 1.__block对象在block中是可以被修改.重新赋值的. 2.__block对象在block中不会被block强引用一次, ...
- 笔记:EF出现列名 'Discriminator' 无效、类没有加入数据库上下文也被数据迁移生成表
笔记: EF出现列名 'Discriminator' 无效: 类没有加入数据库上下文也被数据迁移生成表: 出现该问题一般是使用了某个基类继承了实体类: 原因是code first的POCO实体对象的继 ...
- vue中的数据双向绑定
学习的过程是漫长的,只有坚持不懈才能到达到自己的目标. 1.vue中数据的双向绑定采用的时候,数据劫持的模式.其实主要是用了Es5中的Object.defineProperty;来劫持每个属性的get ...
- Java如何查看死锁?
转载自 https://blog.csdn.net/u014039577/article/details/52351626 Java中当我们的开发涉及到多线程的时候,这个时候就很容易遇到死锁问题,刚开 ...
- foo()与@foo()的区别
1.@foo() 是错误控制输出,foo()是正常调用输出. 2.@符号在PHP 中可以忽略错误报告,对于表达式有提示错误的,但有不影响语句执行的,可以在表达式之前加@. 3.可以把@符号放在变量.函 ...
- APP接口
<?phpClass Response{ /*** 返回json数据* @param $code 状态码* @param $message 描述信息* @param $data 数据* @par ...
- Spring Boot 推荐的 Java 配置
在学 Spring 的过程中 , 配置文件慢慢的被注解所替代 , 现在 Spring Boot 更是推荐使用 Java 配置完全来代替配置文件 . 需要使用到的注解有 : Bean 相关 : @Con ...
- mybatis的setting
在mybaits中,setting的的配置参数如下(如果不在配置文件中配置将使用默认值): 设置参数 描述 有效值 默认值 cacheEnabled 该配置影响的所有映射器中配置的缓存的全局开关 tr ...
- HDU4436_str2int
很好的一个题目.对于理解后缀自动机很有用. 题目给你若干数字串,总长度不超过100000,任意一个串的任意一个子串都可以拿出来单独的作为一个数字.同一个数字只算一次. 问所有不同数字的和为多少? 嗯嗯 ...
- django中使用FastDFS分布式文件系统接口代码实现文件上传、下载、更新、删除
运维使用docker部署好之后FastDFS分布式文件系统之后,提供给我接口如下: fastdfs tracker 192.168.1.216 192.168.1.217 storage 192.16 ...