aardio 官方社区

 找回密码
 注册会员

QQ登录

只需一步,快速开始

搜索
查看: 22656|回复: 6

nnmsg扩展库(nanomsg 消息通信组件)

  [复制链接]

166

主题

2154

回帖

1万

积分

管理员

积分
13056
发表于 2017-12-7 19:07:48 | 显示全部楼层 |阅读模式
nanomsg 是一个开源的消息通信组件。

nanomsg 项目官方基本上放弃维护了,不建议继续使用这个组件。
我当时写这个扩展库的时候就发现随便发一个消息 nanomsg 就会直接崩溃(所以我用 WebSocket 写的那个客户端禁用了发送按钮),
过了很多年以后升级了一下,发现问题还是没有修复,而且还出现了更多问题。

开发工具解决不了编程中遇到的所有问题以及所有第三方组件可能存在的问题,
甚至是这些第三方组件的作者都无奈与放弃的问题。

建议:

1、不要使用这个扩展库,改用 zeromq

2、一定要用的话,可以尝试更换或回退 nanomsg 版本。

---------------------------------------------------------------------------------------------

最新版 nanomsg.dll 遇到 XXX 问题,

别人用 8 年前的 nanomsg.dll  就没有问题怎么办?

surveyor 不报错,八年前的 nanomsg.dll .7z (76.24 KB, 下载次数: 56)

你也可以用 8 年前的 nanomsg.dll  。

替换个 DLL  总会吧, 不需要修改任何 aardio 代码。


166

主题

2154

回帖

1万

积分

管理员

积分
13056
 楼主| 发表于 2017-12-7 19:08:46 | 显示全部楼层
push/pull套接字结合使用可实现消息队列的扇出模式,
这是一个1对多的模式,服务端不能有多个,但客户端可以多个。
官网上给的这个图是1对1的,不要误解(他实际上是用于1对多的):


服务端或客户端不管谁先启动,都会等待对方连接,
注意pub/sub模式的服务端启动后是不会等待客户端来连接的,而push/pull就完全相反必须双方连接好了再推送,可以想象为一个管道,两头都接上才能传输数据。

pub/sub模式中,服务端一旦跟客户端连接,中间就绝不会丢弃消息,
就类似于一个单向的数据流,服务端只发不收,客户端只收不发,一个消息不会重复发给多个客户端
一般用于任务分派、负载均衡。

push服务端示例:
import console;

import nnmsg;
var sock = nnmsg.socket.push();
sock.bind (
"ws://*:7715")

console.log(
"push服务端等待连接中,没有人连接是不会发送的")

for(i=1;100;1){
      
    sock.send(
"分发任务ID:" + i );
    console.log(
"分发任务ID:" + i )
   
sleep(1000)
}

console.pause(
true);
pull客户端示例:
import console;

import nnmsg;
var sock = nnmsg.socket.pull();

console.log(
"客户端等待连接")
if( sock.connect("ws://127.0.0.1:7715") ){
   
   
var s = sock.recv();
   
while(s){
        console.log(
"服务器返回:",s );
        s = sock.recv();
    }
   
}
console.pause(
true);
   
千万不要以为这有什么呀,自己写个套接字也可以推送点东西,
nanomsg可没有这么简单,表面上看起来他好像是一个传输流,实际上他并不是。

nanomsg不像传统套接字那样,一定要服务端先启动,客户端后面跑过来连接,
他也可以客户端先启动,服务端后启动。

而且在连接传输的过程中,服务端,或者是客户端都可以中途断线,
下次再启动,可以继续工作,很神奇是吧?!

166

主题

2154

回帖

1万

积分

管理员

积分
13056
 楼主| 发表于 2017-12-7 20:21:38 | 显示全部楼层
sub/pub套接字结合使用可实现消息广播模式(Topics && Broadcast)
服务端只管发布,不管客户端是否连接,也不管是不是丢消息,但客户端连接上来以后就不会丢消息。


这个模式与push/pull的区别是很明显的,
不会像push/pull那样一定要等待双方连接才传输数据。
pub服务端只管自己顾自己的发布消息,而不管别人有没有收到。
一个典型的例子就是报时服务器,下面看代码。

pub服务端:
import console;

import nnmsg;
var sock = nnmsg.socket.pub();
sock.bind (
"ws://*:7713")

console.log(
"pub服务端已启动,不管客户端是不是连接上来,也不考虑有没有人接收消息")

for(i=1;100;1){
      
    sock.send(
"报时:" + tostring( time() ) );
    console.log(
"报时:" + tostring( time() )  )
   
sleep(1000)
}

console.pause(
true);
sub客户端:
import console;

import nnmsg;
var sock = nnmsg.socket.sub();

console.log(
"客户端等待连接")

//一定要指定订阅的主题前缀,指定为空订阅所有主题
sock.subscribe("报时:");

if( sock.connect("ws://127.0.0.1:7713") ){
   
   
var s = sock.recv();
   
while(s){
        console.log(
"服务器返回:",s );
        s = sock.recv();
    }
   
}
console.pause(
true);
   
