当前位置: 首页 > 知识库问答 >
问题:

如何生成套接字线程并使用UDP广播数据包与主线程进行报警通信?

经景辉
2023-03-14

我是Java初学者。我有一个设备,每隔5s发送一次UDP广播ping包,很少发送警报(一种警报)。

我希望有一个java程序,它监听ping数据包,并显示上次ping以来的时间,如果在一定的时间内没有收到ping,或者如果收到来自传感器的实际警报,它会发出某种警报。

我无耻地从stackoverflow复制了这段代码,但是serversocket.receive(receivePacket)阻塞,所以计数器不能工作。

我认为我需要生成一个线程来打开套接字并等待接收到的数据,然后以某种方式与主线程通信而不阻塞,这样计时器就可以运行,但我不知道如何实现这一点。

package com.testing;

import java.io.IOException;
import java.net.*;
import java.time.Duration;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

public class Receiver {  // from https://stackoverflow.com/a/13780614/1340782

    public static void main(String[] args) {
        int port = args.length == 0 ? 8266 : Integer.parseInt(args[0]);
        new Receiver().run(port);
    }

    public void run(int port) {
        try {
            DatagramSocket serverSocket = new DatagramSocket(port);
            byte[] receiveData = new byte[8];
            String sendString = "pong";
            byte[] sendData = sendString.getBytes("UTF-8");

            System.out.printf("Listening on udp:%s:%d%n",
                    InetAddress.getLocalHost().getHostAddress(), port);
            DatagramPacket receivePacket = new DatagramPacket(receiveData,
                    receiveData.length);


            LocalTime lastPing = java.time.LocalTime.now();
            String lastMessage = "";

            while(true)
            {
                serverSocket.receive(receivePacket);
                String sentence = new String( receivePacket.getData(), 0,
                        receivePacket.getLength() );
//                System.out.println(java.time.LocalTime.now().truncatedTo(ChronoUnit.SECONDS) + " RECEIVED: " + sentence);
                LocalTime now = java.time.LocalTime.now();
                lastMessage = now.format(DateTimeFormatter.ofPattern("HH:mm:ss"))
                        + " RECEIVED: " + sentence;
                if (sentence.equals("ping")) {
                    lastPing = java.time.LocalTime.now();
                }
                lastMessage = lastMessage + " - " + Duration.between(lastPing,now).toMillis() + "ms since last ping";
                System.out.print(lastMessage);
                System.out.print("\r");
            }
        } catch (IOException e) {
            System.out.println(e);
        }
        // should close serverSocket in finally block
    }
}

谢谢大家

共有1个答案

荣俊杰
2023-03-14

在本例中,您使用的是阻塞IO,因此,如果您希望在套接字等待数据的同时运行某些内容,您将需要另一个线程,正如您已经发现的那样。

在本例中,看起来您并不真正需要自己管理线程,而是使用Java的repeating scheduler服务,这样您就可以让一个任务在每个p时间段内重复运行。

进行网络连接的代码不需要任何更改,只需将管理ping的代码提取到一个单独的方法中,该方法将执行如下操作:

java prettyprint-override">import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

class Scratch
{
    // AtomicReference helps exchange data between threads safely
    static final AtomicReference<Instant> lastPing = new AtomicReference<>();

    public static void main(String[] args) throws InterruptedException
    {

        // the lambda below will run every 2 seconds
        Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> {
            Instant lastPingTime = lastPing.get();
            if (lastPingTime == null)
            {
                System.out.println("No ping yet");
            }
            else
            {
                System.out.println("Last ping was " + Duration.between(lastPingTime, Instant.now()) + " ago");
            }
        }, 0, 2, TimeUnit.SECONDS);

        // simulate a ping from the main Thread after 5 seconds
        Thread.sleep(5_000L);

        lastPing.set(Instant.now());
    }
}
No ping yet
No ping yet
No ping yet
Last ping was PT0.999S ago
Last ping was PT2.997S ago
Last ping was PT4.995S ago
...

希望这足以让你畅通。关于Java中的多线程有很多要读的,但是知道了可以使用AtomicReference以及它的基本表亲(AtomicBooleanAtomicInteger...)在不同的线程之间安全地交换数据应该已经足够您现在实现您想要的了。

了解JavaExecutorService(我在上面使用Executors创建了一个)也很重要,因此您不需要直接自己创建线程(服务将为您完成)。请注意,由于ExecutorService通常在内部保留一个线程池,因此您需要确保在完成后调用它的close(),否则您的应用程序将永远无法完成运行(对于GUI和服务器可能没有问题,但对于CLI和短时间运行的进程则没有问题)。

 类似资料:
  • 这是我的客户端和服务器的代码。 class Client1{Client1(int no){try{String message;message=“Hello this is client”+no;byte[]b=message.getBytes();DatagramPacket dp=new DatagramPacket(b,b length,inetAddress.getLocalHost()

  • 我想广播消息本地到许多应用程序。对于这一点,我认为UDP套接字是最好的IPC,纠正我,如果我是Worwn。 并倾听: 问题是我必须像这样通过IP192.168.1.255,但在实际场景中可能没有eth0接口,只有环回。那我怎么才能做到这一点呢?

  • 本文向大家介绍在Python中使用多线程进行套接字编程?,包括了在Python中使用多线程进行套接字编程?的使用技巧和注意事项,需要的朋友参考一下 多线程概念 多线程是几乎所有现代编程语言(尤其是python)的核心概念,因为它的线程实现简单。 线程是程序内的子程序,可以独立于代码的其他部分执行。线程在同一上下文中执行,以共享程序的可运行资源(如内存)。 当在一个进程中,我们同时执行多个线程时,称

  • 所以我正在编写代码,它将解析文件夹中的多个文本文件,收集它们的信息,并将这些信息保存在两个静态列表实例变量中。信息存放的顺序并不重要,因为我最终将对其进行排序。但由于某些原因,增加线程数不会影响速度。这是我的run方法和主方法中利用多线程的部分。 如果需要额外的信息,我基本上有一个静态实例变量作为我需要浏览的文件的数组,还有一个常量是线程数(为了测试目的手动更改)。如果我有4个线程和8个文件,每个

  • 我们现有的软件定期向本地子网(X.X.X.255)上的特定端口(7125)广播UDP数据包。我们的监控软件运行在HP-UX(11.11)上,可以接收这些数据包,没有问题。然而,在将监控软件移植到Linux(RHEL6.1)之后,我们发现它并没有接收到广播数据包。tcpdump显示了到达Linux主机的数据包,但内核不会将它们发送给我们的软件。 我使用了几个Python2.x脚本,这些脚本模拟了监控

  • 为了实现这一点,我使用了队列/线程池机制。最初,我创建一个固定数量线程的池,并有一个队列datastructure来存储客户机地址。这个队列在所有线程之间共享,因此我使用“互斥”来锁定/解锁这个队列。在主服务器线程中,我创建一个套接字,将其绑定到全局端口/地址,然后在“recvfrom”调用上阻止服务器。任何希望与服务器通信的客户端都会向侦听全局端口地址的主线程服务器发送“HI”消息。主服务器线程