最近,我使用NetMQ在服务器和客户端之间发送或接收消息。 服务器代码,例如:
void Main()
{
CreatePullAndPushSocket();
Task.Factory.StartNew(()=> {
while (true)
{
Thread.Sleep(1);
if (Pull != null)
{
var message = Pull.ReceiveFrameString();
}
}
});
}
PullSocket Pull;
PushSocket Push;
private void CreatePullAndPushSocket()
{
Pull = new PullSocket("tcp://ip1:port1");
Push = new PushSocket("tcp://ip2:port2");
}
public void SendMessageToClient(string message)
{
if (Push != null)
{
Push.SendFrame(message);
}
}
客户代码如下:
void Main()
{
new Thread(()=> {
while (true)
{
Thread.Sleep(1);
if (Pull != null)
{
var message = Pull.ReceiveFrameString();
}
}
}).Start();
}
PullSocket Pull;
PushSocket Push;
private void CreatePullAndPushSocket()
{
Pull = new PullSocket("tcp://ip2:port2");
Push = new PushSocket("tcp://ip1:port1");
}
public void SendMessageToClient(string message)
{
if (Push != null)
{
Push.SendFrame(message);
}
}
当我运行两个应用程序(即服务器应用程序)时,另一个是客户端应用程序。
很奇怪,我遵循了https://netmq.readthedocs.io/en/latest/push-pull/的指导!!
答案 0 :(得分:0)
在NetMQ中,非常重要的一点是线程模型。真正重要的是,您不应在多个线程中使用套接字。因此,如果线程1创建了套接字,则应该使用它。如果您想通过使用相同的套接字从其他线程(比如说Thread#2)发送消息,那就别管了。您应该以某种方式将消息从线程2发送到线程1,然后将其通过套接字发送到客户端。
所以从根本上讲CreatePullAndPushSocket是错误的,然后可能发生奇怪的事情。您正在一个线程中创建套接字,而在另一个线程中使用套接字。这简直是错误的。
另一件事是您的Thread.Sleep。您不应该使用Thread.Sleep,因为您的线程正在休眠1s,然后检查套接字一次,而不是休眠并检查一次。 NetMQ具有带有超时功能的TryReceive。因此它可以检查套接字1秒钟,然后退出以检查您是否调用了cancel / stop或其他方法。甚至更好的是有一个轮询器,它会一直监听套接字,并允许我们从其他线程调用stop。
让我们看一下这段代码:
private Poller _poller;
public void Start()
{
Task.Factory.StartNew(()=> {
using(var pullSocket = new PullSocket("tcp://ip1:port1"))
using(_poller = new Poller())
{
pullSocket.ReceiveReady += (object sender, NetMQSocketEventArgsnetMqSocketEventArgs) =>
{
var message = netMqSocketEventArgs.Socket.ReceiveMultipartMessage();
}
_poller.Add(pullSocket);
_poller.Run();
}
});
}
public void Stop()
{
_poller?.Stop();
}
或者如果您想在while循环中使用没有轮询器的代码:
私有只读CancellationTokenSource _cts;
public void Start()
{
_cts = new CancellationTokenSource();
var token = _cts.Token;
Task.Factory.StartNew(()=> {
using(var pullSocket = new PullSocket("tcp://ip1:port1"))
{
while (cancellationToken.IsCancellationRequested == false)
{
NetMQMessage message = new NetMQMessage();
bool success = workerSocket.TryReceiveMultipartMessage(TimeSpan.FromSeconds(5), ref message);
if (success == false)
{
continue;
}
//if You reach this line, than You have a message
}
}
},
token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);
}
public void Stop()
{
_cts.Cancel();
_cts.Token.WaitHandle.WaitOne();//if You want wait until service will stop
}
所以回到您的问题,您应该仅在创建套接字的线程内部使用套接字。好的事情是总是在using语句中使用socket来最终总是释放它。
我看不到SendMessageToClient方法的用法,但我假设您是通过某个按钮或某些东西调用它的。如果从该线程调用了套接字的构造函数,则可以执行此操作。如果您可以告诉我您在哪里调用此方法,我可以对此说点什么。