java 做多线程通讯

来源:互联网 发布:mac如何airdrop 编辑:程序博客网 时间:2024/03/29 14:37

前几天老大给我一个任务,要求我用java做一个发送端,模拟一个双IP终端向定时间间隔向两台服务器发送登录指令,根据服务器是否有回馈来判断服务器软件是否异常关闭。

1、每隔3分钟发送一次登录,这个肯定是多线程,要做两个线程,分别向两天服务器发送登录,然后立马将UDP接口转换成接收状态,但是转换之后,如果收到数据,可以顺利执行下面代码;如果没有收到数据,会一直处于接收状态,进入阻塞,后续的关闭UDP通道的指令也不能执行。因为这个必须3分钟一次登录,我只能在每次收到(或者是没收到)数据就及时将连接socket关闭,否则下次新建UDP socket的时候会报异常,这也是这个问题的根结(UDP socket 阻塞了)。。。

2、整个程序的布置就是要将向多个IP发送登录、接收回馈、报警、写日志等一系列动作放在线程中执行,IP、端口、数据包等信息均放在配置文件中读取。

模块设计:

1、数据字节处理

public static byte[] hex2byte(String s1)//输入为16进制字符串,转换成byte字节{String digital = "0123456789ABCDEF";char[] hex2char = s1.toCharArray();byte[] bytes = new byte[s1.length() / 2];int temp;for (int i = 0; i < bytes.length; i++) {temp = digital.indexOf(hex2char[2 * i]) * 16;temp += digital.indexOf(hex2char[2 * i + 1]);bytes[i] = (byte) (temp & 0xff);}return bytes;}

2、建立UDP socket

发送与接收都用同一个端口,这对UDP通信来说是比较复杂的,原因有两点:其一、UDP通信是面向无连接的,服务端的代码只负责接收数据,监听固定端口,而客户端,在建立socket通道的时候就可以指定本地端口(也可不指定,此时客户端操作系统随机指定端口),在发送时,监控软件处于客户端;在接收时,监控软件处于服务端。如果要使程序死循环执行下去,每隔3分钟发送一个登录包,即每三分钟进行一次客户端和服务端的切换。其二、UDP的receive方法是阻塞函数(这个我要做下解释,阻塞即意味着,在阻塞发生时,程序停留在这个地方,其后面的代码不执行),当然,这个可以通过设置socket的timeout值来迫使阻塞破裂,进而执行catch (IOException e) {...}里面的代码,这个对于多进程死循环程序很重要。

3、多线程执行代码处理与共享内存管理

多线程对内存共享是一种很重要的技术,这对于处理多任务时至关重要,因为对变量的修改要加锁,所以将变量多线程执行段放在synchronized中执行,例如

synchronized (this) {frame.appendString("\r\n <== Receive data from "+datagramPacket.getAddress().toString());}
这样,在frame中显示的内容就直接根据当前进程显示内容滚动显示。

4、读入配置文件(文本文件与声音文件)

读配置文件是很关键的一步,一直纠结与编译前和编译后,对相对路径的迷惑,我一般采用指定绝对路径的方法,说不定哪天能够意外发现大牛的某篇博客而茅塞顿开,在就不谈路径问题。

一度面临先有鸡先有蛋的问题迷惑不已,软件执行--读配置文件--加载配置文件--执行输出。这似乎成了小程序的固定模式,当然,也可以在读配置文件之前,通过UI来给用户自定义配置文件路径,这样似乎也有点不科学,软件如果都做的这么傻瓜了,你的软件就肯定会贬值,当然也会获得很好的用户体验。

public void Alert(String alert_file_path) {//读声音文件try { FileInputStream fileau=new  FileInputStream(alert_file_path); AudioStream as=new AudioStream(fileau); AudioPlayer.player.start(as);} catch (IOException e) {e.printStackTrace();           }}

配置文件中要加载很多台服务器的IP地址、端口,本地端口,发送数据字节(0x),这些数据我还是推荐用数组来处理,而且,安全性更高,如果我给用户的最大值为1billion,是否可以认为,用户将拿我的软件对GPS运营商进行暴力攻击?

5、写日志文件

写日志文件对很多人来说都不值得提,因为太多的博客在教我们read & write log files,这里不再复述。

6、动态信息打印

动态信息打印的基础是你先画出一个frame,这个可以参看某些基础教材,本人比较喜欢看大学教材,虽然过于简单,但是确实看完印象深刻。

7、主函数

主函数的设计是对整个软件运行流程的把握,下面直接上代码

public static void main(String[] args){try {UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());} catch (ClassNotFoundException e1) {// TODO Auto-generated catch blocke1.printStackTrace();} catch (InstantiationException e1) {// TODO Auto-generated catch blocke1.printStackTrace();} catch (IllegalAccessException e1) {// TODO Auto-generated catch blocke1.printStackTrace();} catch (UnsupportedLookAndFeelException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}frame=new DragingFrame();        frame.setSize(400, 300);        frame.setLocation(300, 300);        frame.setResizable(false);                frame.setTitle("服务端监控程序  developed by forilen V1.3");        frame.setVisible(true);        //JOptionPane.showMessageDialog(null, "程序已经打开,切勿重复打开!");readFile rf=new readFile();String [][]config;config =rf.readFileByLines("C:/alter_info/alter.conf");//Read the configure text(IP,port,packages) from the fileint timeout=Integer.parseInt(config[0][0]);int frequency=Integer.parseInt(config[0][1]);int auto=Integer.parseInt(config[0][2]);int total=Integer.parseInt(config[0][3])+1;while (flag) {//根据flag配置文件,设置参数是否死循环执行for (int i = 1; i < total; i++) {test_so r1 = new test_so("1s");r1.set_tag(config[i][0], config[i][1], config[i][2],timeout,config[i][3]);Thread t1 = new Thread(r1, "t1");t1.start();}try {Thread.sleep(frequency*1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}if (auto==0) {continue;}else {auto--;if (auto==0) {break;}}}    }

8、程序发布

程序发布我还是建议直接发布成jar包就行了,exe文件运行都太过肤浅,装了jre的机子都支持jar包的执行



0 0