回到简体

This commit is contained in:
chai2010
2016-02-15 11:06:34 +08:00
parent 9e878f9944
commit 2b37b23285
177 changed files with 2354 additions and 2354 deletions

View File

@@ -1,8 +1,8 @@
## 8.2. 示例: 併發的Clock服
## 8.2. 示例: 并发的Clock服
網絡編程是併發大顯身手的一個領域,由於服務器是最典型的需要同時處理很多接的程序,這些連接一般來自遠彼此立的客端。在本小中,我們會講解go言的net包這個包提供編寫一個網絡客戶端或者服器程序的基本件,無論兩者間通信是使用TCPUDP或者Unix domain sockets。在第一章中我們已經使用的net/http包里的方法也算是net包的一部分。
网络编程是并发大显身手的一个领域,由于服务器是最典型的需要同时处理很多接的程序,这些连接一般来自远彼此立的客端。在本小中,我们会讲解go言的net包这个包提供编写一个网络客户端或者服器程序的基本件,无论两者间通信是使用TCPUDP或者Unix domain sockets。在第一章中我们已经使用的net/http包里的方法也算是net包的一部分。
的第一例子是一個順序執行的時鐘服務器,它每隔一秒鐘將當前時間寫到客端:
的第一例子是一个顺序执行的时钟服务器,它每隔一秒钟将当前时间写到客端:
<u><i>gopl.io/ch8/clock1</i></u>
```go
@@ -45,13 +45,13 @@ func handleConn(c net.Conn) {
```
Listen函數創建了一net.Listener的象,這個對象會監聽一個網絡端口上到來的連接,在這個例子里我用的是TCP的localhost:8000端口。listener象的Accept方法直接阻塞,直到一新的接被建,然後會返迴一個net.Conn對象來表示這個連接。
Listen函数创建了一net.Listener的象,这个对象会监听一个网络端口上到来的连接,在这个例子里我用的是TCP的localhost:8000端口。listener象的Accept方法直接阻塞,直到一新的接被建,然后会返回一个net.Conn对象来表示这个连接。
handleConn函數會處理一完整的客戶端連接。在一for死循中,將當前的候用time.Now()函得到,然後寫到客端。由net.Conn實現了io.Writer接口可以直接向其寫入內容。這個死循環會一直行,直到入失。最可能的原因是客端主動斷開連接。這種情況下handleConn函數會用defer調用關閉服務器側的連接,然後返迴到主函數,繼續等待下一個連接請求。
handleConn函数会处理一完整的客户端连接。在一for死循中,将当前的候用time.Now()函得到,然后写到客端。由net.Conn实现了io.Writer接口可以直接向其写入内容。这个死循环会一直行,直到入失。最可能的原因是客端主动断开连接。这种情况下handleConn函数会用defer调用关闭服务器侧的连接,然后返回到主函数,继续等待下一个连接请求。
time.Time.Format方法提供了一格式化日期和時間信息的方式。它的參數是一格式化模闆標識如何格式化時間,而這個格式化模限定Mon Jan 2 03:04:05PM 2006 UTC-0700。有8部分(週幾,月份,一月的第天,等等)。可以以任意的形式來組合前面這個模闆;出在模中的部分會作爲參考來對時間格式進行輸出。在上面的例子中我們隻用到了小、分和秒。time包里定了很多標準時間格式比如time.RFC1123。在行格式化的逆向操作time.Parse,也用到同的策略。(譯註:這是go言和其它言相比比奇葩的一地方。。你需要住格式化字符串是1月2日下午34分5秒零六年UTC-0700而不像其它言那Y-m-d H:i:s一樣,當然了里可以用1234567的方式來記憶,倒是也不麻)
time.Time.Format方法提供了一格式化日期和时间信息的方式。它的参数是一格式化模板标识如何格式化时间,而这个格式化模限定Mon Jan 2 03:04:05PM 2006 UTC-0700。有8部分(周几,月份,一月的第天,等等)。可以以任意的形式来组合前面这个模板;出在模中的部分会作为参考来对时间格式进行输出。在上面的例子中我们只用到了小、分和秒。time包里定了很多标准时间格式比如time.RFC1123。在行格式化的逆向操作time.Parse,也用到同的策略。(译注:这是go言和其它言相比比奇葩的一地方。。你需要住格式化字符串是1月2日下午34分5秒零六年UTC-0700而不像其它言那Y-m-d H:i:s一样,当然了里可以用1234567的方式来记忆,倒是也不麻)
爲了連接例子里的服器,我需要一個客戶端程序比如netcat這個工具(nc命令)這個工具可以用來執行網絡連接操作。
为了连接例子里的服器,我需要一个客户端程序比如netcat这个工具(nc命令)这个工具可以用来执行网络连接操作。
```
$ go build gopl.io/ch8/clock1
@@ -64,7 +64,7 @@ $ nc localhost 8000
^C
```
戶端將服務器發來的時間顯示了出,我用Control+C來中斷客戶端的在Unix繫統上,你看到^C這樣的響應。如果你的繫統沒有裝nc這個工具你可以用telnet來實現同樣的效果,或者也可以用我下面的這個用go寫的簡單的telnet程序用net.Dial就可以簡單地創建一TCP接:
户端将服务器发来的时间显示了出,我用Control+C来中断客户端的在Unix系统上,你看到^C这样的响应。如果你的系统没有装nc这个工具你可以用telnet来实现同样的效果,或者也可以用我下面的这个用go写的简单的telnet程序用net.Dial就可以简单地创建一TCP接:
<u><i>gopl.io/ch8/netcat1</i></u>
```go
@@ -94,7 +94,7 @@ func mustCopy(dst io.Writer, src io.Reader) {
}
```
這個程序會從連接中讀取數據,併將讀到的內容寫到標準輸出中直到遇到end of file的件或者發生錯誤。mustCopy這個函數我們在本節的幾個例子中都用到。讓我們同時運行兩個客戶端來進行一個測試,這里可以開兩個終端窗口,下面左的是其中的一個的輸出,右的是另一個的輸出:
这个程序会从连接中读取数据,并将读到的内容写到标准输出中直到遇到end of file的件或者发生错误。mustCopy这个函数我们在本节的几个例子中都用到。让我们同时运行两个客户端来进行一个测试,这里可以开两个终端窗口,下面左的是其中的一个的输出,右的是另一个的输出:
```
$ go build gopl.io/ch8/netcat1
@@ -110,9 +110,9 @@ $ ./netcat1
$ killall clock1
```
killall命令是一Unix命令行工具可以用定的程名來殺掉所有名字匹配的程。
killall命令是一Unix命令行工具可以用定的程名来杀掉所有名字匹配的程。
第二個客戶端必等待第一個客戶端完成工作,這樣服務端才能繼續向後執行;因爲我們這里的服器程序同一時間隻能處理一個客戶端連接。我們這里對服務端程序做一小改,使其支持併發在handleConn函數調用的地方增加go關鍵字,每一次handleConn的調用都入一個獨立的goroutine。
第二个客户端必等待第一个客户端完成工作,这样服务端才能继续向后执行;因为我们这里的服器程序同一时间只能处理一个客户端连接。我们这里对服务端程序做一小改,使其支持并发在handleConn函数调用的地方增加go关键字,每一次handleConn的用都入一个独立的goroutine。
<u><i>gopl.io/ch8/clock2</i></u>
```go
@@ -127,7 +127,7 @@ for {
```
在多個客戶端可以同接收到時間了:
在多个客户端可以同接收到时间了:
```
$ go build gopl.io/ch8/clock2
@@ -147,7 +147,7 @@ $ ./netcat1
$ killall clock2
```
**練習 8.1** 改clock2支持傳入參數作爲端口,然後寫一個clockwall的程序這個程序可以同時與多個clock服器通信,多服器中讀取時間,併且在一表格中一次示所有服務傳迴的結果,類似於你在某些公室里看到的時鐘牆。如果你有地理上分布式的服器可以用的話,讓這些服器跑在不同的器上面;或者在同一台器上跑多不同的例,這些實例監聽不同的端口,假自己在不同的時區。像下面這樣
**练习 8.1** 改clock2支持传入参数作为端口,然后写一个clockwall的程序这个程序可以同时与多个clock服器通信,多服器中读取时间,并且在一表格中一次示所有服务传回的结果,类似于你在某些公室里看到的时钟墙。如果你有地理上分布式的服器可以用的话,让这些服器跑在不同的器上面;或者在同一台器上跑多不同的例,这些实例监听不同的端口,假自己在不同的时区。像下面这样
```
$ TZ=US/Eastern ./clock2 -port 8010 &
@@ -156,4 +156,4 @@ $ TZ=Europe/London ./clock2 -port 8030 &
$ clockwall NewYork=localhost:8010 Tokyo=localhost:8020 London=localhost:8030
```
**練習 8.2** 實現一個併發FTP服器。服務器應該解析客戶端來的一些命令比如cd命令來切換目録ls列出目録內文件get和send來傳輸文件close來關閉連接。你可以用標準的ftp命令來作爲客戶端,或者也可以自己實現一個
**练习 8.2** 实现一个并发FTP服器。服务器应该解析客户端来的一些命令比如cd命令来切换目录ls列出目录内文件get和send来传输文件close来关闭连接。你可以用标准的ftp命令来作为客户端,或者也可以自己实现一个