2015年8月10日 星期一

[.NET]Thread.Yield()


另一個Thread切換執行的方式:Thread.Yield()

  • Yield()
    • 呼叫時會確認此CPU上是否有其他等待被呼叫的執行緒,若是,切換到其他執行去執行,若否,則會讓當前執行緒繼續執行;切換到何執行緒由作業系統自動選擇
    • 高CPU利用率
    • 關鍵:不管有沒有讓成功,CPU還是會執行你行程上的任一執行緒
  • Sleep(Time)
    • 將當前執行緒暫停一段指定時間,指定時間內當前執行緒絕對不會被執行,而空出來的CPU資源則交由作業系統去運用;在指定時間到達後,此執行緒重新進入分配佇列內等待執行
    • Thread.Sleep(0)有短暫讓出的效果,會檢查是否有等待執行的執行緒,若否,則本執行緒不會被暫停會繼續跑下去

    • 較低CPU利用率
    • 關鍵:在Sleep期間,此執行緒絕對不會被執行

[Windows Form] Property Grid 使用心得 - Part I


 Windows Form 架構中,有個視覺元件叫做Property Grid,她展現的Layout大概就是像設計工具中屬性頁的樣子,可以把物件中標定為Property的欄位顯示出來

這東西有著許多好處:


  • 可以很快速地開發出反映一個Class中的Property的基本UI(在一些不重視視覺效果的應用領域奇方便,例如…自動化設備軟體(說溜嘴了?)
  • 由於是反映Property,所以可在Property中限制參數的變動範圍,提供一種基本的、制式的使用者輸入防呆機制 
  • 搭配Type Convertor還有其他若干屬性設定後,可以以此為框架延伸出看來很有一致性的UI架構,而且只需要少量的程式碼
  • 總體來說我覺得用在不需要很Fancy但講究開發效率的領域中非常的適合(就是在說自己的工作)
  • 最基本用法:
  1. 定義一個Class 裡面有若干個Property,並宣告一個Instance出來
  2. 拉入一個Property Grid到你的Form內,將SelectedObject指向剛剛宣告的Instance
  3. 執行,Property Grid會完全把Class內的Property給反映出來
其中有趣的是,Property Grid會自動限制輸入為變數可接受的型態,宣告為Integer你就不可能輸入abc、宣告為boolean選項就只會有true/false,若宣告為某種Enum,就會以ComboBox的形式提供有限個選項,選項會以Enum項目名稱顯示。
 enum MyEnum
    {
        OPTION1,
        OPTION2,
        OPTION3,
    }

    class MyClass
    {
        public int Property1 
        {
            get
            {
                return __innerVariableInteger;
            }
            set 
            {
                // constrained range
                if (value > 10 && value < 20)
                    __innerVariableInteger = value;
            }
        }
        public string Property2
        {
            get
            {
                return __innerVariableString;
            }
            set
            {
                __innerVariableString = value;
            }
        }
        public MyEnum Property3 { get; set; }

        protected string __innerVariableString = "";
        protected int __innerVariableInteger = 15;

    }
若是型別為Enum則會自動提供ComboBox選項



如果我想限制參數1數值必須大於10小於20,只要在Property中的Set函式內寫一些拒絕輸入的機制,使用Property Grid的使用者就不可能突破此關卡,例如:
public int Property1 
        {
            get
            {
                return __innerVariableInteger;
            }
            set 
            {
                // constrained range
                if (value > 10 && value < 20)
                    __innerVariableInteger = value;
            }
        }
你永遠沒辦法Key-in這範圍以外的值。

  • 使用Attribute標籤補述Property:

若是以最陽春的作法直接反映Property,可以注意到顯示出來的變數名稱都是以程式的宣告變數名為顯示,這樣是很難被使用者接受的(又有底線、名詞又不平實誰看得懂)

又或是某些Property並不想提供給使用者編輯,更甚者不想給人家看見

此時就要以Attribute描述的方式給予Property一些敘述,常用的敘述有:

    • Browsable         // 控制屬性是否可顯示在Grid上
    • ReadOnly          // 控制屬性是否可編輯
    • DisplayName     // 控制屬性顯示出來的名稱(就是用此標籤將艱澀的變數名轉譯成友善的敘述)
    • Categrory          // 控制屬性的分類,這可以做出折疊分類的效果
    • Description        // 控制屬性的描述,就是下面灰色的Bar會帶出的描述
加工一下MyClass:
  class MyClass
    {
        [Description("The input value range is 16-19")] //offered the description which would showed on the bar below
        [Category("Catagory A")]            // offered the folded categoring method
        [DisplayName("Integer Parameter")]  // offered the customised display name
        public int Property1 
        {
            get
            {
                return __innerVariableInteger;
            }
            set 
            {
                // constrained range
                if (value > 10 && value < 20)
                    __innerVariableInteger = value;
            }
        }
        [Browsable(false)]  //wont be showed on PropertyGrid
        public string Property2
        {
            get
            {
                return __innerVariableString;
            }
            set
            {
                __innerVariableString = value;
            }
        }
        [DisplayName("想要選什麼?")] // much more human-readable?
        public MyEnum Property3 { get; set; }

        protected string __innerVariableString = "";
        protected int __innerVariableInteger = 15;

    }

  • Property1顯示名稱改變嚕,而且有了分類
  • Property2隱藏嚕
  • Property3更讓人看得懂意義

咦,但是選項還是以程式語言的形式呈現阿?Boolean選項是true/false,怎麼就不能叫做 "是/否",Enum選項是英文,阿公阿罵哪看得懂,而且還帶了宅味在其中,這該怎麼去除呢?接著就要應用TypeConvertor,將選項做適當的轉譯,是退散宅味的好秘方,字字句句都可以成為很口語與詳實的描述。(之後再寫…)

後記:

一切的入手是從這篇開始的,非常感謝
最近發現這篇做了更多進階的介紹,讚
屬性化程式設計概念
關於TypeConvertor的MSDN原始說明


2015年7月11日 星期六

[LINUX] 使用憑證登入SSH

為何要使用憑證登入ssh呢? 因為如此一來登入ssh的動作就是認機不認人,簡單的說,往後登入SSH不需Key-in密碼,這在某些應用上是方便的,比如說 Github Private Server,若是透過ssh做push的話就不用每次都要打密碼,也可以很方便的用Git的圖形介面做同步(Sync)動作。

我用的是CentOS , 基本上是照著官方文件操作的

參考來源: http://wiki.centos.org/HowTos/Network/SecuringSSH#head-9c5717fe7f9bb26332c9d67571200f8c1e4324bc


概念如下:

在終端機上:

產生RSA憑證
#ssh-keygen -t rsa
如果一路enter到底的話,會在你的本機~/.ssh資料夾下產生id_rsa.pub檔案,即為公鑰

接著將此公鑰傳遞到伺服器上,
#scp ~/.ssh/id_rsa.pub user@192.168.0.1:/tmp
// 將id_rsa.pub拷貝到 192.168.0.1的tmp資料夾下,以user登入


在伺服器上(假設登入為user):

在~/.ssh資料夾下新建authorized_keys
#touch ~/.ssh/authorized_keys
接著匯入方才傳到伺服器上的公鑰內容到authorized_keys檔案內
#cat /tmp/id_rsa.pub >> ~/.ssh/authorized_keys

最後設定一下SELinux(效果不明,不大清楚為何要做)
#restorecon -Rv ~/.ssh

官方文件就寫到此了,但是!!!!!本魯我卡在這裡仍是無法透過憑證登入!!!
原來還少幾個設定……(價值3小時)

在伺服器上(登入為root)
修改sshd設定
#vim /etc/ssh/sshd_config

裡頭有幾行設定預設是未開啟的,請把他們打開:
PubkeyAuthentication yes
AuthorizedKeysFile      .ssh/authorized_keys

接著重開sshd
#service sshd restart

如此一來才能透過RSA憑證登入,GOOGLE了好久最後自己發現

後記1:檢視公鑰碼(有時候弄到亂掉,可以下此指令比對終端機與伺服器上的公鑰是否一致)
#ssh-keygen -lf id_rsa.pub

後記2:CentOS 的 useradd 指令沒有 --disabled-password這個選項,只要單純的useradd user即能做到不允許密碼登入(因為密碼未設定)



2015年6月21日 星期日

[Raspberry Pi]DHT11溫濕度模組 x Google sheet

很久以前參加了台灣樹莓派的社群聚會,認識了DHT11這款溫濕度監控模組,其主要是顆溫濕度感測器,可以輸出溫度、相對濕度兩種資訊,但對應用者而言,在乎的是怎麼跟這小東西交換資訊。

在那場聚會裡,主講者sosorry先生分享了如何實做底層Linux Driver去實現One-wire protocol去跟DHT11溝通取得資料,實做Linux Driver是件精彩的事,但需要花點功夫理解,小弟不才一直沒有動手操作了一遍,一直到最近,在國外網站Adafruit發現已有非常簡單的應用方法,甚至在文末追加了存取google sheet的方法,使得你量測到的資料可以追加在google sheet,實現了隨時隨地透過google監控家中溫/濕度,甚至是簡單的紀錄與分析,十分有趣!

原文出處:https://learn.adafruit.com/downloads/pdf/dht-humidity-sensing-on-raspberry-pi-with-gdocs-logging.pdf
在這邊分享(翻譯)出來:

1.硬體準備:

因為原文是用Adafruit的轉接板作為範例,這裡忽略掉原文的說明,可以參考這裡的圖示連接
基本上只需連接三隻腳,3.3V , GND , 以及訊號線。


NOTE: 我是去光華商場買了長得像這樣的DHT11模組,他是將原本的DHT11焊在PCB板上,並加上了PULL-UP電阻,大概幾十塊錢。

其中S腳是訊號線,-是地,中間那根則是3.3V電源
因為已經加上了PULL-UP電阻,所以訊號線的部份不需要額外掛電阻,這點跟上面範例稍微不同,需要稍加注意。

2. 軟體部份:

下載Adafruit分享的git package,裡面有範例程式,以及Adafruit撰寫的DHT11驅動
#git clone https://github.com/adafruit/Adafruit_Python_DHT.git

準備好Python環境
#sudo apt-get update
#sudo apt-get install build-essential python-dev python-openssl

安裝Adafruit 驅動套件
#cd Adafruit_Python_DHT       //去剛剛git clone下載好的位置
#sudo python setup.py install    //安裝套件

準備到這裡就已經完成,接著就是執行Adafruit已準備好的測試程式來看看
#cd examples     //前往範例資料夾
#sudo ./AdafruitDHT.py 11 4    //執行測試程式

由於存取底層GPIO需要ROOT權限,所以記得要打sudo
這程式需要兩個引數,第一個引數是Sensor形式,第二個引數是訊號線對應的GPIO號碼

Sensor共有2302(AM2302) , 11(DHT11) , 22(DHT22)三個選項

如果電路系統沒有問題的話,應該會印出溫溼度資訊,到此時就打完收工啦! 有夠簡單

3. 將量測資訊寫到Google sheet內

接著來嘗試把溫溼度資訊以試算表的形式逐行記錄下來,透過Google sheet甚至可以在異地監測呢

首先在你的Google Drive裡裡開一個新的Google試算表,將這個試算表取個好名字,例如:"DHT11好好看看我家到底有多熱" (中文在後面可能會卡關,還是取個英文的就好)

原文建議你留下第一列打上標頭,將其他列刪除掉,不然程式會從第1000行寫起,這會有點瞎

接著遵照這裡的指示開啟你的OAuth2權限

如果上述步驟有確實做完的話,會得到一個.json檔案
將這個檔案以筆記本 或是 vim 打開的話,會有一行長得像這樣:
"client_email": "149345334675-md0qff5f0kib41meu20f7d1habos3qcu@developer.gserviceaccount.com",

就是一個Email,這個Email位置就是你要分享為共同編輯的對象,程式會以共同編輯者的身份對表格寫資料。
打開你剛剛建立的Google試算表,右上角有個分享,填入這個email,記得權限要開成可以編輯。

接著回頭回來處理板子上的運作環境,此時還需要安裝額外的套件:
#sudo apt-get install python-pip
#sudo pip install gspread oauth2client

安裝完畢後,請將剛剛的.json檔,拷貝到 Adafruit_Python_DHT/examples下
然後對Adafruit_Python_DHT/examples/google_spreadsheet.py 稍做編輯,
需要額外編輯處有五處:

#DHT_TYPE = Adafruit_DHT.DHT11  // 將你的Sensor形式設定好
#DHT_PIN = 4 //將你訊號線連接的GPIO腳位設定好
#GDOCS_OAUTH_JSON = 'xxxxx.json'     //將剛剛拷貝到examples下的的.json檔案名稱設定好
#GDOCS_SPREADSHEET_NAME = 'DHT11好好看看我家到底有多熱'    //將你要寫入的google表格名稱設定好
#FREQUENCY_SECONDS = 300  //設定多少秒量測一次並寫入google表格

設定動作就到這邊,沒了!

接著就是執行google_spreadsheet.py開始量測溫/濕度並寫入表格啦!
#sudo ./google_spreadsheet.py

喔耶


後記:
開始持續記載溫濕度以後就嘗試了各種實驗如何讓房間更舒服點……

[2015/07/02] 登出ssh後繼續執行(Nohup指令)
若要在登出ssh後繼續執行程式,下以下指令:
#nohup sudo ./google_spreadsheet.py &






2015年6月14日 星期日

[Raspberry Pi]連結無線網路…連了這麼久阿

好一陣子沒玩Raspberry PI了,弄個無線網路就弄老半天…記起來!

連結到已知AP,使用wpa_supplicant,步驟如下

1. 建立wpa資訊
#wap_passphrase "your_essid" "your_password" > /etc/wpa_supplicant/wps_supplicant.conf
此時會在 /etc/wpa_supplicant/wps_supplicant.conf 檔案裡建立一個block :
 network = {
      ssid = "your_essid"
      psk = "your_password"
}

NOTE: 此檔案可有多個 network = {}  block,即為AP清單

2. 使用wpa_supplicant連結AP,此時呼叫下列指令開啟deamon
#wpa_supplicant -B  -i wlan0 -c /etc/wpa_supplicant/wps_supplicant.conf

NOTE1: 若deamon已開啟,則需要kill -9 先把deamon幹掉再重開,另尋正當方法中…
NOTE2: 另外方式就是重開機重跑wpa_supplicant

3. 確認AP是否已連結,使用iwconfig
#iwconfig wlan0
確認印出的資訊裡是否有ESSID:"your_essid",有了就是連上惹。

3. 最後,向AP要求動態IP
#dhclient wlan0

4. 用ifconfig確認wlan0是否已經獲得IP
看看inet addr 是否有值嚕

PS1: 若wpa_supplicant已經在作用中,使用iwconfig是無效的(不要浪費時間在這裡惹)

PS2: 開機後就使用wpa_supplicant管理無線網路:

設定/etc/network/interfaces,將wlan0的組態改為如下:
allow-hotplug wlan0
iface wlan0 inet manual
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf

如此一來開機後就會以wpa_supplicant.conf的內容找尋是否有可用的AP,然後自動連接

2014年12月7日 星期日

[Raspberry-Pi] 相機模組 x Live555MediaServer




想找到可以遠端觀看Pi-Camera Live-Stream的方法,而且要有一定的即時性,只是嘗試過幾招都不是很理想:


  • Motion 

偵測到背景改變後才開始錄影,就監視攝影機來說是省去錄影空間的好解法,但也因此CPU運算個沒停,即時影像輸出是很不流暢的。

參考1:http://www.instructables.com/id/Raspberry-Pi-as-low-cost-HD-surveillance-camera/?ALLSTEPS

參考2:http://www.instructables.com/id/Raspberry-Pi-Completely-Wireless-IP-Camera-Solar/


  • MJPG-Streamer(live streamer only)
只做影像的live-streaming,跑起來也比motion順暢多,但採用的是HTTP Live Stream協定,強調資料傳送的準確性,而非時間性,實際運作也稱不上流暢

參考1:http://blog.miguelgrinberg.com/post/stream-video-from-the-raspberry-pi-camera-to-web-browsers-even-on-ios-and-android
參考2:https://dotblogs.com.tw/bowwowxx/2015/06/08/151511
參考3:解決/dev/video0 does not support streaming i/o
參考4:照此官方步驟安裝uv4l(驅動Raspberry原廠相機至/dev/video0)
20150526備註:
消掉UVCIOC_CTRL_ADD - Error: Inappropriate ioctl for device的作法
$mjpg_streamer -i "input_uvc.so -n" -o "output_http.so -w ./www" //input_uvc.so引數加上-n

最後因緣際會瞭解了RTSP(Real Time Streaming Protocol),是種強調即時傳送串流的協定,看了維基百科的介紹,想像起來可能是偏向時間性的傳送協定,所以目標就暫時聚焦在找到實現RTSP的服務啦!

很幸運的Linux上有Live555這個開源軟體,可以讓我們架起簡單的Media Server
官方參考:Live555 Media Server

簡單作法如下:




#wget http://www.live555.com/liveMedia/public/live555-latest.tar.gz   //下載Live555原始碼
#tar -zxvf live555-latest.tar.gz  //解壓縮
#cd live //至live 資料夾
#./genMakefiles linux //按linux架構產生Make檔案
註1:live資料夾下有許多開頭為config.xxxx的檔案,即為對應的genMakefiles組態檔案。
註2:以"linux"架構編譯的執行檔是可以在Pi上運作的,其他架構的還沒試過。

#make //編譯Live555
#make install //佈署編譯後的Live555
註:在Pi上部屬後的Live555執行檔們會被複製到 /usr/local/bin下


  • Step2-啟動Live555MediaServer


#cd /usr/local/bin                // 進到Live555的佈署資料夾
#./live555MediaServer &   // 啟動live555MediaServer,會秀出簡單的說明

此時live555MediaServer就被啟動了並開始連入需求的監聽,播放來源檔案路徑是相對於live5執行檔位置開始計算,也就是說,想要被播放的檔案必須與live555MediaServer執行檔放在一起,或是在其位置下的子資料夾


  • Step3-啟動Pi-Camera

(在此之前要先設定好Pi-Camera唷,可以參考http://www.raspberrypi.org/learning/python-picamera-setup/

#touch rpi.264         // 開一空檔案準備給Pi-Camera作緩衝
註:live555以副檔名辨認播放格式,此處以h264來錄影與播放
 #raspivid -t 999999 -h 180 -w 270 -o rpi.264 //啟動Pi-Camara,並將串流存在rpi.264檔案裡

好的,做到這邊就完成RTSP Server側的簡單設定了,接著要到Client側開串流來看看。


  • Step4-使用VLC觀看線上串流(On Windows)


在VLC下的檔案->開啟網路串流
網址輸入:
rtsp://hostname:8554/rpi.264(因為Step3的串流是輸出到與live555Server同層的檔案裡)

就可以看見流暢的影像啦!
只是…怎麼Time-shifting這麼多哩…覺得是影像在Pi上緩衝太多的關係
這點解決的話就完美了!
To Be Continued....


其他參考:
網路後端的工作筆記
大隻熊的部落格
Python-Camera      // 用Python來控制嚕,進階使用

[LINUX] 快速設定網路磁碟機-SAMBA

最近猛烈的玩起了PI,有時候要從WINDOWS筆電傳檔案給PI,此時不得不倚靠SAMBA了。
這篇筆記主要參考自鳥哥(鳥哥:第十六章、檔案伺服器之二: SAMBA 伺服器)但在這裡只紀錄慣用懶人設定嚕

設定目標:分享LINUX下的帳號資料夾(home),權限管控為LINUX上的User 


  • Step1-安裝SAMBA: 


#apt-get install samba
#apt-get  install samba-common-bin // 在Pi上,這套件是用來取testparm指令的

註解:在Raspbian上安裝後,啟動smbd會有錯誤(nmbd無法啟動,大概是被其他服務卡住),必須重開機,smbd(SAMBA服務)從此過後會於init.d自動載入




  • Step2-設定SAMBA: 


#cp /etc/samba/smb.conf  /etc/samba/smb.conf.master    //複製一份原始參數檔來修改
#vim /etc/init.d/samba/smb.conf .master                          //改在複製品上

[global]下的設定都不用改!預設的登入方式會是user(以帳號登入)
[home]下改變設定:
browseable = yes               //此分享可被瀏覽
read only = no                   //開放家資料夾可寫入
create mask = 0775            //開放檔案讀寫權限
directory mask = 0775        //開放資料夾讀寫權限

註:當valid users = %s , 只能以\\server\username的方式掛載網路磁碟機 否則,可用\\server\home的方式 或是 \\server\labelname 的方式 掛載網路磁碟機 (標籤名等於分享名稱)

在上面的Comment欄位內,原作者建議使用testparm來管理smb.conf,會有檢查參數以及精簡設定的效果

#testparm -s smb.conf.master > smb.conf  //用testparm檢查參數語法是否正確,並套用在smb.conf上


  • Step3-設定SAMBA帳號


鳥哥:在 SAMBA 上面的使用者帳號,必須要是 Linux 帳號中的一個!

所以先在LINUX環境下設定要登入的SAMBA帳號密碼
#useradd username
#passwd username

接著在SAMBA帳號資料庫加入帳號
#pdbedit -a -u username // username必須要在linux帳號內存在

建立samba user , 建立時會要求輸入密碼 , 此密碼是用在WINDOWS掛載網路磁碟機用的!

註解:在遠端側瀏覽、寫入、讀取檔案,全部透過linux uid 做檔案權限控制,簡單的說,根據username在linux下的權限賦予遠端操作檔案權限


  • Step4-重啟smbd 


 #service smbd restart


  • Step5-WINDOWS側設定  


在我的電腦上右鍵->連線網路磁碟機
代號隨便填,
資料夾填\\server\username(這是因為SAMBA設定valid user = %s的關係)

帳號:剛剛加入的帳號名 username
密碼:pdbedit指令設定的密碼

備註: 在CentOS下,SAMBA服務可能會被selinux擋住,此時要去作selinux進階設定
鳥哥-SELinux 的相關議題

 大功告成~

後記1:pdbedit -L -v (列出所有使用者,忘記有哪些帳號時可以回想一下)

2014年11月27日 星期四

[.NET] Lambda 中參考變數生命週期

Lambda,請念作浪打,就是希臘字母中的λ(波長) 不知道在那一代.NET體系後就出現了這個有趣的特性

簡單的說,Lambda-Expression是一種匿名函式的描述方式,我的習慣裡,通常配合Delegate一起服用(即時性的產生函式物件) 寫法長成這樣:

static Func delegateInstance = new Func(() => 
{
            Console.WriteLine("I was prisoned in Lambda!!!");
            return 0;
});
另外一個有趣的事情是,在CLR的記憶體模型中,
ByReference物件生命週期並不是離開函式Scope就消失,
 而是不再有人參考到此物件時,這飄渺在記憶體太空的虛無之物才會被GC回收,

所以可能會出現,在Lambda生成時,Lambda去參考函式局部範圍下的某個Object, 即便離開生成函式,一直到Lambda執行時,
這個Object仍然被保持住,而Lambda得以順利執行。
會有種 物件小姐 從 生成他的函式酒店 被"帶出場"的感覺(威~):


static int createLambda() 
{
            String theInstance = "I was created in createLambda()";
            delegateInstance = new Func(() => 
            {
                Console.WriteLine(theInstance.ToString());
                return 0;
            });

            return 0;
}
static int executeLambda()
{
            delegateInstance();
            return 0;
}
static void Main(string[] args)
{         
            createLambda();
            executeLambda();    //' theInstance still kept,  so that no NullReferenceException would raise
}

最後分享一個案例,若在Foreach中想要替陣列裡的每個物件創造對應的Lambda,在Lambda執行時,能反應陣列裡各物件的狀態(一個Lambda反應一個物件) 此時放在Lambda內的應該要用哪個具名參考?


  1. Iterator?
  2. 在Foreach外宣告一個參考? 
  3. 在Foreach內宣告參考?

       static void Main(string[] args)
        {         
          
            List theList = new List();
            Random rnd = new Random();

            Console.WriteLine("Peek answers");
            for (int i = 0; i < 10; i++)
            {
                myClass instance = new myClass();
                instance.myString = rnd.Next().ToString();
                theList.Add(instance);
                Console.WriteLine(instance.ToString());
            }
            Console.WriteLine("Peek over");


            delegateInstance = null;
            //myClass tempReference ;  //  option 2
            foreach (myClass item in theList)
            {
                //myClass tempReference = item;                       // option 3
                //tempReference = item;
                delegateInstance += new Func(() =>
                {
                    //Console.WriteLine(tempReference.ToString());
                    Console.WriteLine(item.ToString());                // option 1

                    return 0;
                });
            }

            Console.WriteLine("Lambda run");
            delegateInstance();                     // the invocation list
            Console.WriteLine("Lambda finish");

        }

答案是1、3都可(兩者效果等價),Foreach下的Reference在Iterator進到下一格時,會全部Refresh 所以各個Lambda內參考到的物件彼此是不相同的(連結到不同指標),即便程式碼中他們都是同名的變數。


 相反地,選項2用的Reference在Foreach外宣告,相當於只用一個指標去連結不同的物件 但Lambda們都是以同一個指標去參考物件,所以印出來的東西都是一樣的。

2014年11月15日 星期六

[.NET] TCP使用筆記1--物件序列化/反序列化傳送接收

將物件序列化後傳送串流 ------> 收到串流後反序列化還原物件

Import System.Runtime.Serialization.Formatters.Binary
<Serializable()>
Public Class MySerializableClass   ' Define a Class which is able to be serialized '
    Property s As String = "abcdedfg"
    Property i As Integer = 50
    Property f As Double = 3.14159256
End Class

Dim clientSend As TcpClient = New TcpClient()        'used to send stream'
Dim clientReceive As TcpClient = new TcpClient()     'used to receive stream'

Sub serializeAndSend()
   Dim bf As BinaryFormatter = New BinaryFormatter()             
   bf.Serialize(clientSend.GetStream(), New MySerializableClass())   ' Serialize object and write into net-stream '
End Sub

Function receiveAndDeserialize() As Object
   Dim bf As BinaryFormatter = New BinaryFormatter()             
   return bf.Deserialize(clientReceived.GetStream())   ' stream received and deserialize to object'
End Function

其中BinaryFormatter可用在任何串流的序列化/反序列化(檔案串流、網路串流、記憶體串流…等等) ,
可延伸此法將物件資料存入/讀出磁碟,比方機台參數設定...等等,或是做大型物件的記憶體內複製(應用記憶體串流)。

2014年11月8日 星期六

Windows網路橋接器 + Raspberri PI

筆記一下消耗我兩晚青春的Windows網路橋接器…

這次要搞定的拓樸結構長這樣:




目標是讓Raspberry PI 還有 筆電 都可以透過Wifi Router上網

首先先建立Windows網路橋接器,將筆電的Wifi介面與Ethernet介面橋接起來:


















橋接後照著原先的習慣,讓筆電連接Wifi,
並設定"自動取得IP",讓網路橋接器以DHCP協定向Router要到IP:






















Rasperry PI 這邊就要特別注意了,

必須手動設定 靜態IP、子網路遮罩、Gateway,
若以dhclient是要不到DHCPPACK的,因為透過網路橋接器發出的DHCPDISCOVER是以網路橋接器MAC為訊框,導致Router也一直將封包回錯對象,以至於Raspberry PI無法取得動態IP。
(檢查方法:查Router的 /var/log/syslog , 裡面的DHCP相關Log可以發現這個線索)

手動設定的方法如下:

#sudo vi /etc/network/interfaces           //編輯網路設定檔案

加入此行:
auto eth0
iface eth0 inet static
address 192.168.0.51 #注意要跟Router同網域,而且此IP未被其它人佔用
netmask 255.255.255.0network 192.168.0.254 #注意要跟Router同網域
broadcast 192.168.0.255 #注意要跟Router同網域
gateway 192.168.0.1     #可照著上圖的IPv4預設閘道設定

如此一來就沒問題了