首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【技术分享】TFRecord 实践

【技术分享】TFRecord 实践

原创
作者头像
腾讯云TI平台
发布于 2019-07-03 06:39:41
发布于 2019-07-03 06:39:41
2.3K00
代码可运行
举报
文章被收录于专栏:腾讯云TI平台腾讯云TI平台
运行总次数:0
代码可运行

文章作者:张舒婷,经授权发布。

why use TFRecord

对于数据量较小而言,可能一般选择直接将数据加载进内存,然后再分batch输入网络进行训练。但是,如果数据量较大,这样的方法就不适用了,因为太耗内存,所以这时最好使用 tensorflow 提供的队列 queue,也就是第二种方法从文件读取数据。对于一些特定的读取,比如csv文件格式,官网有相关的描述。而 TFRecords 是tensorflow 的内定标准形式,更加高效的读取方法。 Tensorflow 读取数据的三种方式:

  • Preloaded data: 预加载数据 将数据直接内嵌到Graph中,再把Graph传入Session中运行。当数据量比较大时,Graph的传输会遇到效率问题。import tensorflow as tf # 设计Graph x1 = tf.constant([2, 3, 4]) x2 = tf.constant([4, 0, 1]) y = tf.add(x1, x2) # 打开一个session --> 计算y with tf.Session() as sess: print sess.run(y)
  • Feeding: Python产生数据,再把数据喂给后端 用占位符替代数据,待运行的时候填充数据。 import tensorflow as tf # 设计Graph x1 = tf.placeholder(tf.int16) x2 = tf.placeholder(tf.int16) y = tf.add(x1, x2) # 用Python产生数据 li1 = [2, 3, 4] li2 = [4, 0, 1] # 打开一个session --> 喂数据 --> 计算y with tf.Session() as sess: print sess.run(y, feed_dict={x1: li1, x2: li2}) 切记feed_dict{}的数据不可以是tensor格式,会引起错误:TypeError: The value of a feed cannot be a tf.Tensor object. Acceptable feed values include Python scalars, strings, lists, or numpy ndarrays.关于这个问题的讨论,在tensorflow也开了issue,但并没有解决方案。
  • Reading from file: 从文件中直接读取 前两种方法很方便,但是遇到大型数据的时候就会很吃力,即使是Feeding,中间环节的增加也是不小的开销,比如数据类型转换等等。最优的方案就是在Graph定义好文件读取的方法,让TF自己去从文件中读取数据,并解码成可使用的样本集。
how to generate/parse TFRecod and its mechanism

在TensorFlow官方github文档中example.proto的文件,这个文件详细说明了TensorFlow里面的example协议。tensorflow的example包含的是基于key-value对的存储方法,其中key是一个字符串,其映射到的是feature信息,feature包含三种类型:

BytesList:字符串列表 FloatList:浮点数列表 Int64List:64位整数列表

以上三种类型都是列表类型,意味着都能够进行拓展,但是也是因为这种弹性格式,所以在解析的时候,需要制定解析参数。

