鍍金池/ 教程/ GO/ 通訊
版權(quán)
簡介
Bibliography
接口
通訊
函數(shù)
進(jìn)階
索引
并發(fā)

通訊

在這章中將介紹 Go 中與外部通訊的通訊模塊。將會了解文件、目錄、網(wǎng)絡(luò)通訊和運(yùn)行其他程序。Go 的 I/O 核心是接口 io.Reader 和 io.Writer。

在 Go 中,從文件讀?。ɑ?qū)懭耄┦欠浅H菀椎?。程序只需要使?os 包就可以從文件 /etc/passwd 中讀取數(shù)據(jù)。

http://wiki.jikexueyuan.com/project/learn-go-language/images/178.png" alt="pic" />

接下來展示了如何做到這點:

  1. 打開文件,os.Open 返回一個實現(xiàn)了 io.Reader 和 io.Writer 的 *os.File;
  2. 確保關(guān)閉了 f;
  3. 一次讀取 1024 字節(jié);
  4. 到達(dá)文件末尾;
  5. 將內(nèi)容寫入 os.Stdout

如果想要使用緩沖 IO,則有 bufio 包:

http://wiki.jikexueyuan.com/project/learn-go-language/images/179.png" alt="pic" />

0 .打開文件;

  1. 轉(zhuǎn)換 f 為有緩沖的 Reader。NewReader 需要一個 io.Reader,因此或許你認(rèn)為這會出錯。但其實不會。任何有 Read() 函數(shù)就實現(xiàn)了這個接口。同時,從列表 7.1可以看到,*os.File 已經(jīng)這樣做了;

  2. 從 Reader 讀取,而向 Writer 寫入,然后向屏幕輸出文件。

io.Reader

在前面已經(jīng)提到 io.Reader 接口對于 Go 語言來說非常重要。許多(如果不是全部的話)函數(shù)需要通過 io.Reader 讀取一些數(shù)據(jù)作為輸入。為了滿足這個接口,只需要實現(xiàn)一個方法:Read(p []byte) (n int, err error)。寫入則是(你可能已經(jīng)猜到了)實現(xiàn)了 Write 方法的 io.Writer。如果你讓自己的程序或者包中的類型實現(xiàn)了 io.Reader 或者 io.Writer 接口,那么整個 Go 標(biāo)準(zhǔn)庫都可以使用這個類型!

一些例子

前面的程序?qū)⒄麄€文件讀出,但是通常情況下會希望一行一行的讀取。下面的片段展示了如何實現(xiàn):

http://wiki.jikexueyuan.com/project/learn-go-language/images/180.png" alt="pic" />

更加通用(但是也更加復(fù)雜)的方法是 ReadLine,參閱包 bufio 的文檔了解更多內(nèi)容。

在 shell 腳本中通常遇到的場景是需要檢查某個目錄是否存在,如果不存在,就創(chuàng)建一個。

http://wiki.jikexueyuan.com/project/learn-go-language/images/181.png" alt="pic" />

這兩個例子的相似之處展示了 Go 擁有的“腳本” 化特性,例如,用 Go 編寫程序感覺上類似使用動態(tài)語言(Python、Ruby、Perl 或者 PHP)。

命令行參數(shù)

來自命令行的參數(shù)在程序中通過字符串 slice os.Args 獲取,導(dǎo)入包 os 即可。flag 包有著精巧的接口,同樣提供了解析標(biāo)識的方法。這個例子是一個 DNS 查詢工具:

http://wiki.jikexueyuan.com/project/learn-go-language/images/182.png" alt="pic" />

0 .定義 bool 標(biāo)識,-dnssec。變量必須是指針,否則 package 無法設(shè)置其值;

  1. 類似的,port 選項;
  2. 簡單的重定義Usage 函數(shù),有點羅嗦;
  3. 指定的每個標(biāo)識,PrintDefaults 將輸出幫助信息;
  4. 解析標(biāo)識,并填充變量。

當(dāng)參數(shù)被解析之后,就可以使用它們:

http://wiki.jikexueyuan.com/project/learn-go-language/images/183.png" alt="pic" />

執(zhí)行命令

os/exec 包有函數(shù)可以執(zhí)行外部命令,這也是在 Go 中主要的執(zhí)行命令的方法。通過定義一個有著數(shù)個方法的*exec.Cmd 結(jié)構(gòu)來使用。

執(zhí)行 ls -l:

import "os/exec"
cmd := exec.Command("/bin/ls", "-l")
err := cmd.Run()

上面的例子運(yùn)行了 “l(fā)s -l”,但是沒有對其返回的數(shù)據(jù)進(jìn)行任何處理,通過如下方法從命令行的標(biāo)準(zhǔn)輸出中獲得信息:

http://wiki.jikexueyuan.com/project/learn-go-language/images/184.png" alt="pic" />