这个sub客户端有一点特别,一定要用 sock.subscribe("报时:"); 指定你感兴趣的消息,
这个函数的参数指定要订阅消息的前几个字符,这几个字符没有特别格式的要求,只要消息是由这几个字符开始就可以。

pus/sub模式里,服务端的同一个消息可能被多个客户端接收,也可能根本没有客户端接收,
push/pull则完全不同 - 服务端消息一定会被一个客户端,并且也只会被一个客户端取走。


166

主题

2154

回帖

1万

积分

管理员

积分
13056
 楼主| 发表于 2017-12-7 20:28:52 | 显示全部楼层
surveyor/respondent套接字结合使用可实现调查模式,
surveyort负责发出调查问题,而respondent客户端则负责回应。


surveyor 服务端示例:
import console;

import nnmsg;
var sock = nnmsg.socket.surveyor();
sock.bind (
"ws://*:7717")

console.log(
"已启动 Survey(WebSocket协议) 服务端")
while (1){   
   
var msg  = sock.send("客户端你好,现在几点了?");
   
while(1){
        
var tm,err = sock.recvTable();
        
if(!tm){
            
if(nnmsg.lasterrno() == 0x9523DFE/*_NN_EFSM*/ ) break ;
            
else continue ;  
        }
        console.log( tm )
    }
     
    console.log(
"调查完了")   
}
  
respondent客户端:
import console;
import nnmsg;

console.log(
"Survey(WebSocket协议)客户端已启动")
var sock = nnmsg.socket.respondent();

if( sock.connect("ws://127.0.0.1:7717") ){
   
while(1){
      
var msg  = sock.recv();
        console.dump(
"收到:",msg );
        sock.sendTable( time() )
    }
}

console.pause(
true);


166

主题

2154

回帖

1万

积分

管理员

积分
13056
 楼主| 发表于 2017-12-7 20:32:49 | 显示全部楼层
pair套接字,服务端和客户端可以1对1的收发消息,


pair 服务端:
import console;

import nnmsg;
var sock = nnmsg.socket.pair();
sock.bind (
"ws://*:7710")

console.log(
"已启动 WebSocket 服务端")
while (1){   
   
var msg  = sock.recv();
    console.dump(
"客户端:",msg );   
    sock.send(
"客户端你还好吗?!")
}

console.pause(
true);
pair 客户端:
import console;

import nnmsg;
var sock = nnmsg.socket.pair();
if( sock.connect("ws://127.0.0.1:7710") ){
    sock.send(
"hello")
    console.log(
"服务端:",sock.recv() )
}
console.pause(
true);
   

166

主题

2154

回帖

1万

积分

管理员

积分
13056
 楼主| 发表于 2017-12-7 22:46:30 | 显示全部楼层
一个消息总线上可以有多个套接字,
每个套接字即是服务端可以启动监听,也是客户端可以同时连接多个其他的套接字。

连接到消息总线的任何一个套接字发送消息,消息总线上的其他套接字都能收到,一个套接字发出的消息,
其他套接字有可能重复的接收到多次(这个就好比街头听到的小道消息,可能由不同的人告诉你)。
但是套接字永远不会收到自己发的消息。



下面请看演示,消息总线里不分服务端或者客户端:
import win.ui;
/*DSG{{*/
var winform = win.form(text="nanomsg消息总线模式 演示";right=759;bottom=469)
winform.add(
edit={cls=
"edit";left=17;top=18;right=739;bottom=445;db=1;dl=1;dr=1;dt=1;edge=1;multiline=1;vscroll=1;z=1}
)
/*}}*/

winform.show();

//用于启动一个节点线程
var joinbus = function(port,winform){
   
import win;
   
import nnmsg;
   
   
var sock = nnmsg.socket.bus();
    sock.bind (
"tcp://*:" + port)
   
   
var nodes = thread.get("nnmsg-bus") : {};
   
for(i,addr in nodes){
        sock.connect(addr)
//连接到消息总线上所有其他的节点
    }
   
//把自己的地址写到消息总线上去
    table.push(nodes,"tcp://127.0.0.1:" + port);
    thread.set(
"nnmsg-bus",nodes )
      
   
sleep(100);//等待其他节点加入
    sock.send(port + "发送:我是新人,我今天才刚知道这个消息总线" )
   
   
while( win.isWindow(winform.hwnd) ){   
        
var msg  = sock.recv();
        winform.edit.print(port +
"接收:" + msg)
    }
}

//创建一大堆节点模拟消息总线
for(port=7591;7599){
    thread.invoke(joinbus,port,winform)  
sleep(100);
}

win.loopMessage();
运行示例可以看到,这个模式发送的消息发送的还是有些激烈的,所以这种模式只适合在本地局域网内使用。


166

主题

2154

回帖

1万

积分

管理员

积分
13056
 楼主| 发表于 2017-12-7 23:05:51 | 显示全部楼层
nanomsg实现各种模式的代码惊人的简洁,但简洁不等于简单。
并且各种编程语言里基本都有nanomsg的实现,使用nanomsg有良好的可扩展性。

