- FD file descriptor 文件信息
- netFD 實現了各個系統對socket的封裝
conn
該結構實現了Conn接口
type conn struct {
fd *netFD
}
conn的方法
- Read(b []byte) (n int, err error)
-
從連接中讀取所有內容
result, err := ioutil.ReadAll(conn) //讀取所有內容 //讀取指定長度的內容 var buf [512]byte n, err := conn.Read(buf[0:]) //不斷的從連接讀取.. result := bytes.NewBuffer(nil) var buf [512]byte for { n, err := conn.Read(buf[0:]) result.Write(buf[0:n]) if err != nil { if err == io.EOF { break } return nil, err } } return result.Bytes(), nil - Write(b []byte) (n int, err error)
-
向連接中寫入數據,n是寫入數據的大小
_, err = conn.Write([]byte("GET / HTTP/1.0\r\n\r\n")) - Close() error
- 關閉連接
- LocalAddr() Addr
- 獲取發送連接的本地IP和端口
- RemoteAddr() Addr
-
獲取目標主機的ip和端口
tcpAddr, err := net.ResolveTCPAddr("tcp4", "www.baidu.com:80") conn, err := net.DialTCP("tcp", nil, tcpAddr) fmt.Println(conn.LocalAddr()) // 192.168.1.88:51164 fmt.Println(conn.RemoteAddr()) // 220.181.111.147:80 - SetDeadline(t time.Time) error
- 設置連接到期時間,就是連接超時時間
- SetReadDeadline(t time.Time) error
- 設置連接讀取到期時間
- SetWriteDeadline(t time.Time) error
- 設置連接寫入到期時間
- SetReadBuffer(bytes int) error
- 設置操作系統連接相關接收緩沖區大小
- SetWriteBuffer(bytes int) error
- 設置操作系統連接相關傳輸緩沖區大小
- File() (f *os.File, err error)
- 返回網絡文件信息
TCPConn
注意:該類型並沒有實現PacketConn接口.這是和udp的不同
type TCPConn struct {
conn
}
DialTCP
一旦客戶端已經建立TCP服務, 就可以和對方設備"通話"了. 如果成功,該調用返回一個用於通信的TCPConn。客戶端和服務器通過它交換消息。通常情況下,客戶端使用TCPConn寫入請求到服務器, 並從TCPConn的讀取響應。持續如此,直到任一(或兩者)的兩側關閉連接。客戶端使用DialTCP()該函數建立一個TCP連接。
DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error)
其中laddr是本地地址,通常設置為nil;raddr是一個服務的遠程地址, net是一個字符串,根據您是否希望是一個TCPv4連接,TCPv6連接來設置為"tcp4", "tcp6"或"tcp"中的一個,當然你也可以不關心鏈接形式。
客戶端可能發送的消息之一就是“HEAD”消息。這用來查詢服務器的信息和文檔信息。 服務器返回的信息,不返回文檔本身。發送到服務器的請求可能是:
"HEAD / HTTP/1.1\r\n\r\n"
來吧看一個完整的栗子:
package main
import (
"fmt"
"io/ioutil"
"net"
"os"
)
func main() {
tcpAddr, err := net.ResolveTCPAddr("tcp4", "localhost:80") //換成www.baidu.com:80試一試
checkError(err)
conn, err := net.DialTCP("tcp", nil, tcpAddr)
checkError(err)
_, err = conn.Write([]byte("GET / HTTP/1.0\r\n\r\n")) //發送http請求
checkError(err)
result, err := ioutil.ReadAll(conn)
checkError(err)
fmt.Println(string(result))
os.Exit(0)
}
func checkError(err error) {
if err != nil {
fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
os.Exit(1)
}
}
TCPConn的方法
- ReadFrom(r io.Reader) (int64, error)
- 從一個IO中讀取數據
- CloseRead() error
- CloseWrite() error
- SetLinger(sec int) error
- SetKeepAlive(keepalive bool) error
- 即使沒有任何通信,一個客戶端可能希望保持連接到服務器的狀態。
- SetNoDelay(noDelay bool) error
- 設置操作系統是否延遲發送數據包,默認是無延遲的
TCPlistener
type TCPListener struct {
fd *netFD
}
ListenTCP
在一個服務器上注冊並監聽一個端口。然后它阻塞在一個"accept"操作,並等待客戶端連接。當一個客戶端連接, accept調用返回一個連接(connection)對象
net參數可以設置為字符串"tcp", "tcp4"或者"tcp6"中的一個。如果你想監聽所有網絡接口,IP地址應設置為0,或如果你只是想監聽一個簡單網絡接口,IP地址可以設置為該網絡的地址。如果端口設置為0,O/S會為你選擇一個端口。否則,你可以選擇你自己的。需要注意的是,在Unix系統上,除非你是監控系統,否則不能監聽低於1024的端口,小於128的端口是由IETF標准化。該示例程序選擇端口1200沒有特別的原因。TCP地址如下":1200"
讓我們看個完整的栗子
package main
import (
"fmt"
"net"
"os"
"time"
)
func main() {
tcpAddr, err := net.ResolveTCPAddr("tcp", ":1201")
checkError(err)
listener, err := net.ListenTCP("tcp", tcpAddr)
checkError(err)
for {
conn, err := listener.Accept()
if err != nil {
continue
}
daytime := time.Now().String()
conn.Write([]byte(daytime))
conn.Close()
}
}
func checkError(err error) {
if err != nil {
fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
os.Exit(1)
}
}
相比客戶端服務器更要注意對錯誤的處理。服務器應該永遠運行,所以,如果出現任何錯誤與客戶端,服務器只是忽略客戶端繼續運行。否則,客戶端可以嘗試搞砸了與服務器的連接,並導致服務器宕機。
TCPListener方法
- AcceptTCP() (c *TCPConn, err error)
- 接收TCP連接
- Accept() (c Conn, err error)
- 接收,返回一個連接
- Close() error
- 關閉監聽
- Addr() Addr
- 返回監聽的網絡地址
- SetDeadline(t time.Time) error
-
設置監聽到期時間
listener.SetDeadline(time.Now().Add(time.Second * 30))
- File() (f *os.File, err error)
關於長連接理論上的實現.
長連接,就是不斷的連接.只要保證連接不斷.服務端不斷循環讀取連接中的值,然后進行處理.發送結果就OK了.保持連接..發送.接受.
