【go语言 socket编程系列】Conn接口类型及简单服务器实现Read Write 和Close方法

【Conn接口类型】

Conn是一种通用的面向流的网络连接,多个Goroutine可以同时调用Conn上的方法。

主要通过Read(b []byte)读取数据,Write(b [byte]) 写数据 及Close() 关闭连接。

其源码定义在net.go中

type Conn interface {        
        Read(b []byte) (n int, err error)      
        Write(b []byte) (n int, err error)      
        Close() error      
        LocalAddr() Addr       
        RemoteAddr() Addr
        SetDeadline(t time.Time) error     
        SetReadDeadline(t time.Time) error
        SetWriteDeadline(t time.Time) error
}

【conn结构体】

conn结构体为一个 *netFD的网络文件描述符号,Conn接口方法都会作用在conn对象上。

type conn struct {
        fd *netFD
}

Read(b []byte)

Read 方法用于从conn对象中读取字节流并写入[]byte类型的b对象中。 

func (c *conn) Read(b []byte) (int, error) {
        if !c.ok() {
                return 0, syscall.EINVAL
        }
        n, err := c.fd.Read(b)
        if err != nil && err != io.EOF {
                err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
        }
        return n, err
}

Write(b [byte])

Write()方法用于把[]byte类型的切片中的数据写入到conn对象中

func (c *conn) Write(b []byte) (int, error) {
        if !c.ok() {
                return 0, syscall.EINVAL
        }
        n, err := c.fd.Write(b)
        if err != nil {
                err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
        }
        return n, err
}

Close()

Close()方法用于关闭conn连接。实现代码中会优先调用 ok()方法。

func (c *conn) Close() error {
        if !c.ok() {
                return syscall.EINVAL
        }
        err := c.fd.Close()
        if err != nil {
                err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
        }
        return err
}


func (c *conn) ok() bool { return c != nil && c.fd != nil }

【一个简单的服务器实现】

工作流程:通过net.ListenTCP()生成一个mylistener对象,通过mylistener.Accept()方法接受客户端请求

handleRequest自定义函数中,预先申请[]byte类型的变量 mybuff,用于存放 从conn对象读取的数据。并通过Write()方法再写入到conn对象中。

package main

import (
	"fmt"
	"net"
	"os"
)

func main() {
	service := ":2001"
	tcpAddr, err := net.ResolveTCPAddr("tcp", service)
	checkError(err)

	mylistener, err := net.ListenTCP("tcp", tcpAddr)
	checkError(err)

	for {
		conn, err := mylistener.Accept()
		if err != nil {
			continue
		}
		handleRequest(conn)
		conn.Close()

	}

}
func checkError(err error) {
	if err != nil {
		fmt.Println("Fatal error :", err.Error())
		os.Exit(1)
	}
}

func handleRequest(conn net.Conn) {
	var mybuff [512]byte
	for {
		n, err := conn.Read(mybuff[0:])
		if err != nil {
			return
		}
		fmt.Println(string(mybuff[0:]))
		fmt.Println("localaddr is:", conn.LocalAddr())
		fmt.Println("remoteaddr is:", conn.RemoteAddr())
		fmt.Println("##########")

		_, err2 := conn.Write(mybuff[0:n])
		if err2 != nil {
			return
		}
	}

}

func checckError(err error) {
	if err != nil {
		fmt.Println("Fatal err:", err.Error())
		os.Exit(1)
	}
}

客户端通过 telnet命令简单实现,输入内容后回车,会直接打印到屏幕。

c$telnet localhost 2001
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
the first server
the first server
second
second

服务端的显示如下

the first server

localaddr is: 127.0.0.1:2001
remoteaddr is: 127.0.0.1:50120
##########
second
t server

localaddr is: 127.0.0.1:2001
remoteaddr is: 127.0.0.1:50120
##########

从服务端的打印信息看, 有个“t server”的输出,其原因是 handleRequest函数中 定义的 mybuff是  [512]byte ,并通过mybuff[0:n]来写入数据。不同长度显示的会不一样。

猜你喜欢

转载自blog.csdn.net/natpan/article/details/82873581