nanomsg不但可以实现多种不同的通信模式,也可以选择多种不同的通信协议。
例如上面的我写的消息总线模式 - 使用的是tcp协议,而其他的模式使用的是WebSocket协议。
尤其是其中的WebSocket协议非常有趣,我们可以自己写一个WebSocket去连接nanomsg的服务端,并与nanomsg交互。

最初尝试的时候,我失败了!
在aardio中使用 web.socket.client 对象去连接 nanomsg,nanomsg很不高兴的拒绝了连接。

于是,我想起了 wsock.tcp.simpleHttpServer 这个好东西,
首先我用 wsock.tcp.simpleHttpServer启动了一个HTTP服务端 - 用来冒充nanomsg服务端。
然后用 nanamsg创建了一个WebSocket客户端连接上去,在HTTP服务器上输出发过来的数据包,
发现了nanomsg的小秘密,多了一个Sec-WebSocket-Protocol的HTTP头。

好吧,下面我们看演示代码。

nanomsg 服务端:
import console;

import nnmsg;
var sock = nnmsg.socket.pub();
sock.bind (
"ws://*:7725")

console.log(
"pub服务端已启动,可以打开aardio websocket客户端试一下了")

for(i=1;100;1){
      
    sock.send(
"报时:" + tostring( time() ) );
    console.log(
"报时:" + tostring( time() )  )
   
sleep(1000)
}

console.pause(
true);

下面是aardio实现的WebSocket客户端:
import win.ui;
/*DSG{{*/
var winform = win.form(text="WebSocket客户端演示";right=770;bottom=467)
winform.add(
btnClose={cls=
"button";text="断开";left=681;top=295;right=757;bottom=333;db=1;dr=1;z=6};
btnOpen={cls=
"button";text="连接WebSocket服务端";left=501;top=295;right=655;bottom=333;db=1;dr=1;z=2};
btnSend={cls=
"button";text="发送数据";left=567;top=380;right=764;bottom=456;db=1;dr=1;z=4};
cbSecWebSocketProtocol={cls=
"combobox";left=301;top=298;right=481;bottom=324;edge=1;items={};mode="dropdown";z=7};
txtMessage={cls=
"edit";left=29;top=22;right=741;bottom=285;db=1;dl=1;dr=1;dt=1;edge=1;multiline=1;z=1};
txtSend={cls=
"edit";text="WebSocket测试";left=25;top=382;right=554;bottom=457;db=1;dl=1;dr=1;edge=1;multiline=1;z=3};
txtUrl={cls=
"edit";text="ws://127.0.0.1:7725";left=29;top=295;right=269;bottom=331;db=1;dl=1;dr=1;edge=1;z=5}
)
/*}}*/

winform.cbSecWebSocketProtocol.items ={
   
"pub.sp.nanomsg.org";
   
"sub.sp.nanomsg.org";
   
"pair.sp.nanomsg.org";
   
"req.sp.nanomsg.org";
   
"rep.sp.nanomsg.org";
   
"surveyor.sp.nanomsg.org";
   
"respondent.sp.nanomsg.org";
   
"push.sp.nanomsg.org";
   
"pull.sp.nanomsg.org";
   
"bus.sp.nanomsg.org";
}
winform.cbSecWebSocketProtocol.selIndex = 1;

import web.socket.client;
var ws = web.socket.client();
ws.heartbeatInterval = - 1;
//sub端不能发任何数据

ws.onOpen =
function(){
    winform.cbSecWebSocketProtocol.disabled =
true;
}

ws.onClose =
function(){
    winform.txtMessage.print(
"onClose");
    winform.cbSecWebSocketProtocol.disabled =
false;
    winform.btnSend.disabledText =
null;
}

ws.onError =
function(err){
    winform.txtMessage.print(
"onError",err);
}

ws.onMessage =
function(msg){
    winform.txtMessage.print(msg.data);
}

winform.btnSend.oncommand =
function(id,event){
    ws.send(winform.txtSend.text)   
}

winform.btnOpen.oncommand =
function(id,event){
   
//加上这句,假装自己是nanomsg客户端
    ws.headers ={
        [
"Sec-WebSocket-Protocol"] = winform.cbSecWebSocketProtocol.selText;
    }
   
   
if( winform.cbSecWebSocketProtocol.selText == "pub.sp.nanomsg.org" ){
        winform.btnSend.disabledText =
"此模式不支持发送"
    }
    ws.connect(winform.txtUrl.text);
}

winform.btnClose.oncommand =
function(id,event){
    ws.close();
}

winform.show();
win.loopMessage();

运行示例,奇迹发生了:
nnmsg.png
您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

手机版|未经许可严禁引用或转载本站文章|aardio.com|aardio 官方社区 ( 皖ICP备09012014号 )

GMT+8, 2025-1-13 15:41 , Processed in 0.072740 second(s), 26 queries .

Powered by Discuz! X3.5

Copyright © 2001-2024 Tencent Cloud.

快速回复 返回顶部 返回列表