主頁 >  其他 > skynet原始碼分析之sproto決議和構建 ,讓你從繁瑣中解脫

skynet原始碼分析之sproto決議和構建 ,讓你從繁瑣中解脫

2020-12-31 13:02:07 其他

skynet提供一套與客戶端通訊的協議sproto,設計簡單,有利于lua使用,參考官方wiki https://github.com/cloudwu/skynet/wiki/Sproto,本篇介紹組裝".sproto"檔案以及sproto構建流程,之后,會另寫一篇介紹sproto的使用方法,

1. 組裝.sproto檔案流程

以下面簡單的test.sproto檔案為例介紹.sproto檔案組裝流程:

-- test.sproto
.Person {
    name 0 : string
    id 1 : integer
    email 2 : string

    .PhoneNumber {
        number 0 : string
        type 1 : integer
    }

    phone 3 : *PhoneNumber
}

.AddresBook {
    person 0 : *Person
}

proto1 1001 {
    request {
        p 0 : integer
    }
    response {
        ret 0 : *Person
    }
}

通過sparser.parse api組裝.sproto檔案,引數text即test.sproto檔案的內容:

 -- lualib/sprotoparser.lua
 function sparser.parse(text, name)
     local r = parser(text, name or "=text")
     dump(r)
     local data = encodeall(r)
     sparser.dump(data)
     return data
 end

