• tcptump的使用------使用JAVA与tcpdump从网络获取原始数据


    从这里开始,就开始接触使用分布式系统处理大数据了。在处理大数据之前,需要有一个场景,否则技术工具无法嵌入现实当中,价值就会降低。我碰到的场景应该还是比较具有普遍性,因此大家可以在我的场景里先玩一遍,熟悉一下流程和方法,然后加以改造,加载到自己的场景和环境中。

    场景:在一个大型公司内部,终端和各个业务系统之间的数据传输都通过网络进行。出于监控的要求,需要在网络上获取所有数据包,并查看数据包里是否含有某些关键字。如果含有某些关键字,证明终端和业务系统间正在进行某种操作。系统记录下这些操作,用于实时显示或统计使用。

    这其实就是“行为数据”的采集和记录,是典型的大数据处理场景。

    扩展一下,将该场景所使用的技术和工具加载到互联网或APP上,就可以在不改动任何业务系统、在用户无感知的情况下,采集用户的行为数据并加以利用,形成用户习惯数据。当然,也可以通过“埋点”的方式进行,但改动业务系统不要花钱嘛,能省一点是一点。

    网络数据的获取。网络数据通过网络设备的“镜像口”获得。镜像口的设置可以让网管帮忙,一般可网管交换机都可以做到,思科、华三、迈普这些都没啥问题。通过镜像口获取网络数据,就可以在各个业务系统和用户无感知的情况下获取所有的数据了。当然,如果公司或者系统在传输时使用https等加密手段,这个就没办法了。不过一般公司很少在内网传输时加密。

    结构如下(画功实在是感人):

    将镜像口(也就是上图的监听口)接到一台服务器的RJ45网卡上,不用配IP地址,服务器这个网卡就可以接收到所有在网络上传输的数据了。如下图,eth1就是接入镜像口的网卡。

    使用 tcpdump -i eth1 可以看到网络上传输的部分数据。通过源地址、目标地址,就可以大概判断是不是公司的数据了。

    tcpdump的使用很复杂,网上很多方法介绍,这里就不做解释,直接用起来。一般来说,完整的tcpdump数据包包含了很多段,每段还有标识等等。如下图:

    可以看到网络包中包含有一段json,这就是在网络上传输的数据。

    但直接通过tcpdump获得的这些数据是不适合直接扔给分布式系统做处理的。为什么呢?

    因为分布式处理是多台设备并行处理,达到扩展数据处理能力的目的。刚刚说了,完整的tcpdump数据包包含了很多段,假设这个数据包为A,A1是第一段,A2是第二段。如果同时将A1,A2并发给分布式系统处理,并且同时出结果,把结果拼起来,这是没问题的。但现实情况是,A1比A2先处理完,先收到一个结果A1,就没法得到一个有意义的结果。更糟糕的情况时,假如此时同时出来一个B1,把A1,B1拼在一起得到一个更错误的结果。

    所以,要利用分布式系统处理tcpdump的数据,就要把一个完整的数据包一次性丢给分布式处理系统,保证数据包和计算结果的完整性和对应性。也就是A1数据包进去计算,得到的是A1的计算结果。

    使用tcpdump命令:

    tcpdump -Anvtttt -s 0 -i eth1 tcp[20:2]=0x4745 or tcp[20:2]=0x4854 or tcp[20:2]=0x504f|sed '/ IP (tos/s/^/<<interval>>/'

    需要特别说明的是,tcp[20:2]=0x4745 or tcp[20:2]=0x4854 or tcp[20:2]=0x504f 是对tcpdump数据包进行初步过滤,只需要http包,其他的比如arp、rtp包之类的不需要。

    使用个命令后,tcpdump得到的数据都会在第一行留一个<<interval>>作为标志,标志这个数据包开始,到下一个<<interval>>结束。这样就可以为下一步利用JAVA清楚所有换行符做好标记。

    得到的结果如下:

    两个<<interval>>之间就是一个完整的tcpdump数据包。下面结合使用JAVA,将一个完整的tcpdump数据包整合成一个能被分布式大数据处理平台进行处理的数据。其实是一个简单的ETL过程。

    使用JAVA对tcpdump数据包进行数据清洗,并加载到kafka中

    1、使用eclipse新建一个maven工程,这里起名叫shell

    2、使用pom.xml对依赖包进行管理,主要使用kafka的依赖包。

    <dependencies>
    <!-- kafka -->
    <dependency>
    <groupId>org.apache.kafka</groupId>
    <artifactId>kafka_2.11</artifactId>
    <version>0.10.1.1</version>
    </dependency>
    <dependency>
    <groupId>org.apache.kafka</groupId>
    <artifactId>kafka-clients</artifactId>
    <version>0.10.1.1</version>
    </dependency>
    <dependency>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-resources-plugin</artifactId>
    <version>2.3</version>
    </dependency>
    </dependencies>
    View Code

    3、在kafka中设置一个topic。这个kafka的配置和topic的配置以后再说,不难。如果不知道怎么弄,可以在JAVA程序里写到一个本地文本文件里。这算是个作业,大家自己做吧。

    4、将每个tcpdump包中两个<<interval>>之间的数据进行清洗。主要是把其中的换行符替换成“|”符号,清除掉其他不想要的符号。把清洗干净的数据放到s_right变量中等待发送。接着清洗另一条数据,清洗完第二条数据后,将s_right里的数据前移到s_left中并发送到kafka里,第二条数据放在s_right中等待发送。

    package shell;
    
    import java.io.*;
    import java.text.SimpleDateFormat;
    import java.util.Properties;
    import java.util.concurrent.ExecutionException;
    import java.util.Date;
    import java.util.Calendar;
    
    //import kafka.producer.*;
    //import kafka.serializer.StringEncoder;
    //import kafka.javaapi.producer.Producer;
    //import kafka.producer.Partitioner;
    //import kafka.producer.ProducerConfig;
    
    import org.apache.kafka.clients.producer.KafkaProducer;
    import org.apache.kafka.clients.producer.Producer;
    import org.apache.kafka.clients.producer.ProducerRecord;
    
    public class runShell {
    
        // private static kafka.javaapi.producer.Producer<Integer, String> producer
        // = null;
    
        public static void main(String[] args) throws IOException, InterruptedException, ExecutionException {
    
            String SHELL_FILE_DIR, SHELL_FILE;
            SHELL_FILE_DIR = "/hadoop/sh/";
             //把tcpdump命令放到一个sh文件中,把文件地址写在SHELL_FILE 中,这样JAVA
             //程序就可以调用tcpdump命令了
            SHELL_FILE = "./" + "getTcpdump.sh";
            String s = null;
            String s_left = "", s_right = "";
            int runningStatus = 0;
    
            Properties props = new Properties();
            props.put("bootstrap.servers","你的kafka的地址和端口");
            props.put("acks", "1");
            props.put("retries", 0);
            props.put("linger.ms", 0);
            props.put("buffer.memory", 33554432);
            props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
            props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
            // 将props的配置放到kafka中
            Producer<String, String> producer = new KafkaProducer<String, String>(props);
    
    
            // 设置kafka的topic
            String TOPIC = "netRawdata";
    
            ProcessBuilder pb = new ProcessBuilder(SHELL_FILE);
            pb.directory(new File(SHELL_FILE_DIR));
    
            Process p = pb.start();
    
            BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
            BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getInputStream()));
            while ((s = stdInput.readLine()) != null) {
    
                if (s.startsWith("<<interval>>")) {
                    s_left = s_right;
                    s_right = s.substring(12);
    
                    if (s_left != "") {
                        s_left = s_left.replaceAll("	", " ");
                        s_left = s_left.replaceAll(" +", " ");
                        producer.send(new ProducerRecord<String, String>(TOPIC, s_left)).get();
                        System.out.println(s_left);
                    }
    
                } else {
    
                    s_right = s_right + "|" + s;
                }
    
            }
            while ((s = stdError.readLine()) != null) {
                System.out.println(s);
            }
            try {
                runningStatus = p.waitFor();
    
                if (s_right != "") {
                    s_right = s_right.replaceAll("	", " ");
                    s_right = s_right.replaceAll(" +", " ");
                    s_right = s_right.replaceAll("
    ", " ");
                    producer.send(new ProducerRecord<String, String>(TOPIC, s_right)).get();
                    System.out.println(s_right);
                    producer.close();
                }
    
            } catch (InterruptedException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
    
        }
    
    }
    View Code
  • 相关阅读:
    STL容器list容器API
    STL容器之list基本概念
    STL容器queue的API
    做tab切换时,点击浏览器返回拿不到实时的tab参数,请求不到实时的数据
    v-for渲染出来的列表,要根据不同的状态改变样式,通过给标签添加lang属性完成
    清除每隔5000毫秒请求一次接口的定时器(需求:每当我手动核销电子码,页面上的显示数据要实时更新到)
    ES6数组解构赋值
    es6 var、let、const命令
    canvas计算高度(自定义高度)
    Vue 点击button请求接口,接收不到返回的参数
  • 原文地址:https://www.cnblogs.com/alpha118/p/6769079.html
Copyright © 2020-2023  润新知