網(wǎng)絡(luò)

所有網(wǎng)絡(luò)相關(guān)的類型和函數(shù)可以在 net 包中找到。這其中最重要的函數(shù)是 Dial。當(dāng) Dial 到遠(yuǎn)程系統(tǒng),這個函數(shù)返回 Conn 接口類型,可以用于發(fā)送或接收信息。函數(shù) Dial 簡潔的抽象了網(wǎng)絡(luò)層和傳輸層。因此 IPv4 或者 IPv6,TCP 或者 UDP 可以共用一個接口。

通過 TCP 連接到遠(yuǎn)程系統(tǒng)(端口 80),然后是 UDP,最后是 TCP 通過 IPv6,大致是這樣:

http://wiki.jikexueyuan.com/project/learn-go-language/images/185.png" alt="pic" />

如果沒有錯誤(由e 返回),就可以使用conn 從套接字中讀寫。在包net 中的原始定義是:

// Read reads data from the connection.
Read(b []byte)(n int, err error)

這使得 conn 成為了 io.Reader。

// Write writes data to the connection.
Write(b []byte)(n int, err error)

這同樣使得 conn 成為了 io.Writer,事實上 conn 是 io.ReadWriter。

但是這些都是隱含的低層 c,通常總是應(yīng)該使用更高層次的包。例如 http 包。一個簡單的 http Get 作為例子:

http://wiki.jikexueyuan.com/project/learn-go-language/images/186.png" alt="pic" />

0 .需要的導(dǎo)入;

  1. 使用 http 的 Get 獲取 html;
  2. 錯誤處理;
  3. 將整個內(nèi)容讀入 b;
  4. 如果一切 OK 的話,打印內(nèi)容。

練習(xí)

Q28. (2) 進(jìn)程

  1. 編寫一個程序,列出所有正在運(yùn)行的進(jìn)程,并打印每個進(jìn)程執(zhí)行的子進(jìn)程個數(shù)。輸出應(yīng)當(dāng)類似:
Pid 0 has 2 children: [1 2]
Pid 490 has 2 children: [1199 26524]
Pid 1824 has 1 child: [7293]
  • 為了獲取進(jìn)程列表,需要得到 ps -e -opid,ppid,comm 的輸出。輸出類似:
PID PPID COMMAND
9024 9023 zsh
19560 9024 ps
  • 如果父進(jìn)程有一個子進(jìn)程, 就打印 child, 如果多于一個, 就打印 children;
  • 進(jìn)程列表要按照數(shù)字排序,這樣就以 pid 0 開始,依次展示。這里有一個 Perl 版本的程序來幫助上手(或者造成絕對的混亂)。

http://wiki.jikexueyuan.com/project/learn-go-language/images/187.png" alt="pic" />

Q29. (0) 單詞和字母統(tǒng)計

1 .編寫一個從標(biāo)準(zhǔn)輸入中讀取文本的小程序,并進(jìn)行下面的操作:

  1. 計算字符數(shù)量(包括空格);
  2. 計算單詞數(shù)量;
  3. 計算行數(shù)。

換句話說,實現(xiàn)一個 wc(1)(參閱本地的手冊頁面),然而只需要從標(biāo)準(zhǔn)輸入讀取。

Q30. (0) Uniq

  1. 編寫一個 Go 程序模仿 Unix 命令 uniq 的功能。程序應(yīng)當(dāng)像下面這樣運(yùn)行,提供一個下面這樣的列表:
'a' 'b' 'a' 'a' 'a' 'c' 'd' 'e' 'f' 'g'  

它將打印出沒有后續(xù)重復(fù)的項目:

'a' 'b' 'a' 'c' 'd' 'e' 'f'  

下面列出的 7.8 是 Perl 實現(xiàn)的算法。

http://wiki.jikexueyuan.com/project/learn-go-language/images/188.png" alt="pic" />

Q31. (2) Quine Quine 是一個打印自己的程序。

  1. 用 Go 編寫一個 Quine 程序。

Q32. (1) Echo 服務(wù)

  1. 編寫一個簡單的 echo 服務(wù)。使其監(jiān)聽于本地的 TCP 端口 8053 上。它應(yīng)當(dāng)可以讀取一行(以換行符結(jié)尾),將這行原樣返回然后關(guān)閉連接。
  2. 讓這個服務(wù)可以并發(fā),這樣每個請求都可以在獨立的 goroutine 中進(jìn)行處理。

Q33. (2) 數(shù)字游戲

  • 從列表中隨機(jī)選擇六個數(shù)字:

1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 25; 50; 75; 100

數(shù)字可以多次被選中;

  • 從 1 : : : 1000 中選擇一個隨機(jī)數(shù)i;

  • 嘗試用先前的六個數(shù)字(或者其中的幾個)配合運(yùn)算符+,
上一篇:版權(quán)下一篇:簡介