Tuesday, December 27, 2022

[Protocol] Avahi

Avahi 是一套使應用程式能夠公布或發現區域網上運行的服務和主機的系統

Avahi 啟動時,需要依賴 D-Bus

目的:找尋區域網路服務或設備

先了解知識:mDNS (Multicast DNS) 和 DNS-SD (DNS-based Service Discovery)

mDNS 就是對區網做「廣播」而廣播的內容則是我們熟悉的 DNS Query

DNS-SD -- 參考網頁中的「根據 DNS-SD 篩選出 Airplay / Chromecast 裝置」

zeroconf

Zeroconf 全稱為 Zero configuration networking,中文名則為零配置網路服務規範,是一種用於自動生成可用IP地址的網路技術,不需要額外的手動配置和專屬的配置伺服器。

精神在於希望把網路設定這件事情自動化,達到零設定(無須手動設定)的目的

主要是定義了三個層次

1. 指派位址(Address Selection)- 不需利用 dhcp server 取得 裝置地址如 IP 的相關資料

RFC 3927 , Dynamic Configuration of IPv4 Link-Local Addresses

2. 名稱解析(Name Resolution) - 不需要通過 DNS server 就轉換 domain name 和 IP 的關係

Multicast DNS

3. 服務搜尋(Service Discovery)- 利用 DNS-SD 來取得裝置服務,而不需通過 directory server

DNS-based Service Discovery, or DNS-SD.

  1. DNS-SD 的 FQDN 結構
  2. DNS-SD 會使用的 Record

Apple 的 zeroconf 協議技術實現 – Bonjour

apple 的 airplay,airprint 都是依賴了zeroconf 的基礎上,才展現出強大的功能

例子說明:
使用者擁有一臺apple tv和一臺iPhone4s,那之只要都連入到同一個無線區域網內,iphone4s就會自動找出apple tv,那麼在播放音樂或者視訊時候,使用者只要點選推送,就可以講音樂和視訊推送到apple tv上播放。

開源的 zeroconf 協議技術實現 – Avahi

Avahi 是 Zeroconf 規範的開源實現,可以分成 server 以及 client

server 的部份主要是要告訴大家你自己是誰, 提供區網有什麼服務

client 的部份主要是用來聽廣播, 取得區網上所有可使用的服務

環境

version: avahi-daemon (0.8-5ubuntu5)