在TensorFlow中,example是按行读取,比如存储 M×NM×N矩阵,使用ByteList存储的话,需要M×NM×N大小的列表,按照每一行的读取方式存放。 官方样例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
An Example for a movie recommendation application:
   features {
     feature {
       key: "age"
       value { float_list {
         value: 29.0
       }}
     }
     feature {
       key: "movie"
       value { bytes_list {
         value: "The Shawshank Redemption"
         value: "Fight Club"
       }}
     }
     feature {
       key: "movie_ratings"
       value { float_list {
         value: 9.0
         value: 9.7
       }}
     }
     feature {
       key: "suggestion"
       value { bytes_list {
         value: "Inception"
       }}
     }
  1. 如果一个example的feature K 的数据类型是 T,那么所有其他的所有feature K都应该是这个数据类型
  2. feature K 的value list的item个数可能在不同的example中是不一样多的,这个取决于你的需求
  3. 如果在一个example中没有feature K,那么如果在解析的时候指定一个默认值的话,那么将会返回一个默认值
  4. 如果一个feature k 不包含任何的value值,那么将会返回一个空的tensor而不是默认值

除了单个example构成的feature外,tensorflow还提供了sequence example,表示一个或者多个example,同时还包括上下文context,其中,context表示的是feature_lists的总体特征,如数据集的长度等,feature_list包含一个key,一个value,value表示的是features集合(feature_lists),同样,官方源码也给出了sequence_example的例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
context: {
   feature: {
     key  : "locale"
     value: {
       bytes_list: {
         value: [ "pt_BR" ]
       }
     }
   }
   feature: {
     key  : "age"
     value: {
       float_list: {
         value: [ 19.0 ]
       }
     }
   }
   feature: {
     key  : "favorites"
     value: {
       bytes_list: {
         value: [ "Majesty Rose", "Savannah Outen", "One Direction" ]
       }
     }
   }
 }
 feature_lists: {
   feature_list: {
     key  : "movie_ratings"
     value: {
       feature: {
         float_list: {
           value: [ 4.5 ]
         }
       }
       feature: {
         float_list: {
           value: [ 5.0 ]
         }
       }
     }
   }
   feature_list: {
     key  : "movie_names"
     value: {
       feature: {
         bytes_list: {
           value: [ "The Shawshank Redemption" ]
         }
       }
       feature: {
         bytes_list: {
           value: [ "Fight Club" ]
         }
       }
     }
   }
   feature_list: {
     key  : "actors"
     value: {
       feature: {
         bytes_list: {
           value: [ "Tim Robbins", "Morgan Freeman" ]
         }
       }
       feature: {
         bytes_list: {
           value: [ "Brad Pitt", "Edward Norton", "Helena Bonham Carter" ]
         }
       }
     }
   }
 }

除此之外,官网还有一些其他一致性的例子,可供参考。

  • Generate TFRecord 如果将数据集转换为TFRecord,以COCO数据集的image caption为例,每张图片为jpeg格式,有一个编号,每个image对应5条caption;caption存在于annotation.json文件中,json文件的文件结构如下 REF

captions_train2017.json主结构 { “info”: info, “licenses”: [license], “images”: [image], “annotations”: [annotation] } [info] { “year”: int, “version”: str, “description”: str, “contributor”: str, “url”: str, “date_created”: datetime, } [license] { “id”: int, “name”: str, “url”: str, } [image] { “id”: int, “width”: int, “height”: int, “file_name”: str, “license”: int, “flickr_url”: str, “coco_url”: str, “date_captured”: datetime, } [annotation] { “id”: int, “image_id”: int, “caption”: str } 例如 { “image_id”: 179765, “id”: 38, “caption”: “A black Honda motorcycle parked in front of a garage.” }

形成TFRecord则可以用如下代码(来自于tensorflow/models/research/im2txt/build_coco):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
### other function

def _int64_feature(value):
  """Wrapper for inserting an int64 Feature into a SequenceExample proto."""
  return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))


def _bytes_feature(value):
  """Wrapper for inserting a bytes Feature into a SequenceExample proto."""
  return tf.train.Feature(bytes_list=tf.train.BytesList(value=[str(value)]))


def _int64_feature_list(values):
  """Wrapper for inserting an int64 FeatureList into a SequenceExample proto."""
  return tf.train.FeatureList(feature=[_int64_feature(v) for v in values])


def _bytes_feature_list(values):
  """Wrapper for inserting a bytes FeatureList into a SequenceExample proto."""
  return tf.train.FeatureList(feature=[_bytes_feature(v) for v in values])

### 
with tf.gfile.FastGFile(image.filename, "r") as f:
  encoded_image = f.read()

try:
  decoder.decode_jpeg(encoded_image) ## tensor->nparray
except (tf.errors.InvalidArgumentError, AssertionError):
  print("Skipping file with invalid JPEG data: %s" % image.filename)
  return

context = tf.train.Features(feature={
    "image/image_id": _int64_feature(image.image_id),
    "image/data": _bytes_feature(encoded_image),
}) ## context config