第3-4行,通過lpeg庫將.sproto檔案分析轉化成一個lua表,部分結果如下,包含protocol和type兩大類,protocol里包含所有的協議,每個協議有request,response,tag三個key;type里包含所有的型別,每個型別有1個或多個域(field),每個field里包含name,tag,typename等資訊,

  "protocol" = {
           "proto1" = {
               "request"  = "proto1.request"
               "response" = "proto1.response"
               "tag"      = 1001
           }
       }
  "type" = {
           "AddresBook" = {
              1 = {
                  "array"    = true
                  "name"     = "person"
                  "tag"      = 0
                  "typename" = "Person"
              }
          }
          "Person" = {
              1 = {
                  "name"     = "name"
                  "tag"      = 0
                  "typename" = "string"
              }
 ...

第5-6行,把lua表按特定格式組裝成二進制資料后,結果如下(每一行16個位元組):

  02 00 00 00 00 00 65 01 - 00 00 32 00 00 00 02 00 
  00 00 00 00 0A 00 00 00 - 41 64 64 72 65 73 42 6F 
  6F 6B 1A 00 00 00 16 00 - 00 00 05 00 00 00 01 00 
  04 00 02 00 04 00 06 00 - 00 00 70 65 72 73 6F 6E 
  6E 00 00 00 02 00 00 00 - 00 00 06 00 00 00 50 65 
  72 73 6F 6E 5A 00 00 00 - 12 00 00 00 04 00 00 00 
  06 00 01 00 02 00 04 00 - 00 00 6E 61 6D 65 10 00 
  00 00 04 00 00 00 02 00 - 01 00 04 00 02 00 00 00 
  69 64 13 00 00 00 04 00 - 00 00 06 00 01 00 06 00 
  05 00 00 00 65 6D 61 69 - 6C 15 00 00 00 05 00 00 
  00 01 00 06 00 08 00 04 - 00 05 00 00 00 70 68 6F 
  6E 65 4E 00 00 00 02 00 - 00 00 00 00 12 00 00 00 
  50 65 72 73 6F 6E 2E 50 - 68 6F 6E 65 4E 75 6D 62 
  65 72 2E 00 00 00 14 00 - 00 00 04 00 00 00 06 00 
  01 00 02 00 06 00 00 00 - 6E 75 6D 62 65 72 12 00 
  00 00 04 00 00 00 02 00 - 01 00 04 00 04 00 00 00 
  74 79 70 65 2F 00 00 00 - 02 00 00 00 00 00 0E 00 
  00 00 70 72 6F 74 6F 31 - 2E 72 65 71 75 65 73 74 
  13 00 00 00 0F 00 00 00 - 04 00 00 00 02 00 01 00 
  02 00 01 00 00 00 70 34 - 00 00 00 02 00 00 00 00 
  00 0F 00 00 00 70 72 6F - 74 6F 31 2E 72 65 73 70 
  6F 6E 73 65 17 00 00 00 - 13 00 00 00 05 00 00 00 
  01 00 04 00 02 00 04 00 - 03 00 00 00 72 65 74 18 
  00 00 00 14 00 00 00 04 - 00 00 00 D4 07 08 00 0A 
  00 06 00 00 00 70 72 6F - 74 6F 31 

通過這個結果(下面稱為result)反推sproto組裝流程:

第2-4行,按“<s4”格式打包字串,即字串長度占4個位元組,按小端格式打包在頭部,再加上字串內容,

第14-22行,result前6個位元組分別是"\2\0\0\0\0\0",接下來分別是type的組裝結果(tt)和protocol的組裝結果(tp),result7-10個位元組是65 01 00 00,為type組裝后的長度357(6*2^4+5+1*2^16), result從368個位元組開始是protocol的組裝結果,368-371個位元組是18 00 00 00,表示protocol的組裝結果有24個位元組(1*2^4+8),即最后24個位元組,

  -- lualib/sprotoparser.lua
  function packbytes(str)
      return string.pack("<s4",str)
  end
  
   local function encodeall(r)
       return packgroup(r.type, r.protocol)
   end
   
  local function packgroup(t,p)
      ...
      tt = packbytes(table.concat(tt))
      tp = packbytes(table.concat(tp))
      result = {
          "\2\0", -- 2fields
          "\0\0", -- type array   (id = 0, ref = 0)
          "\0\0", -- protocol array (id = 1, ref =1)
  
          tt,
          tp,
      }
      return table.concat(result)
  end

type組裝結果共有357個位元組(11-367):按字典升序遍歷所有type,依次呼叫packtype進行組裝,

第一個type是“AddresBook”:result11-14個位元組是32 00 00 00,表示“AddresBook”組裝結果有50個位元組(3*2^4+2)(第21行),因為有1個field,result15-20個位元組是02 00 00 00 00 00(第13-15行),緊接著是第16行packbytes("AddresBook"),長度是10,結果是 0A 00 00 00 41(A) 64(d) 64(d) 72(r) 65(e) 73(s) 42(B) 6F(o) 6F(o) 6B(k),即result的21-34個位元組,接下來第35-38的四個位元組1A 00 00 00,是"AddresBook"的所有field組裝后長度26(1*2^4+10),

  -- lualib/sprotoparser.lua
   local function packtype(name, t, alltypes) -- 組裝每一個type
       ...
       local data
       if #fields == 0 then
           data = {
               "\1\0", -- 1 fields
               "\0\0", -- name (id = 0, ref = 0)
               packbytes(name),
          }
      else
          data = {
              "\2\0", -- 2 fields
              "\0\0", -- name (tag = 0, ref = 0)
              "\0\0", -- field[]      (tag = 1, ref = 1)
              packbytes(name),
              packbytes(table.concat(fields)),
          }
      end
  
      return packbytes(table.concat(data))
  end 

field組裝流程,result第39-42的4個位元組16 00 00 00,是第一個field的組裝結果長度22(1*2^4+6),即result的43-64個位元組,由AddresBook的資料可知,組裝流程是:

第8行, 05 00

第13行,00 00

第23行,01 00

第24行,04 00, f.type=1

第25行,02 00, f.tag=0

第28行,04 00

第33行,06 00 00 00 70(p) 65(e) 72(r) 73(s) 6F(o) 6E(n),name="person",正好對應result的43-64個位元組,

"AddresBook" = {
     1 = {
         "array"    = true
         "name"     = "person"
         "tag"      = 0
         "typename" = "Person"
     }
 }

 -- lualib/sprotoparser.lua
  local function packfield(f) -- 組裝每一個field
      local strtbl = {}
      if f.array then
          if f.key then
              table.insert(strtbl, "\6\0")  -- 6 fields
          else
              table.insert(strtbl, "\5\0")  -- 5 fields
          end
     else
         table.insert(strtbl, "\4\0")    -- 4 fields
     end
     table.insert(strtbl, "\0\0")    -- name (tag = 0, ref an object)
     if f.buildin then
         table.insert(strtbl, packvalue(f.buildin))      -- buildin (tag = 1)
         if f.extra then
             table.insert(strtbl, packvalue(f.extra))        -- f.buildin can be integer 
   or string
         else
             table.insert(strtbl, "\1\0")    -- skip (tag = 2)
         end
         table.insert(strtbl, packvalue(f.tag))          -- tag (tag = 3)
     else
         table.insert(strtbl, "\1\0")    -- skip (tag = 1)
         table.insert(strtbl, packvalue(f.type))         -- type (tag = 2)
         table.insert(strtbl, packvalue(f.tag))          -- tag (tag = 3)
     end
     if f.array then
         table.insert(strtbl, packvalue(1))      -- array = true (tag = 4)
     end
     if f.key then
         table.insert(strtbl, packvalue(f.key)) -- key tag (tag = 5)
     end
     table.insert(strtbl, packbytes(f.name)) -- external object (name)
     return packbytes(table.concat(strtbl))
 end

接下來,依次組裝其他type,組裝完type,然后呼叫packproto組裝每一個proto,result372-375四個位元組14 00 00 00,表示"proto1"組裝后的長度20(1*2^4+4),

"proto1" = {
 "request" = "proto1.request"
 "response" = "proto1.response"
 "tag" = 1001
}

組裝流程如下:

第10-12行, 04 00 00 00 D4 07

第18行,08 00 (alltypes[p.request].id=3)

第24行,0A 00 (alltypes[p.response].id=4)

第35行,name="proto1",長度是6,打包后是 06 00 00 00 70(p) 72(r) 6F(o) 74(t) 6F(0) 31(1),正好對應result的最后20個位元組,

   -- lualib/sprotoparser.lua
  local function packproto(name, p, alltypes) -- 組裝每一個proto
      if p.request then
          local request = alltypes[p.request]
          if request == nil then
              error(string.format("Protocol %s request type %s not found", name, p.request))
          end
          request = request.id
      end
      local tmp = {
         "\4\0", -- 4 fields
         "\0\0", -- name (id=0, ref=0)
         packvalue(p.tag),       -- tag (tag=1)
     }
     if p.request == nil and p.response == nil and p.confirm == nil then
         tmp[1] = "\2\0" -- only two fields
     else
         if p.request then
             table.insert(tmp, packvalue(alltypes[p.request].id)) -- request typename (tag=2)
         else
             table.insert(tmp, "\1\0")-- skip this field (request)

         end
         if p.response then
             table.insert(tmp, packvalue(alltypes[p.response].id)) -- request typename (tag=3)
         elseif p.confirm then
             tmp[1] = "\5\0" -- add confirm field
             table.insert(tmp, "\1\0")
             -- skip this field (response)
             table.insert(tmp, packvalue(1)) -- confirm = true
         else
             tmp[1] = "\3\0" -- only three fields
         end
     end
 
     table.insert(tmp, packbytes(name))
 
     return packbytes(table.concat(tmp))
 end

小結:組裝.sproto檔案流程如下:

(1). 用lpeg庫決議.sproto檔案內容,把資訊保存在一個lua表里

(2). 依次組裝所有types,對每一個type先組裝名稱,再組裝它的fields

(3). 依次組裝所有protos

最后組裝出的二進制塊是由N個type和N個proto組成,每個type又包含name和N個field,每個field包含name、buildin、type、tag、array等資訊;每個proto包含name、tag、request、response等資訊,不論是field,type還是proto,都會加一些位元組前綴,用來表示接下來位元組的資訊,格式如下:

2. sproto構建流程

當把.sproto檔案組裝成二進制塊后,sproto構建就是決議這個二進制塊,了解了組裝程序后,決議程序就是把組裝程序倒過來,最后把決議結果保存在c結構里,通過lua層newproto,最侄訓呼叫到create_from_bundle 這個api來構建sproto,三個引數:s構建后的sproto保存在這個結構里,stream組裝的二進制資料塊,sz長度,

第19行,struct_field api計算前綴,不同的前綴接下來的資料含義不同

第23行,count_array api計算數目,比如計算types的總數,計算protos的總數,每個type中fields的總數

第26-29行,保存types總數s->type_n

第31-34行,保存protos總數s->protocol_n

第38-43行,通過import_type api構建每一個type的資料,保存在s->type這個陣列里

第44-49行,通過import_protocol api構建每一個proto的資料,保存在s->proto這個陣列里

  // lualib/sproto/sproto.c
  struct sproto *
  sproto_create(const void * proto, size_t sz) {
      ...
      if (create_from_bundle(s, proto, sz) == NULL) {
          pool_release(&s->memory);
          return NULL;
      }
      return s;
 }
 
 static struct sproto *
 create_from_bundle(struct sproto *s, const uint8_t* stream, size_t sz) {
     ...
     int fn = struct_field(stream, sz);
     int i;
     ...
     for (i=0;i<fn;i++) {
         int value = toword(stream + i*SIZEOF_FIELD);
         int n;
         if (value != 0)
             return NULL;
         n = count_array(content);
         if (n<0)
            return NULL;
         if (i == 0) {
             typedata = content+SIZEOF_LENGTH;
             s->type_n = n;
             s->type = pool_alloc(&s->memory, n * sizeof(*s->type));
         } else {
             protocoldata = content+SIZEOF_LENGTH;
             s->protocol_n = n;
             s->proto = pool_alloc(&s->memory, n * sizeof(*s->proto));
         }
         content += todword(content) + SIZEOF_LENGTH;
     }
 
     for (i=0;i<s->type_n;i++) {
         typedata = import_type(s, &s->type[i], typedata);
         if (typedata == NULL) {
             return NULL;
         }
     }
     for (i=0;i<s->protocol_n;i++) {
         protocoldata = import_protocol(s, &s->proto[i], protocoldata);
         if (protocoldata == NULL) {
             return NULL;
         }
     }
 
     return s;
 }

sproto資料結構如下:

// lualib/sproto/sproto.c
struct sproto { // 整個sproto結構
    struct pool memory;
    int type_n; // types總數
    int protocol_n; // proto總數
    struct sproto_type * type; // N個type資訊
    struct protocol * proto; // N個proto資訊
};

struct sproto_type { // 單個type結構
    const char * name; // 名稱
    int n; // fields實際個數
    int base; //如果tag是連續的,為最小的tag,否則是-1
    int maxn; //fields實際個數+最小的tag+不連續的tag個數,比如tag依次是1,3,5,則maxn=3+1+2=6
    struct field *f; // N個field資訊
};

struct field { // 單個field結構
    int tag; //唯一的tag
    int type; // 型別,可以是內置的integer,string,boolean,也可以是自定義的type,也可以是陣列
    const char * name; // 名稱
    struct sproto_type * st; //如果是自定義的型別,st指向這個型別
    int key;
    int extra;
};

struct protocol { //單個proto結構
    const char *name; //名稱
    int tag; //唯一的tag
    int confirm;    // confirm == 1 where response nil
    struct sproto_type * p[2]; //request,response的型別
};

通過sproto_dump api,列印出構建后的sproto的資訊如下:

=== 5 types ===
AddresBook 1 0 1
    person (0) *Person
Person 4 0 4
    name (0) string
    id (1) integer
    email (2) string
    phone (3) *Person.PhoneNumber
Person.PhoneNumber 2 0 2
    number (0) string
    type (1) integer
proto1.request 1 0 1
    p (0) integer
proto1.response 1 0 1
    ret (0) *Person
=== 1 protocol ===
    proto1 (1001) request:proto1.request response:proto1.response

構建成功后,呼叫saveproto將sproto保存在全域陣列G_sproto中,供所有lua VM加載(loadproto)使用,

這就是sproto的決議和構建流程,接下來會寫一篇文章介紹sproto如何使用,


在2021年1月13/14號我會開一個四小時玩轉skynet訓練營,也就是兩個禮拜之后,現在已經開放報名,對游戲開發感興趣的諸位同好可以訂閱一下,

訓練營內容大概如下:

1. 多核并發編程
2. 訊息佇列,執行緒池
3. actor訊息調度
4. 網路模塊實作
5. 時間輪定時器實作
6. lua/c介面編程
7. skynet編程精要
8. demo演示actor編程思維

期待大家一起來打造游戲開發的技術盛宴,

憑借報名截圖可以進群973961276領取上一期skynet訓練營的錄播以及這期的預習資料哦!

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/242945.html

標籤:其他

上一篇:golang 猜數字小游戲

下一篇:華碩筆記本 換鍵盤 電池不供電 問題

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more