johnnysu@johnnysu-VirtualBox:/etc/avahi/services$ ifconfig
enp0s3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.50.114 netmask 255.255.255.0 broadcast 192.168.50.255
inet6 fe80::49b2:8ba6:6532:9d0e prefixlen 64 scopeid 0x20<link>
ether 08:00:27:75:08:d1 txqueuelen 1000 (Ethernet)
RX packets 172828 bytes 65464536 (65.4 MB)
RX errors 21 dropped 0 overruns 0 frame 0
TX packets 17493 bytes 1902108 (1.9 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
device interrupt 19 base 0xd020

lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 9106 bytes 919852 (919.8 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 9106 bytes 919852 (919.8 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

ubuntu 安裝 avahi

avahi-utils - Avahi browsing, publishing and discovery utilities

sudo apt-get install avahi-daemon avahi-utils

查詢是否啟動

johnnysu@johnnysu-VirtualBox:~$ systemctl list-units --all | grep -E "dbus|avahi-daemon"
avahi-daemon.service loaded active running Avahi mDNS/DNS-SD Stack
dbus.service loaded active running D-Bus System Message Bus
getty-static.service loaded inactive dead getty on tty2-tty6 if dbus and logind are not available
avahi-daemon.socket loaded active running Avahi mDNS/DNS-SD Stack Activation Socket
dbus.socket loaded active running D-Bus System Message Bus Socket

查詢監聽

johnnysu@johnnysu-VirtualBox:~/airplay$ sudo netstat -tlunp | grep avahi
udp 0 0 0.0.0.0:5353 0.0.0.0:* 5357/avahi-daemon:
udp 0 0 0.0.0.0:49226 0.0.0.0:* 5357/avahi-daemon:
udp6 0 0 :::5353 :::* 5357/avahi-daemon:
udp6 0 0 :::52810 :::* 5357/avahi-daemon:

設定檔

/etc/avahi/avahi-daemon.conf

[server]
host-name=johnny
domain-name=local

如果有設定 ipv6=no 的話,

use-ipv6=no

以下就會沒有

udp6 0 0 :::5353 :::* 5357/avahi-daemon:
udp6 0 0 :::52810 :::* 5357/avahi-daemon:

重新啟動

sudo systemctl restart avahi-daemon

找另一台主機確定 mDNS server 是否通

wolfe@wolfe-VirtualBox:~/work/UxPlay-master$ ping johnny.local
PING johnny.local (192.168.50.114) 56(84) bytes of data.
64 bytes from 192.168.50.114 (192.168.50.114): icmp_seq=1 ttl=64 time=27.8 ms
64 bytes from 192.168.50.114 (192.168.50.114): icmp_seq=2 ttl=64 time=18.1 ms
64 bytes from 192.168.50.114 (192.168.50.114): icmp_seq=3 ttl=64 time=2.33 ms

register an mDNS/DNS-SD service 有 2 種方式

1. 透過 avahi-publish 方式 register an mDNS/DNS-SD service

      avahi-publish -s [options] name service-type port [TXT data ...]

       avahi-publish-service [options] name service-type port [TXT data ...]

avahi-publish -s "My service" _myservic._tcp 1234

johnnysu@johnnysu-VirtualBox:/etc/avahi/services$ avahi-browse -a -r

= enp0s3 IPv4 My service _myservic._tcp local
hostname = [johnny.local]
address = [192.168.50.114]
port = [1234]
txt = []

2. 編寫你自己的服務 (提供 DNS-SD 會使用的 Record)

預設是放在 /etc/avahi/services

johnnysu@johnnysu-VirtualBox:/etc/avahi/services$ ls
ftp.service smb.service

ftp.service

<?xml version="1.0" standalone='no'?>
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
<name replace-wildcards="yes">FTP</name>
<service>
<type>_ftp._tcp</type>
<host-name>ftp.johnny.local</host-name>
<port>21</port>
<txt-record>path=/share</txt-record>
<txt-record>u=guest</txt-record>
<txt-record>p=pass</txt-record>
</service>
</service-group>

smb.service

<?xml version="1.0" standalone='no'?>
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
<name replace-wildcards="yes">Samba</name>
<service>
<type>_smb._tcp</type>
<host-name>smb.johnny.local</host-name>
<port>445</port>
<txt-record>path=/share</txt-record>
<txt-record>u=guest</txt-record>
<txt-record>p=pass</txt-record>
</service>
</service-group>

在 /usr/share/doc/avahi-daemon/examples 裡有一些現成的範例

其它細節可以參考這裡 http://manpages.ubuntu.com/manpages/precise/man5/avahi.service.5.html

Service type 定義在 avahi/service-type-database/service-types 根據 DNS SRV (RFC 2782) Service Types

_ftp._tcp:FTP File Transfer

_airplay._tcp:AirPlay Remote Video

Finished register an mDNS/DNS-SD service,設定 host name/address mapping

avahi 預設會為 hosts 的 IP 去反查域名,所以不能多個 domain name 指向同 1 個 IP

設定 host name 對映 address (擇一)

way1

sudo vim /etc/avahi/hosts

192.168.50.114 ftp.johnny.local

way2 (一定要有 .local)

/usr/local/bin/avahi-add-names.sh

/usr/bin/avahi-publish -a -R ftp.johnny.local 192.168.50.114 > /dev/null 2>&1 &
/usr/bin/avahi-publish -a -R smb.johnny.local 192.168.50.115 > /dev/null 2>&1 &

chmod +x /usr/local/bin/avahi-add-names.sh

sed -i '/ExecStart/aExecStartPost=\/usr\/local\/bin\/avahi-add-names\.sh' /lib/systemd/system/avahi-daemon.service

sudo systemctl daemon-reload

啟動,擇一

1. sudo /etc/init.d/avahi-daemon start

2. sudo systemctl start avahi-daemon

查看狀況

johnnysu@johnnysu-VirtualBox:~/airplay/test-avahi$ sudo systemctl status avahi-daemon
● avahi-daemon.service - Avahi mDNS/DNS-SD Stack
Loaded: loaded (/lib/systemd/system/avahi-daemon.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2022-12-27 17:01:49 CST; 2s ago
TriggeredBy: ● avahi-daemon.socket
Process: 6718 ExecStartPost=/usr/local/bin/avahi-add-names.sh (code=exited, status=0/SUCCESS)
Main PID: 6716 (avahi-daemon)
Status: "avahi-daemon 0.8 starting up."
Tasks: 4 (limit: 4626)
Memory: 1.6M
CPU: 23ms
CGroup: /system.slice/avahi-daemon.service
├─6716 "avahi-daemon: running [johnnysu-VirtualBox.local]"
├─6717 "avahi-daemon: chroot helper"
├─6719 /usr/bin/avahi-publish -a -R ftp.johnny.local 192.168.50.114
└─6720 /usr/bin/avahi-publish -a -R smb.johnny.local 192.168.50.115

十二 27 17:01:49 johnnysu-VirtualBox avahi-daemon[6716]: Network interface enumeration completed.
十二 27 17:01:49 johnnysu-VirtualBox avahi-daemon[6716]: Registering new address record for fe80::49b2:8ba6:6532:9d0e on enp0s3.*.
十二 27 17:01:49 johnnysu-VirtualBox avahi-daemon[6716]: Registering new address record for 192.168.50.114 on enp0s3.IPv4.
十二 27 17:01:49 johnnysu-VirtualBox avahi-daemon[6716]: Registering new address record for ::1 on lo.*.
十二 27 17:01:49 johnnysu-VirtualBox avahi-daemon[6716]: Registering new address record for 127.0.0.1 on lo.IPv4.
十二 27 17:01:49 johnnysu-VirtualBox systemd[1]: Started Avahi mDNS/DNS-SD Stack.
十二 27 17:01:49 johnnysu-VirtualBox avahi-daemon[6716]: Server startup complete. Host name is johnnysu-VirtualBox.local. Local service cookie is 2433229662.
十二 27 17:01:50 johnnysu-VirtualBox avahi-daemon[6716]: Service "FTP" (/services/ftp.service) successfully established.
十二 27 17:01:50 johnnysu-VirtualBox avahi-add-names.sh[6720]: Established under name 'smb.johnny.local'
十二 27 17:01:50 johnnysu-VirtualBox avahi-add-names.sh[6719]: Established under name 'ftp.johnny.local'

立即測試的話,可用:nohup ./avahi-add-names.sh

以下用 client 來測試

使用 avahi-browse 測試

wolfe@wolfe-VirtualBox:~/work/UxPlay-master$ avahi-browse -r -t _ftp._tcp

+ enp0s3 IPv4 FTP FTP File Transfer local
= enp0s3 IPv4 FTP FTP File Transfer local
hostname = [ftp.johnny.local]
address = [192.168.50.114]
port = [21]
txt = ["p=pass" "u=guest" "path=/share"]

FTP File Transfer local= enp0s3 IPv4 FTP
FTP File Transfer local
hostname = [ftp.johnny.local]
address = [192.168.50.114]
port = [21]
txt = ["p=pass" "u=guest" "path=/share"]

Johnnysu@johnnysu-VirtualBox:~$ avahi-browse -r -t _smb._tcp
+ enp0s3 IPv4 JOHNNYSU-VIRTUALBOX Microsoft Windows Network local
+ lo IPv4 JOHNNYSU-VIRTUALBOX Microsoft Windows Network local
= enp0s3 IPv4 JOHNNYSU-VIRTUALBOX Microsoft Windows Network local
hostname = [johnny.local]
address = [192.168.50.114]
port = [445]
txt = []
= lo IPv4 JOHNNYSU-VIRTUALBOX Microsoft Windows Network local
hostname = [johnny.local]
address = [127.0.0.1]
port = [445]
txt = []

其它指令:

##發現所有已註冊的服務

avahi-browse -a -r

使用 dig 測試服務是否活著

成功

johnnysu@johnnysu-VirtualBox:/etc/avahi/services$ dig -p 5353 @192.168.50.114 ftp.johnny.local

; <<>> DiG 9.18.1-1ubuntu1.1-Ubuntu <<>> -p 5353 @192.168.50.114 ftp.johnny.local
; (1 server found)
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 34416
;; flags: qr aa; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;ftp.johnny.local. IN A

;; ANSWER SECTION:
ftp.johnny.local. 10 IN A 192.168.50.114

;; Query time: 0 msec
;; SERVER: 192.168.50.114#5353(192.168.50.114) (UDP)
;; WHEN: Tue Dec 27 17:24:30 CST 2022
;; MSG SIZE rcvd: 50

因為沒有 192.168.50.115 server,所以沒找到

johnnysu@johnnysu-VirtualBox:/etc/avahi/services$ dig -p 5353 @192.168.50.115 _smb._tcp.local ptr

; <<>> DiG 9.18.1-1ubuntu1.1-Ubuntu <<>> -p 5353 @192.168.50.115 _smb._tcp.local ptr
; (1 server found)
;; global options: +cmd
;; connection timed out; no servers could be reached

使用 nmap 測試

johnnysu@johnnysu-VirtualBox:~$ sudo nmap -Pn -sUC -p5353 192.168.50.114
Starting Nmap 7.80 ( https://nmap.org ) at 2022-12-28 10:03 CST
Nmap scan report for johnnysu-VirtualBox (192.168.50.114)
Host is up (0.000072s latency).

PORT STATE SERVICE
5353/udp open zeroconf
| dns-service-discovery:
| 21/tcp ftp
| Address=192.168.50.114
| 445/tcp smb
| Address=192.168.50.114 fe80::49b2:8ba6:6532:9d0e
| Device Information
|_ Address=192.168.50.114 fe80::49b2:8ba6:6532:9d0e

Monday, December 26, 2022

[Protocol] D-Bus introduction

D-Bus,數據總線,是一個低延遲,低開銷,高可用性的 IPC 機制,协议传递的是二进制数据,, 而不是其他的文本格式 (如JSON/XML), 协议是基于消息处理的, 而不是基于流


相较于传统意义上的 IPC 机制(例如PIPE/FIFO/Socket/共享内存/SysvIpc),D-Bus提供了更高层次的抽象

目前也透過 kobject 與 kernel 做整合,如此一來,D-BUS 便能輕易整合 kernel、application 與 desktop,真正解決以往「系統整合」所遇到的障礙。

http://dbus.freedesktop.org/doc/dbus-glib/index.html

1. 方法调用(Method Call):用来实现跨进程的方法(函数)调用,配合代码生成工具,可以做到让进程间的函数调用和普通的函数调用几无区别

2. 信号(Signal):发布订阅(Pub-Sub)模式的通信机制,发送进程注册并发送(广播)信号,接收进程订阅自己感兴趣的信号。

3. 属性(Property):可类比 C++ 类中成员变量的 Getter-Setter,如果进程A提供了一个属性,那么其他进程可以通过D-Bus来读取、写入该属性。

在架構上分位三層

1. Layer 1 libdbus :freedesktop 機構提供的一個免費開源的一個由C語言編寫的 low-level API 。是提供dbus功能的庫。是高階API繫結的低階API

2. Layer 2 dbus daemon :dbus實現的IPC守護進行,隨Linux啟動,通過不通程序對其的連線,實現了多程序間訊息的路由(包含核心、網路、桌面等)

3. Layer 3 Wapper libraries (high-level API): 對 low-level API libdbus 的封裝 ,例如 libdbus-qt libdbus-python github.com/godbus/dbus ,這些不同程式語言實現的 Wapper 是不同開發者應該使用的lib,其簡化了D-Bus的開發難度。最基础的是 C,有官方提供的参考代码,也有 Java、Python等,每种语言的实现被称为 D-Bus Binding。

[Protocol] WebRTC

 

WebRTC

[Protocol] AirPlay 原理

基本概念

AirPlay 是一個用來與 Apple TV溝通的協定,可用 iOS 設備或 itunes將資料交給 Apple TV進行播放,其實作使用 Multicast DNS, HTTP, RTSP, RTP or NTP 等協定,並加上些許的修改


Unofficial AirPlay Protocol Specification

Saturday, December 10, 2022

Code that Fits in Your Head

筆記:

軟體開發方法論:

Test-driven development (TDD,測試驅動開發)

Behaviour-driven development (BDD,行為驅動開發)

Domain-driven development (DDD,領域驅動開發)

Type-driven development (型別驅動開發)

Property-driven development (特性驅動開發)


封裝

描述物件和呼叫者之間有效互動的一種契約。指出有效性的一種方式是說明什麼是無效的。

Design by Contract

封裝的想法:你應該能夠與一個物件進行互動而不需要對它的實作細節有深入的了解。這目的有 2 個:

1. 它使你能夠改變實作,也就是進行重構。

2. 它允許你以抽象的方式思考一個物體

在設計時要明確指出哪些是有效的輸入,哪些是無效的輸入,以及你能對輸出提供哪些保證


Martin Fowler:如果不關注內部品質,你很快就會失去在合理時間內進行改善的能力。

內部品質差勁的狀況。起初進展很快,但隨著時間的推移,要增加新的功能變得越來越困難。即使是小型的變更,也需要程式設計師去了解大面積的程式碼,而且是很難理解的程式碼。

當他們進行改動時,會出現意想不到的損害,導致測試時間長,還有需要修復缺陷

Page 51

J.B. Rainsberger 的說法:程式碼不是一種資產,而是一種責任。

Page 98 

參數化的測試

Page 112

Postel' Law

慎重考慮先決與後置條件:對你發送出去的東西要保守,對你所接受的東西則要寬容。

輸入 null,轉換為空字串 

Page 117

試圖用1個無效的人數初始化某個物件,應該要丟出1個例外。+

Page 119

封裝的概念:

並不是禁止直接對外開放類別的欄位:類別的欄位應該被「封裝」在 getXX 和 setXXX。

主要是 1 個物件應該保證它永遠不會處於無效的狀態。這不是呼叫者的責任。物件最清楚「有效」意味者什麼,以及如何做出這種保證。

物件和呼叫者之間的互動應該遵守一個契約。這是一組先決條件和後置條件。

先決條件述述了呼叫者的責任。然後,如果呼叫程式碼履行了那些義務

後置條件就描述了物件所給予的保證。

[Refactoring]Introduction

 

1. 重構有時候,讓你可以在犯錯時,輕鬆找到 bug 的位置

2. 呆子都寫得出電腦可以了解的程式,但只有優利的程式寫得出人看得懂的程式

3. 決定程式好壞的關鍵在於它有多麼容易被修改。


重構目的:

1. 軟體更容易了解

2. 較快找出 bug

3. 協助提升程式編寫速度 (良好的模組化讓我們只要了解1小部分程式就可以)

Thursday, December 1, 2022

[Architecture] 架构师修炼之道

出色的架構本身最終不足以確保軟體品質

錯誤的架構註定導致產生更多的軟體 bugs

1. 軟體架構導論

1.1 成为软件架构师

1.2 設計思維基礎

2. 架構設計原理

2.1 制定设计策略

2.2 換位思考

2.3 挖掘關鍵架構需求

2.4 主動選擇架構

2.5 架構模式

2.6 建立模型,化繁為簡

2.7 召開架構設計研究會

2.8 展示設計策略

2.9 描述架構

2.10 架構評估

2.11 鼓勵團隊參與架構設計

3.  架構師的工具箱



n8n index

 【n8n免費本地端部署】Windows版|程式安裝x指令大補帖  【一鍵安裝 n8n】圖文教學,獲得無限額度自動化工具&限時免費升級企業版功能