Hadoop案例(一)之日志清洗
日志清洗案例
一. 简单解析版
1)需求
去除日志中字段长度小于等于11的日志。
2)输入数据
194.237.142.21 - - [/Sep/::: +] "GET /wp-content/uploads/2013/07/rstudio-git3.png HTTP/1.1" "-" "Mozilla/4.0 (compatible;)"
183.49.46.228 - - [/Sep/::: +] "-" "-" "-"
163.177.71.12 - - [/Sep/::: +] "HEAD / HTTP/1.1" "-" "DNSPod-Monitor/1.0"
163.177.71.12 - - [/Sep/::: +] "HEAD / HTTP/1.1" "-" "DNSPod-Monitor/1.0"
101.226.68.137 - - [/Sep/::: +] "HEAD / HTTP/1.1" "-" "DNSPod-Monitor/1.0"
101.226.68.137 - - [/Sep/::: +] "HEAD / HTTP/1.1" "-" "DNSPod-Monitor/1.0"
60.208.6.156 - - [/Sep/::: +] "GET /wp-content/uploads/2013/07/rcassandra.png HTTP/1.0" "http://cos.name/category/software/packages/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36"
222.68.172.190 - - [/Sep/::: +] "GET /images/my.jpg HTTP/1.1" "http://www.angularjs.cn/A00n" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36"
222.68.172.190 - - [/Sep/::: +] "-" "-" "-"
183.195.232.138 - - [/Sep/::: +] "HEAD / HTTP/1.1" "-" "DNSPod-Monitor/1.0"
183.195.232.138 - - [/Sep/::: +] "HEAD / HTTP/1.1" "-" "DNSPod-Monitor/1.0"
66.249.66.84 - - [/Sep/::: +] "GET /page/6/ HTTP/1.1" "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
221.130.41.168 - - [/Sep/::: +] "GET /feed/ HTTP/1.1" "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36"
157.55.35.40 - - [/Sep/::: +] "GET /robots.txt HTTP/1.1" "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)"
50.116.27.194 - - [/Sep/::: +] "POST /wp-cron.php?doing_wp_cron=1379487095.2510800361633300781250 HTTP/1.0" "-" "WordPress/3.6; http://blog.fens.me"
58.215.204.118 - - [/Sep/::: +] "GET /nodejs-socketio-chat/ HTTP/1.1" "http://www.google.com/url?sa=t&rct=j&q=nodejs%20%E5%BC%82%E6%AD%A5%E5%B9%BF%E6%92%AD&source=web&cd=1&cad=rja&ved=0CCgQFjAA&url=%68%74%74%70%3a%2f%2f%62%6c%6f%67%2e%66%65%6e%73%2e%6d%65%2f%6e%6f%64%65%6a%73%2d%73%6f%63%6b%65%74%69%6f%2d%63%68%61%74%2f&ei=rko5UrylAefOiAe7_IGQBw&usg=AFQjCNG6YWoZsJ_bSj8kTnMHcH51hYQkAA&bvm=bv.52288139,d.aGc" "Mozilla/5.0 (Windows NT 5.1; rv:23.0) Gecko/20100101 Firefox/23.0"
58.215.204.118 - - [/Sep/::: +] "GET /wp-includes/js/jquery/jquery-migrate.min.js?ver=1.2.1 HTTP/1.1" "http://blog.fens.me/nodejs-socketio-chat/" "Mozilla/5.0 (Windows NT 5.1; rv:23.0) Gecko/20100101 Firefox/23.0"
58.215.204.118 - - [/Sep/::: +] "GET /wp-includes/js/jquery/jquery.js?ver=1.10.2 HTTP/1.1" "http://blog.fens.me/nodejs-socketio-chat/" "Mozilla/5.0 (Windows NT 5.1; rv:23.0) Gecko/20100101 Firefox/23.0"
58.215.204.118 - - [/Sep/::: +] "GET /wp-includes/js/comment-reply.min.js?ver=3.6 HTTP/1.1" "http://blog.fens.me/nodejs-socketio-chat/" "Mozilla/5.0 (Windows NT 5.1; rv:23.0) Gecko/20100101 Firefox/23.0"
58.215.204.118 - - [/Sep/::: +] "GET /wp-content/uploads/2013/08/chat.png HTTP/1.1" "http://blog.fens.me/nodejs-socketio-chat/" "Mozilla/5.0 (Windows NT 5.1; rv:23.0) Gecko/20100101 Firefox/23.0"
58.215.204.118 - - [/Sep/::: +] "GET /wp-content/uploads/2013/08/chat2.png HTTP/1.1" "http://blog.fens.me/nodejs-socketio-chat/" "Mozilla/5.0 (Windows NT 5.1; rv:23.0) Gecko/20100101 Firefox/23.0"
58.215.204.118 - - [/Sep/::: +] "GET /wp-content/uploads/2013/08/socketio.png HTTP/1.1" "http://blog.fens.me/nodejs-socketio-chat/" "Mozilla/5.0 (Windows NT 5.1; rv:23.0) Gecko/20100101 Firefox/23.0"
58.248.178.212 - - [/Sep/::: +] "GET /nodejs-grunt-intro/ HTTP/1.1" "http://blog.fens.me/series-nodejs/" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; MDDR; InfoPath.2; .NET4.0C)"
58.248.178.212 - - [/Sep/::: +] "GET /wp-includes/js/jquery/jquery-migrate.min.js?ver=1.2.1 HTTP/1.1" "http://blog.fens.me/nodejs-grunt-intro/" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; MDDR; InfoPath.2; .NET4.0C)"
3)实现代码
(1)编写LogMapper
package com.xyg.mapreduce.weblog;
import java.io.IOException;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper; public class LogMapper extends Mapper<LongWritable, Text, Text, NullWritable>{ Text k = new Text(); @Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { // 1 获取1行数据
String line = value.toString();
// 2 解析日志
boolean result = parseLog(line,context);
// 3 日志不合法退出
if (!result) {
return;
}
// 4 设置key
k.set(line);
// 5 写出数据
context.write(k, NullWritable.get());
}
// 2 解析日志
private boolean parseLog(String line, Context context) {
// 1 截取
String[] fields = line.split(" "); // 2 日志长度大于11的为合法
if (fields.length > ) {
// 系统计数器
context.getCounter("map", "true").increment();
return true;
}else {
context.getCounter("map", "false").increment();
return false;
}
}
}
(2)编写LogDriver
package com.xyg.mapreduce.weblog; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; public class LogDriver { public static void main(String[] args) throws Exception {
args = new String[] { "e:/inputlog", "e:/output1" };
// 1 获取job信息
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
// 2 加载jar包
job.setJarByClass(LogDriver.class);
// 3 关联map
job.setMapperClass(LogMapper.class);
// 4 设置最终输出类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(NullWritable.class);
// 5 设置输入和输出路径
FileInputFormat.setInputPaths(job, new Path(args[]));
FileOutputFormat.setOutputPath(job, new Path(args[]));
// 6 提交
job.waitForCompletion(true);
}
}
二. 复杂解析版
1)需求
对web访问日志中的各字段识别切分
去除日志中不合法的记录
根据统计需求,生成各类访问请求过滤数据
2)输入数据
194.237.142.21 - - [/Sep/::: +] "GET /wp-content/uploads/2013/07/rstudio-git3.png HTTP/1.1" "-" "Mozilla/4.0 (compatible;)"
183.49.46.228 - - [/Sep/::: +] "-" "-" "-"
163.177.71.12 - - [/Sep/::: +] "HEAD / HTTP/1.1" "-" "DNSPod-Monitor/1.0"
163.177.71.12 - - [/Sep/::: +] "HEAD / HTTP/1.1" "-" "DNSPod-Monitor/1.0"
101.226.68.137 - - [/Sep/::: +] "HEAD / HTTP/1.1" "-" "DNSPod-Monitor/1.0"
101.226.68.137 - - [/Sep/::: +] "HEAD / HTTP/1.1" "-" "DNSPod-Monitor/1.0"
60.208.6.156 - - [/Sep/::: +] "GET /wp-content/uploads/2013/07/rcassandra.png HTTP/1.0" "http://cos.name/category/software/packages/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36"
222.68.172.190 - - [/Sep/::: +] "GET /images/my.jpg HTTP/1.1" "http://www.angularjs.cn/A00n" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36"
222.68.172.190 - - [/Sep/::: +] "-" "-" "-"
183.195.232.138 - - [/Sep/::: +] "HEAD / HTTP/1.1" "-" "DNSPod-Monitor/1.0"
183.195.232.138 - - [/Sep/::: +] "HEAD / HTTP/1.1" "-" "DNSPod-Monitor/1.0"
66.249.66.84 - - [/Sep/::: +] "GET /page/6/ HTTP/1.1" "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
221.130.41.168 - - [/Sep/::: +] "GET /feed/ HTTP/1.1" "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36"
157.55.35.40 - - [/Sep/::: +] "GET /robots.txt HTTP/1.1" "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)"
50.116.27.194 - - [/Sep/::: +] "POST /wp-cron.php?doing_wp_cron=1379487095.2510800361633300781250 HTTP/1.0" "-" "WordPress/3.6; http://blog.fens.me"
58.215.204.118 - - [/Sep/::: +] "GET /nodejs-socketio-chat/ HTTP/1.1" "http://www.google.com/url?sa=t&rct=j&q=nodejs%20%E5%BC%82%E6%AD%A5%E5%B9%BF%E6%92%AD&source=web&cd=1&cad=rja&ved=0CCgQFjAA&url=%68%74%74%70%3a%2f%2f%62%6c%6f%67%2e%66%65%6e%73%2e%6d%65%2f%6e%6f%64%65%6a%73%2d%73%6f%63%6b%65%74%69%6f%2d%63%68%61%74%2f&ei=rko5UrylAefOiAe7_IGQBw&usg=AFQjCNG6YWoZsJ_bSj8kTnMHcH51hYQkAA&bvm=bv.52288139,d.aGc" "Mozilla/5.0 (Windows NT 5.1; rv:23.0) Gecko/20100101 Firefox/23.0"
58.215.204.118 - - [/Sep/::: +] "GET /wp-includes/js/jquery/jquery-migrate.min.js?ver=1.2.1 HTTP/1.1" "http://blog.fens.me/nodejs-socketio-chat/" "Mozilla/5.0 (Windows NT 5.1; rv:23.0) Gecko/20100101 Firefox/23.0"
58.215.204.118 - - [/Sep/::: +] "GET /wp-includes/js/jquery/jquery.js?ver=1.10.2 HTTP/1.1" "http://blog.fens.me/nodejs-socketio-chat/" "Mozilla/5.0 (Windows NT 5.1; rv:23.0) Gecko/20100101 Firefox/23.0"
58.215.204.118 - - [/Sep/::: +] "GET /wp-includes/js/comment-reply.min.js?ver=3.6 HTTP/1.1" "http://blog.fens.me/nodejs-socketio-chat/" "Mozilla/5.0 (Windows NT 5.1; rv:23.0) Gecko/20100101 Firefox/23.0"
58.215.204.118 - - [/Sep/::: +] "GET /wp-content/uploads/2013/08/chat.png HTTP/1.1" "http://blog.fens.me/nodejs-socketio-chat/" "Mozilla/5.0 (Windows NT 5.1; rv:23.0) Gecko/20100101 Firefox/23.0"
58.215.204.118 - - [/Sep/::: +] "GET /wp-content/uploads/2013/08/chat2.png HTTP/1.1" "http://blog.fens.me/nodejs-socketio-chat/" "Mozilla/5.0 (Windows NT 5.1; rv:23.0) Gecko/20100101 Firefox/23.0"
58.215.204.118 - - [/Sep/::: +] "GET /wp-content/uploads/2013/08/socketio.png HTTP/1.1" "http://blog.fens.me/nodejs-socketio-chat/" "Mozilla/5.0 (Windows NT 5.1; rv:23.0) Gecko/20100101 Firefox/23.0"
58.248.178.212 - - [/Sep/::: +] "GET /nodejs-grunt-intro/ HTTP/1.1" "http://blog.fens.me/series-nodejs/" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; MDDR; InfoPath.2; .NET4.0C)"
58.248.178.212 - - [/Sep/::: +] "GET /wp-includes/js/jquery/jquery-migrate.min.js?ver=1.2.1 HTTP/1.1" "http://blog.fens.me/nodejs-grunt-intro/" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; MDDR; InfoPath.2; .NET4.0C)"
3)实现代码
(1)定义一个bean,用来记录日志数据中的各数据字段
package com.xyg.mapreduce.log;
public class LogBean {
private String remote_addr;// 记录客户端的ip地址
private String remote_user;// 记录客户端用户名称,忽略属性"-"
private String time_local;// 记录访问时间与时区
private String request;// 记录请求的url与http协议
private String status;// 记录请求状态;成功是200
private String body_bytes_sent;// 记录发送给客户端文件主体内容大小
private String http_referer;// 用来记录从那个页面链接访问过来的
private String http_user_agent;// 记录客户浏览器的相关信息
private boolean valid = true;// 判断数据是否合法
public String getRemote_addr() {
return remote_addr;
}
public void setRemote_addr(String remote_addr) {
this.remote_addr = remote_addr;
}
public String getRemote_user() {
return remote_user;
}
public void setRemote_user(String remote_user) {
this.remote_user = remote_user;
}
public String getTime_local() {
return time_local;
}
public void setTime_local(String time_local) {
this.time_local = time_local;
}
public String getRequest() {
return request;
}
public void setRequest(String request) {
this.request = request;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getBody_bytes_sent() {
return body_bytes_sent;
}
public void setBody_bytes_sent(String body_bytes_sent) {
this.body_bytes_sent = body_bytes_sent;
}
public String getHttp_referer() {
return http_referer;
}
public void setHttp_referer(String http_referer) {
this.http_referer = http_referer;
}
public String getHttp_user_agent() {
return http_user_agent;
}
public void setHttp_user_agent(String http_user_agent) {
this.http_user_agent = http_user_agent;
}
public boolean isValid() {
return valid;
}
public void setValid(boolean valid) {
this.valid = valid;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(this.valid);
sb.append("\001").append(this.remote_addr);
sb.append("\001").append(this.remote_user);
sb.append("\001").append(this.time_local);
sb.append("\001").append(this.request);
sb.append("\001").append(this.status);
sb.append("\001").append(this.body_bytes_sent);
sb.append("\001").append(this.http_referer);
sb.append("\001").append(this.http_user_agent);
return sb.toString();
}
}
(2)编写LogMapper程序
package com.xyg.mapreduce.log;
import java.io.IOException;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper; public class LogMapper extends Mapper<LongWritable, Text, Text, NullWritable>{
Text k = new Text(); @Override
protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
// 1 获取1行
String line = value.toString();
// 2 解析日志是否合法
LogBean bean = pressLog(line);
if (!bean.isValid()) {
return;
}
k.set(bean.toString());
// 3 输出
context.write(k, NullWritable.get());
} // 解析日志
private LogBean pressLog(String line) {
LogBean logBean = new LogBean();
// 1 截取
String[] fields = line.split(" ");
if (fields.length > ) {
// 2封装数据
logBean.setRemote_addr(fields[]);
logBean.setRemote_user(fields[]);
logBean.setTime_local(fields[].substring());
logBean.setRequest(fields[]);
logBean.setStatus(fields[]);
logBean.setBody_bytes_sent(fields[]);
logBean.setHttp_referer(fields[]); if (fields.length > ) {
logBean.setHttp_user_agent(fields[] + " "+ fields[]);
}else {
logBean.setHttp_user_agent(fields[]);
}
// 大于400,HTTP错误
if (Integer.parseInt(logBean.getStatus()) >= ) {
logBean.setValid(false);
}
}else {
logBean.setValid(false);
}
return logBean;
}
}
(3)编写LogDriver程序
package com.xyg.mapreduce.log;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; public class LogDriver {
public static void main(String[] args) throws Exception {
// 1 获取job信息
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
// 2 加载jar包
job.setJarByClass(LogDriver.class);
// 3 关联map
job.setMapperClass(LogMapper.class);
// 4 设置最终输出类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(NullWritable.class);
// 5 设置输入和输出路径
FileInputFormat.setInputPaths(job, new Path(args[]));
FileOutputFormat.setOutputPath(job, new Path(args[]));
// 6 提交
job.waitForCompletion(true);
}
}
Hadoop案例(一)之日志清洗的更多相关文章
- discuz论坛apache日志hadoop大数据分析项目:清洗数据核心功能解说及代码实现
discuz论坛apache日志hadoop大数据分析项目:清洗数据核心功能解说及代码实现http://www.aboutyun.com/thread-8637-1-1.html(出处: about云 ...
- 用 shell 脚本做日志清洗
问题的提出 公司有一个用户行为分析系统,可以记录用户在使用公司产品过程中的一系列操作轨迹,便于分析产品使用情况以便优化产品 UI 界面布局.这套系统有点类似于 Google Analyse(GA),所 ...
- Hadoop案例(五)过滤日志及自定义日志输出路径(自定义OutputFormat)
过滤日志及自定义日志输出路径(自定义OutputFormat) 1.需求分析 过滤输入的log日志中是否包含xyg (1)包含xyg的网站输出到e:/xyg.log (2)不包含xyg的网站输出到e: ...
- Hive学习之四 《Hive分区表场景案例应用案例,企业日志加载》 详解
文件的加载,只需要三步就够了,废话不多说,来直接的吧. 一.建表 话不多说,直接开始. 建表,对于日志文件来说,最后有分区,在此案例中,对年月日和小时进行了分区. 建表tracktest_log,分隔 ...
- Hadoop学习之Hadoop案例分析
一.日志数据分析1.背景1.1 ***论坛日志,数据分为两部分组成,原来是一个大文件,是56GB:以后每天生成一个文件,大约是150-200MB之间: 每行记录有5部分组成:1.访问ip:2.访问时间 ...
- Hadoop案例(十)WordCount
WordCount案例 需求1:统计一堆文件中单词出现的个数(WordCount案例) 0)需求:在一堆给定的文本文件中统计输出每一个单词出现的总次数 1)数据准备:Hello.txt hello w ...
- 二、基于hadoop的nginx访问日志分析---计算日pv
代码: # pv_day.py#!/usr/bin/env python # coding=utf-8 from mrjob.job import MRJob from nginx_accesslog ...
- 一、基于hadoop的nginx访问日志分析---解析日志篇
前一阵子,搭建了ELK日志分析平台,用着挺爽的,再也不用给开发拉各种日志,节省了很多时间. 这篇博文是介绍用python代码实现日志分析的,用MRJob实现hadoop上的mapreduce,可以直接 ...
- Hadoop:实战Web日志分析
示例场景 日志说明 有两台Web服务器,日志文件存放在/usr/local/nginx/logs/目录,日志默认为nginx定义格式.如: 123.13.17.13 - - [25/Aug/2016: ...
随机推荐
- Android之框架20160721
Android的四层架构分别为:Linux2.6内核层,核心库层,应用框架层,应用层. 其中Framework层为我们开发应用程序提供了非常多的API,我们通过调用特殊的API构造我们的APP,满足我 ...
- dorado事件
//----------------------------------------------------------------------------// //校验实体数据是否填写if(enti ...
- Measure the size of a PostgreSQL table row
Q: I have a PostgreSQL table. select * is very slow whereas select id is nice and quick. I think i ...
- C++ ------ 互斥锁、原子操作的性能测试
atomic原子操作:是在新标准C++11,引入了原子操作的概念,并通过这个新的头文件提供了多种原子操作数据类型,例如,atomic_bool,atomic_int等等 测试程序 #include & ...
- Installing kubectl
Installing kubectl Kubernetes uses a command-line utility called kubectl for communicating with the ...
- libuv移植到android
编译环境是linux + ndk,你要先添加好NDK路径的环境变量,然后进入libuv目录执行以下两句完成编译. $ source ./android-configure $NDK gyp $ mak ...
- [LeetCode] “全排列”问题系列(一) - 用交换元素法生成全排列及其应用,例题: Permutations I 和 II, N-Queens I 和 II,数独问题
一.开篇 Permutation,排列问题.这篇博文以几道LeetCode的题目和引用剑指offer上的一道例题入手,小谈一下这种类型题目的解法. 二.上手 最典型的permutation题目是这样的 ...
- LeetCode-Insertion Sort List[AC源码]
package com.lw.leet5; /** * @ClassName:Solution * @Description: * Insertion Sort List * Sort a linke ...
- CF540 D 概率 DP
石头剪刀布三种生物(?) 随机战斗,最后三方各自只有自己方存活下来的概率是多少. 局面的转移明显,注意任选两方决定战斗时有可能出现选了同个种类的,因此注意排除掉同种的组合,也就是条件概率什么的. /* ...
- IIC总线学习
IIC总线 IIC协议简要说明: 1.2条双向串行线,一条数据线称为SDA,一条时钟线SCL,双向半双工 2.传输的设备之间只是简单的主从关系,主机可以作为主机发送也可以作为主机接收,任何时候只能由一 ...