【TCPConn】
net.TCPConn是允许服务端与客户端之间的全双工通信的Go类型。其定义在tcpsock.go文件。
其定义如下
type TCPConn struct {
conn
}
注意到 conn 是小写的c,其定义在net.go文件中,源码如下
type conn struct {
fd *netFD
}
即conn是一个struct类型,只有一个指向netFD类型的 fd指针。 netFD定义在fd_unix.go中,其定义如下
即 netFD是一个网络文件描述符。
type netFD struct {
// locking/lifetime of sysfd + serialize access to Read and Write methods
fdmu fdMutex
// immutable until Close
sysfd int
family int
sotype int
isConnected bool
net string
laddr Addr
raddr Addr
// wait server
pd pollDesc
}
【常用方法】
func (c *conn) Read(b []byte) (int, error)
其在net.go中定义如下
// Read implements the Conn Read method.
func (c *conn) Read(b []byte) (int, error) {
if !c.ok() {
return 0, syscall.EINVAL
}
return c.fd.Read(b)
}
接受者c *conn 的Read方法 调用了fd成员的Read方法。其定义在fd_unix.go 中,源码如下:
func (fd *netFD) Read(p []byte) (n int, err error) {
if err := fd.readLock(); err != nil {
return 0, err
}
defer fd.readUnlock()
if err := fd.pd.PrepareRead(); err != nil {
return 0, &OpError{"read", fd.net, fd.raddr, err}
}
for {
n, err = syscall.Read(int(fd.sysfd), p)
if err != nil {
n = 0
if err == syscall.EAGAIN {
if err = fd.pd.WaitRead(); err == nil {
continue
}
}
}
err = chkReadErr(n, err, fd)
break
}
if err != nil && err != io.EOF {
err = &OpError{"read", fd.net, fd.raddr, err}
}
return
}
func (c *conn) Write(b []byte) (int, error) 函数同Read一样,略。
【net.DialTCP方法】
func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) 主要用于创建一个TCPConn
net 参数为 tcp tcp4 tcp6
laddr 为本地地址,通常为nil
raddr 为目的地址, 为TCPAddr类型的指针
函数返回一个 *TCPConn,可通过 Read 和Write 方法传递数据。
net,DialTCP定义在tcpsock_posix.go文件中,其源码如下
func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
switch net {
case "tcp", "tcp4", "tcp6":
default:
return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: UnknownNetworkError(net)}
}
if raddr == nil {
return nil, &OpError{Op: "dial", Net: net, Addr: nil, Err: errMissingAddress}
}
return dialTCP(net, laddr, raddr, noDeadline)
}
主要通过调用私有函数dialTCP实现TCPConn的创建,dialTCP又会通过newTCPConn 来实现句柄的创建,最终会调用unix系统接口完成。
【代码实现】
调用net.DialTCP方法的代码demo
package main
import (
"fmt"
"io/ioutil"
"net"
"os"
)
func main() {
service := "www.baidu.com:80"
tcpAddr, err := net.ResolveTCPAddr("tcp", service)
checkError(err)
fmt.Println("tcpAddr :")
typeof(tcpAddr)
myConn, err1 := net.DialTCP("tcp", nil, tcpAddr)
checkError(err1)
fmt.Println("myConn :")
typeof(myConn)
_, err = myConn.Write([]byte("HEAD / HTTP/1.1\r\n\r\n"))
checkError(err)
result, err := ioutil.ReadAll(myConn)
checkError(err)
fmt.Println(string(result))
os.Exit(0)
}
func typeof(v interface{}) {
fmt.Printf("type is:%T\n", v)
}
func checkError(err error) {
if err != nil {
fmt.Println("Error:", err.Error())
os.Exit(1)
}
}
编译执行如下
$./l_DialTCP
tcpAddr :
type is:*net.TCPAddr
myConn :
type is:*net.TCPConn
HTTP/1.1 400 Bad Request
Server: nginx/1.13.5
Date: Wed, 26 Sep 2018 07:17:05 GMT
Content-Type: text/html
Content-Length: 173
Connection: close
$