assert len(image.captions) == 1
caption = image.captions[0]
caption_ids = [vocab.word_to_id(word) for word in caption]
feature_lists = tf.train.FeatureLists(feature_list={
    "image/caption": _bytes_feature_list(caption),
    "image/caption_ids": _int64_feature_list(caption_ids)
}) ## feature list config
sequence_example = tf.train.SequenceExample(
    context=context, feature_lists=feature_lists) ## sequence Example

实际处理过程中抽取了json文件中的”image_id”, “filename”, “captions”三个key 对应的值写成example,同时还引入了线程处理文件,以加快速度。

TFRecord解析函数常用的有三个:分别是tf.parse_example, tf.parse_single_example, tf.parse_single_sequence_example,接下来分别介绍:

parse_example的方法定义: def parse_example(serialized, features, name=None, example_names=None) parse_example是把example解析为词典型的tensor 参数含义: serialized:一个batch的序列化的example features:解析example的规则 name:当前操作的名字 example_name:当前解析example的proto名称 tf.parse_single_exampleparse_example少了batch的参数,每一次只解析一个example。

这里重点要说的是第二个参数,也就是features,features是把serialized的example中按照键值映射到三种tensor: 1,VarlenFeature 2, SparseFeature 3,FixedLenFeature,下面对这三种映射方式做一个简要的叙述:

  1. VarlenFeature: 是按照键值把example的value映射到SpareTensor对象:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# serialized data
 serialized = [
    features
      { feature { key: "ft" value { float_list { value: [1.0, 2.0] } } } },
    features
      { feature []},
    features
      { feature { key: "ft" value { float_list { value: [3.0] } } }
  ]
# VarlenFeature的使用方法是
features={
    "ft":tf.VarLenFeature(tf.float32)
}
# get
{"ft": SparseTensor(indices=[[0, 0], [0, 1], [2, 0]],
                      values=[1.0, 2.0, 3.0],
                      dense_shape=(3, 2)) }
  1. FixedLenFeature FixedLenFeature是按照键值对将features映射到大小为[serilized.size(),df.shape]的矩阵,这里的FixLenFeature指的是每个键值对应的feature的size是一样的:# serialized data as before # FixedLenFeature usage features: { "ft": FixedLenFeature([2], dtype=tf.float32, default_value=-1), } # get <maybe cause run error for varlenSeries> {"ft": [[1.0, 2.0], [3.0, -1.0]]}
  2. SparseFeature# serialized [ features { feature { key: "val" value { float_list { value: [ 0.5, -1.0 ] } } } feature { key: "ix" value { int64_list { value: [ 3, 20 ] } } } }, features { feature { key: "val" value { float_list { value: [ 0.0 ] } } } feature { key: "ix" value { int64_list { value: [ 42 ] } } } } ] # And arguments example_names: ["input0", "input1"], features: { "sparse": SparseFeature( index_key="ix", value_key="val", dtype=tf.float32, size=100), } # output is a dictionary: { "sparse": SparseTensor( indices=[[0, 3], [0, 20], [1, 42]], values=[0.5, -1.0, 0.0] dense_shape=[2, 100]), } tf.parse_single_sequence_example对应解析sequenceExample,具体例子如下,对于不定长数据,tensorflow也提供自动补齐的功能,在tf.train.batch, tf.train.batch_join, tf.train.shuffle_batch, tf.train.shuffle_batch_join相关的函数中:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import tensorflow as tf
import os
keys=[[1.0,2.0],[2.0,3.0]]
sess=tf.InteractiveSession()
sess.run(tf.global_variables_initializer())
def make_example(locale,age,score,times):
    example = tf.train.SequenceExample(
        context=tf.train.Features(
            feature={    "locale":tf.train.Feature(bytes_list=tf.train.BytesList(value=[locale])),       "age":tf.train.Feature(int64_list=tf.train.Int64List(value=[age]))
        }),
        feature_lists=tf.train.FeatureLists(
            feature_list={
 "movie_rating":tf.train.FeatureList(feature=[tf.train.Feature(float_list=tf.train.FloatList(value=score)) for i in range(times)])
            }
        )
    )
    return example.SerializeToString()
context_features = {
    "locale": tf.FixedLenFeature([],dtype=tf.string),
    "age": tf.FixedLenFeature([],dtype=tf.int64)
}
sequence_features = {
    "movie_rating": tf.FixedLenSequenceFeature([3], dtype=tf.float32,allow_missing=True)
}
context_parsed, sequence_parsed  = tf.parse_single_sequence_example(make_example("china",24,[1.0,3.5,4.0],2),context_features=context_features,sequence_features=sequence_features)
print tf.contrib.learn.run_n(context_parsed)
print tf.contrib.learn.run_n(sequence_parsed)
# get
[{'locale': 'china', 'age': 24}]

[{'movie_rating': array([[ 1. ,  3.5,  4. ],
       [ 1. ,  3.5,  4. ]], dtype=float32)}]
Tensorflow中线程及队列

上图的过程是先创建一个先入先出的队列(FIFOQueue),并将其内部所有元素初始化为零。然后构建TensorFlow图,它从队列前端取走一个元素,加上1之后,放回队列的后端ref1,ref2

除了先入先出队列,tensorflow还提供RandomShuffleQueue实现异步计算。在实现过程中,需要所有线程都必须能被同步终止,异常必须能被正确捕获并报告,Session终止的时候, 队列必须能被正确地关闭。为了保证上述过程正常进行,Tensorflow提供了tf.Coordinatortf.QueueRunner两个实现多线程。从设计上这两个类必须被一起使用。Coordinator类可以用来同时停止多个工作线程并且向那个在等待所有工作线程终止的程序报告异常。QueueRunner类用来协调多个工作线程同时将多个张量推入同一个队列中。

  • Coordinator类用来帮助多个线程协同工作,多个线程同步终止。 其主要方法有: should_stop(): 如果线程应该停止则返回True。 request_stop(<exception>): 请求该线程停止outofRangeErrorjoin(<list of threads>): 等待被指定的线程终止。

首先创建一个Coordinator对象,然后建立一个或多个使用Coordinator对象的线程。这些线程通常一直循环运行,一直到should_stop()返回True时停止。 任何线程都可以决定计算什么时候应该停止。它只需要调用request_stop(),同时其他线程的should_stop()将会返回True,然后所有线程都停下来。

  • QueueRunner类会创建一组线程

这些线程可以重复的执行Enquene操作, 他们使用同一个Coordinator来处理线程同步终止。此外,一个QueueRunner会运行一个closer thread,当Coordinator收到异常报告时,这个closer thread会自动关闭队列。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
example = ...ops to create one example...
# Create a queue, and an op that enqueues examples one at a time in the queue.
queue = tf.RandomShuffleQueue(...)
enqueue_op = queue.enqueue(example)
# Create a training graph that starts by dequeuing a batch of examples.
inputs = queue.dequeue_many(batch_size)
train_op = ...use 'inputs' to build the training part of the graph...
文件TFRecord读取/写入机制及其调用方法
TFRecord 写 tf.TFRecordWriter

假设serilized_object是一个已经序列化好的example,那么其写的过程如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
writer = tf.python_io.TFRecordWriter(filename)
writer.write(serilized_object)
writer.close()
TFRecord 读 tf.TFRecordReader

在上图中,首先由一个单线程把文件名堆入FIFO队列,两个Reader同时从队列中取文件名并读取数据,Decoder(parse)读出的数据解析后堆入样本队列,最后单个或批量取出样本(图中没有展示样本出列)。

具体的将文件名列表交给tf.train.string_input_producer函数生成一个先入先出的队列, 文件阅读器会需要它来读取数据。

string_input_producer 提供的可配置参数来设置文件名乱序和最大的训练迭代数, QueueRunner会为每次迭代(epoch)将所有的文件名加入文件名队列中, 如果shuffle=True的话, 会对文件名进行乱序处理。这一过程是比较均匀的,因此它可以产生均衡的文件名队列。

这个QueueRunner的工作线程是独立于文件阅读器的线程, 因此乱序和将文件名推入到文件名队列这些过程不会阻塞文件阅读器运行。

在上图中数据输入流图的末端, 我们需要有另一个队列来执行输入样本的训练,评价和推理。因此我们使用tf.train.batch, tf.train.batch_join, tf.train.shuffle_batch, tf.train.shuffle_batch_join 函数来对队列中的样本进行处理,Batch 读取实例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Batching

def read_my_file_format(filename_queue):
 reader = tf.SomeReader() # tf.TFRecordReader()
 key, record_string = reader.read(filename_queue) # queue
 example, label = some_decoder(record_string) # parse example opt
 processed_example = some_processing(example) # example processing
 return processed_example, label

def input_pipeline(filenames, batch_size, num_epochs=None):
# put TFRecord into queue, num_epochs is number of epochs and  need to be local_initialized, if not specified, it will consistent read until the queue is outOfRange.
 filename_queue = tf.train.string_input_producer(
     filenames, num_epochs=num_epochs, shuffle=True) 
 example, label = read_my_file_format(filename_queue)
 # min_after_dequeue defines how big a buffer we will randomly sample
 #   from -- bigger means better shuffling but slower start up and more
 #   memory used.
 # capacity must be larger than min_after_dequeue and the amount larger
 #   determines the maximum we will prefetch.  Recommendation:
 #   min_after_dequeue + (num_threads + a small safety margin) * batch_size
 min_after_dequeue = 10000
 capacity = min_after_dequeue + 3 * batch_size
 example_batch, label_batch = tf.train.shuffle_batch(
     [example, label], batch_size=batch_size, capacity=capacity,
     min_after_dequeue=min_after_dequeue)
 return example_batch, label_batch

在tensorflow计算图未开始时,实际上上述过程只是配置了队列读取的相关参数和读取方式,队列中还没有任何数据,结合上一步骤的函数定义,需要用下述方式进行调用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import tensorflow as tf

def run_training():
    with tf.Graph().as_default(), tf.Session() as sess:
        datas,labels = input_pipeline("example.tfrecords",32)
        c = config()
        initializer = tf.random_uniform_initializer(-1*c.init_scale,1*c.init_scale)
        with tf.variable_scope("model",initializer=initializer):
            model = ModelFunction(config=c,data=datas,label=labels)

        fetches = [model.train_op,model.accuracy,model.loss]

        #init
        init_op = tf.group(tf.global_variables_initializer(),
                       tf.local_variables_initializer())
        sess.run(init_op)

        coord = tf.train.Coordinator()
        threads = tf.train.start_queue_runners(sess=sess,coord=coord)
        try:
            while not coord.should_stop():
                _,accuracy,loss= sess.run(fetches)
        except tf.errors.OutOfRangeError:
            print("done training")
        finally:
            coord.request_stop()
        coord.join(threads)
        sess.close()

def main():
    run_training()

if __name__=='__main__':
    main()

这个例子中并没有对输入文件序列再次重新入队操作,即只是实现了一开始流图的第一阶段,然后就进入解析,构建batch的阶段。即是单个Reader,多个样本的读取方式(train.batch相同),如果使用train.batch_join, train.batch_shuffle_join即是多个Reader,多个样本的读取方式。单Reader时,2个线程就达到了速度的极限。多Reader时,2个Reader就达到了极限。所以并不是线程越多越快,甚至更多的线程反而会使效率下降[ref1], [ref2]。在COCO数据集处理的过程中,使用了单个Reader,单个Reader有四个线程处理(batch_join中Tensor List大小为4)。

这里需要注意的是,一定要全局初始化和局部初始化(tf.train.string_input_producer中的num_epoch是局部参数),但是有时候使用 tf.group() 的方式初始化可能不成功,可以单独分两次进行初始化,参见。 队列的开启使用的是tf.train.start_queue_runners,具体有关Coordinator的使用。

实际训练

在使用tf.contrib.slim.learning.train实现训练的时候,tf.contrib.slim.learning.train函数中已经设置了coordinater, QueneRunner等,并且也增加了初始化设置,因此只需要准备好batch数据即可。具体tf.contrib.slim.learning.train的内容可以参见源码。

常见错误
  1. OutofRange(): 未对队列读取抛出的异常进行处理
  2. OP_REQUIRES failed数据处理过程中出现错误,包括维度不匹配 Dim error文件读取问题 文件损坏,存在空行等
  3. 文件编码问题 UnicodeDecodeError
  4. 队列冲突等问题,这里在读取文件的时候对于线程的设置一定需要注意。其他参考资料: Tensorflow 输入数据处理框架 TensorFlow queuing and threading 不同QueueRunner的使用方法

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
折腾随身wifi过程中的亿点小记(上):备份刷机
备份之前需要安装相关的软件环境、驱动等,在这篇博客 『设备刷机需要的软件 | 宁宁's Blog (momoe.ml) 』中介绍得很全面。当然也不需要全部用到,只需要了解这么几个软件即可:
知识分子没文化
2023/07/01
15.5K1
折腾随身wifi过程中的亿点小记(上):备份刷机
随身WiFi刷OpenWRT 榨干它!
注意: 刷机完后,注意解决USB网络共享问题。详情参考上一篇文章。正常情况下,插入USB后,会出现相应的网段。
逍遥子大表哥
2025/07/28
8190
随身WiFi刷OpenWRT 榨干它!
android adb shell 常用命令
mac: /Users/xx/Library/Android/sdk/tools/bin archquery jobb monkeyrunner sdkmanager avdmanager lint screenshot2 uiautomatorviewer
tea9
2022/09/08
3.7K0
【Android 系统开发】CyanogenMod 13.0 源码下载 编译 ROM 制作 ( 手机平台 : 小米4 | 编译平台 : Ubuntu 14.04 LTS 虚拟机)
转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/51592930
韩曙亮
2023/03/27
4.1K0
【Android 系统开发】CyanogenMod 13.0  源码下载 编译 ROM 制作  ( 手机平台 : 小米4 | 编译平台 : Ubuntu 14.04 LTS 虚拟机)
玩转ADB命令(ADB命令使用大全)
我相信做Android开发的朋友都用过ADB命令,但是也只是限于安装应用push文件和设备重启相关,更深的就不知道了,其实我们完全可以了解多一点,有一些不常用的场景我们至少应该知道它可以做到,比如,我们知道adb install 却不知道adb shell am start。前者是用来安装软件,后者用来打开软件,后者的一个使用场景让我对他重视:公司定制Android系统,在调试屏幕的时候要看是否满屏验证驱动是否正常,比较麻烦的做法是要拿到Android开发者手里用eclipse或者其他ide安装打开。显然相对于驱动人员连上数据线使用adb命令要复杂得多。因此,了解多一点还是很有必要的。
全栈程序员站长
2022/08/27
10.5K0
玩转ADB命令(ADB命令使用大全)
Android ROM 制作教程
大家好,又见面了,我是全栈君,祝每个程序员都可以多学几门语言。 本文来自: 起点手机论坛 具体文章參考:http://www.qdppc.com/forum.php?mod=viewthread&ti
全栈程序员站长
2021/12/15
3.2K0
android 功耗(1)---android 功耗分析方法和优化
底电流在手机飞行模式下调试。每个平台的底电流数据可能不一样,具体可以参考release出来的Current Consumption Data文档或者release note。一般情况下的底电流参考数据上限是:
233333
2020/09/07
5K1
五十元内的轻量服务器:玩客云折腾速通指南(一)
无论你是想要一台低成本的服务器,还是对类似的嵌入式设备感兴趣,接下来这几篇文章都会告诉你如何让玩客云更稳定、更易维护,以及躲开折腾的时候会遇到麻烦和故障。
soulteary
2025/01/08
2.3K0
五十元内的轻量服务器:玩客云折腾速通指南(一)
一文入门Android逆向
本文节主要介绍一下Android逆向常用的环境、工具、动静态分析思路,笔者通过学习肉丝大佬分享的一些内容,加上自己一些经验总结而来。
FB客服
2020/09/14
3.5K0
一文入门Android逆向
Android Automotive Framework调试技巧
三次握手只是一个数据传输的过程,但是,我们传输前需要一些准备工作,比如将创建一个套接字,收集一些计算机的资源,将一些资源绑定套接字里面,以及接受和发送数据的函数等等,这些功能接口在一起构成了socket的编程
wizzie
2022/12/22
5.9K0
Android Automotive Framework调试技巧
Android 源码目录结构详解
这是Android2.1的源代码的目录结构,可以帮助我们研究Android的源代码。Android源代码的下载请参考官网
飞雪无情
2018/08/28
2.7K0
Tina_Linux_OTA_开发指南
OTA 是Over The Air 的简称,顾名思义就是通过无线网络从服务器上下载更新文件对本地系统或文件进行升级,便于客户为其用户及时更新系统和应用以提供更
韦东山
2023/02/25
4.9K0
安卓root权限管理_root权限在哪里设置
Android系统是运行在Linux内核上的,Android与Linux分别有自己的一套严格的安全及权限机制, Android系统权限相关的内容,
全栈程序员站长
2022/11/17
15.1K0
Tina-SDK开发
Tina-SDKV2.0源码网盘链接:https://pan.baidu.com/s/13uKlqDXImmMl9cgKc41tZg?pwd=qcw7
韦东山
2024/08/24
8060
Tina-SDK开发
嵌入式AI快速入门课程-K510篇 (第三篇 环境搭建及开发板操作)
​ 使用桥接模式下,虚拟主机与真实主要在VMnet0构成的局域网内通信,同时通过真实主机中的网关与外网通信,即可实现Ubuntu与开发板进行文件传输。
韦东山
2024/08/22
8560
嵌入式AI快速入门课程-K510篇 (第三篇 环境搭建及开发板操作)
运维面试题(每日一题)
默认生产环境中,三台服务器均可满足访问外网需求;但最终目标是完成服务器01与服务器03之间的不同网段间通讯,即服务器01的10.0.0.10主机IP地址可以正常访问服务器03的10.0.1.10主机IP地址
全栈程序员站长
2022/08/10
5.4K0
运维面试题(每日一题)
Android 渗透测试学习手册 第一章 Android 安全入门
Android 是当今最流行的智能手机操作系统之一。 随着人气的增加,它存在很多安全风险,这些风险不可避免地被引入到应用程序中,使得用户本身受到威胁。 我们将在本书中以方法论和循序渐进的方式来讨论 Android 应用程序安全性和渗透测试的各个方面。
ApacheCN_飞龙
2022/12/01
1K0
Kubernetes Goat:Kubernetes 漏洞靶场
欢迎使用构建代码服务。 该服务是使用具有 CI/CD 管道和现代工具集(如 Git、Docker、AWS 等)的容器构建的。
用户1423082
2024/12/31
3830
Kubernetes Goat:Kubernetes 漏洞靶场
htc u11第三方rom_htc手机windows系统
小弟写得差 请勿拍砖,如果有意见请直接回复本贴!谢谢! 技术有限,部分可能不详细或者错误的请各位指出,大家交流!
全栈程序员站长
2022/11/04
1.5K0
大数据开发工程师基本功修炼之史上最全Linux学习笔记(建议收藏)
Linux是大数据中的基础,无论是运维或开发,都免不了要学,而且学的越扎实越好,下面为大家带来Linux学习笔记
Maynor
2021/06/29
1.7K0
推荐阅读
相关推荐
折腾随身wifi过程中的亿点小记(上):备份刷机
更多 >
交个朋友
加入腾讯云官网粉丝站
蹲全网底价单品 享第一手活动信息
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档