├── 2017-04-26-112556_759x827_scrot.png ├── 2017-04-26-112608_606x752_scrot.png ├── IMG_20170426_122613.jpg ├── IMG_20170504_141239.jpg ├── IMG_20170522_195657.jpg ├── README.md ├── lifi.mp4 ├── pom.xml └── src └── main └── java └── lcy └── rawip4j ├── PacketFrame.java └── RxdUtil.java /2017-04-26-112556_759x827_scrot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binaryer/rawip4j/16e9ca13b6f8958c31281271170b55d716702bca/2017-04-26-112556_759x827_scrot.png -------------------------------------------------------------------------------- /2017-04-26-112608_606x752_scrot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binaryer/rawip4j/16e9ca13b6f8958c31281271170b55d716702bca/2017-04-26-112608_606x752_scrot.png -------------------------------------------------------------------------------- /IMG_20170426_122613.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binaryer/rawip4j/16e9ca13b6f8958c31281271170b55d716702bca/IMG_20170426_122613.jpg -------------------------------------------------------------------------------- /IMG_20170504_141239.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binaryer/rawip4j/16e9ca13b6f8958c31281271170b55d716702bca/IMG_20170504_141239.jpg -------------------------------------------------------------------------------- /IMG_20170522_195657.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binaryer/rawip4j/16e9ca13b6f8958c31281271170b55d716702bca/IMG_20170522_195657.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rawip4j 2 | java链路层封包协议, 实现数据包完整性校验 可用于无线收发模块(激光/可见光/2.4G/433Mhz/315Mhz ...)实现TCP/IP通信 3 | java Data Link Layer protocol 4 | 5 | ## 说明 6 | + 没有重传确认功能, 发送不保证对方一定收到包,亦不保证顺序。需要结合 tun/tap 才能实现TCP通信 7 | + 如果收到包,则可保证包数据完整性(使用md5算法校验和) 8 | + 配合 tun/tap 使用,可实现多终端全双工通信, 建议MTU设置为256以下,恶劣环境下需设置更低的值 9 | + 虽然433Mhz, 315Mhz, Infrared-ray功耗低,但传输速率也较低,因此不适合用来浏览互联网,建议用在物联网少量数据传输场景 10 | 11 | user-program -> tun/tap -> rawip4j -> wireless(zigbee, 433Mhz, 315Mhz, Infrared-ray) -> (THE AIR) -> wireless -> rawip4j -> tun/tap -> user-program 12 | 13 | ## 使用方法: 14 | ``` java 15 | public static void main(String[] args) throws IOException, InterruptedException { 16 | 17 | // 定义队列用于存储接收到的包 received packet queue 18 | final BlockingQueue queue = new LinkedBlockingQueue<>(); 19 | 20 | // 通过 rxtx 获取设备的InputStream 和 OutputStream 21 | //TODO get the InputStream & OutputStream from SerialPort devices 22 | // you can use librxtx-java (aptitude install librxtx-java) 23 | // or http://mvnrepository.com/artifact/org.rxtx/rxtx (untested) 24 | InputStream ins = null; 25 | OutputStream outs = null; 26 | 27 | 28 | 29 | 30 | /* *********************************************************************************************************************** */ 31 | 32 | // 开始读取包,读到的包将放入BlockingQueue队列中 33 | // 这个方法是立即返回的(无阻塞) 34 | // 非线程安全, 如用于多线程场景,请做好加锁同步 35 | // receive packet into the queue 36 | RxdUtil.register(ins, queue); 37 | 38 | 39 | /* *********************************************************************************************************************** */ 40 | 41 | // 新开线程处理接收到的包 42 | // start a received packet handler thread 43 | new Thread(new Runnable() { 44 | 45 | @Override 46 | public void run() { 47 | while(true){ 48 | try { 49 | final byte[] data = queue.take(); 50 | System.out.println("received packet: " + new String(data)); 51 | } catch (InterruptedException e) { 52 | e.printStackTrace(); 53 | } 54 | } 55 | } 56 | }).start(); 57 | 58 | 59 | /* *********************************************************************************************************************** */ 60 | 61 | // 发送包,不保证对方一定接收到包,但如果接收到,则能保证包的数据完整性 62 | // chksumlength: 校验和字节,可以设置为2-16,越大越安全, 建议8 63 | // send a data packet 64 | // chksumlength: use md5 to checksum a packet, the value can be 2-16, recommend 8 65 | new PacketFrame((byte)8, "hello, rawip4j".getBytes()).write(outs); 66 | 67 | 68 | /* *********************************************************************************************************************** */ 69 | 70 | 71 | TimeUnit.SECONDS.sleep(Long.MAX_VALUE); 72 | 73 | 74 | } 75 | ``` 76 | 77 | ## 效果图 78 | 79 | ### 433MHz模块距离20米,隔2墙1窗1门,ping丢包率5%, wget 600bytes/s 80 | 81 | ![](https://github.com/binaryer/rawip4j/raw/master/2017-04-26-112556_759x827_scrot.png) 82 | ![](https://github.com/binaryer/rawip4j/raw/master/IMG_20170426_122613.jpg) 83 | 84 | ### 单工激光传输文件 85 | ![](https://github.com/binaryer/rawip4j/blob/master/IMG_20170504_141239.jpg) 86 | 87 | 88 | ### 可见光通信 89 | ![](https://github.com/binaryer/rawip4j/blob/master/IMG_20170522_195657.jpg) 90 | 91 | https://www.youtube.com/embed/jwORKOSE3NA 92 | -------------------------------------------------------------------------------- /lifi.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binaryer/rawip4j/16e9ca13b6f8958c31281271170b55d716702bca/lifi.mp4 -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | lcy 6 | rawip4j 7 | 0.0.1-SNAPSHOT 8 | jar 9 | 10 | rawip4j 11 | http://maven.apache.org 12 | 13 | 14 | UTF-8 15 | 16 | 17 | 18 | 19 | junit 20 | junit 21 | 3.8.1 22 | test 23 | 24 | 25 | 26 | 27 | 28 | commons-codec 29 | commons-codec 30 | 1.10 31 | 32 | 33 | 34 | 35 | org.apache.commons 36 | commons-lang3 37 | 3.5 38 | 39 | 40 | 41 | com.google.guava 42 | guava 43 | 21.0 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/main/java/lcy/rawip4j/PacketFrame.java: -------------------------------------------------------------------------------- 1 | package lcy.rawip4j; 2 | 3 | import java.io.IOException; 4 | import java.io.OutputStream; 5 | import java.nio.ByteBuffer; 6 | import java.util.Arrays; 7 | 8 | import org.apache.commons.codec.digest.DigestUtils; 9 | import org.apache.commons.lang3.ArrayUtils; 10 | 11 | public class PacketFrame { 12 | 13 | public static final byte[] MAGIC = { 5, -3, 126, 120, -18, 24, 92, 1 }; //可自定义,通讯双方必须一致 14 | 15 | private final byte[] magic = new byte[MAGIC.length]; 16 | private short datalength; // 数据长度 17 | private byte[] data; // 数据 18 | private byte chksumlength; // 校验和长度 19 | private byte[] chksum; // 校验和 20 | 21 | public byte[] getChksum() { 22 | return chksum; 23 | } 24 | 25 | public PacketFrame() { 26 | } 27 | 28 | public PacketFrame(byte chksumlength, byte[] data) { 29 | setChksumlength(chksumlength); 30 | setData(data); 31 | } 32 | 33 | public byte getChksumlength() { 34 | return chksumlength; 35 | } 36 | 37 | public void setChksumlength(byte chksumlength) { 38 | this.chksumlength = chksumlength; 39 | } 40 | 41 | public byte[] getData() { 42 | return data; 43 | } 44 | 45 | public void setData(byte[] data) { 46 | this.data = data; 47 | } 48 | 49 | public void write(OutputStream out) throws IOException { 50 | 51 | if (data.length == 0 || data.length > (Short.MAX_VALUE - Short.MIN_VALUE + 1)) 52 | throw new RuntimeException("data length must be 1-65536, current " + data.length); 53 | if (chksumlength < 2 || chksumlength > 16) 54 | throw new RuntimeException("chksumlength must be 2-16, current " + chksumlength); 55 | 56 | System.arraycopy(MAGIC, 0, magic, 0, MAGIC.length); 57 | out.write(magic); 58 | 59 | datalength = (short) data.length; 60 | out.write(ByteBuffer.allocate(2).putShort(datalength).array()); 61 | out.write(data); 62 | out.write(new byte[]{chksumlength}); 63 | out.write(chksum = ArrayUtils.subarray(DigestUtils.md5(data), 0, chksumlength)); 64 | 65 | /* 66 | System.out.println("writePackage"); 67 | for(byte b : magic){ 68 | System.out.print(b+","); 69 | } 70 | for(byte b : ByteBuffer.allocate(2).putShort(datalength).array()){ 71 | System.out.print(b+","); 72 | } 73 | */ 74 | 75 | } 76 | 77 | // 返回整个PackageFrame长度字节, 包含magic 78 | // 长度未满 -1 79 | // 校验和失败 -2 80 | // 格式错误意料外数据 -3 81 | public static final int read_ok = 0; 82 | public static final int read_tooshort = -1; 83 | public static final int read_chksumerr = -2; 84 | public static final int read_unexpected = -3; 85 | 86 | /** 87 | * 88 | * @param bs 89 | * @param startindex 90 | * @param bslength 91 | * @param packageframe 92 | * @return [是否成功, 包长] 93 | */ 94 | public static int[] read(byte[] bs, int startindex, int bslength, final PacketFrame packageframe) { 95 | 96 | final ByteBuffer bb = ByteBuffer.wrap(bs, startindex, bslength); 97 | for(int i=0; i