golang使用net包中的Dial,Listen做http请求响应
golang提供的net包中,有tcp,http等多种封装好的接口和方法,这里先看下net保重的Dial
我是服务端:在 main() 中创建了一个 net.Listener 类型的变量 listener,他实现了服务器的基本功能:用来监听和接收来自客户端的请求(基于 TCP 协议下,位于 IP 地址为 127.0.0.1、端口为 50000 的 localhost)。Listen() 函数可以返回一个 error 类型的错误变量。用一个无限 for 循环的 listener.Accept() 来等待客户端的请求。客户端的请求将产生一个 net.Conn 类型的连接变量。然后一个独立的协程使用这个连接执行 doServerStuff(),开始使用一个 512 字节的缓冲 data 来读取客户端发送来的数据,并且把它们打印到服务器的终端,len() 获取客户端发送的数据字节数;当客户端发送的所有数据都被读取完成时,协程就结束了。这段程序会为每一个客户端连接创建一个独立的协程。必须先运行服务器代码,再运行客户端代码。
package main
import (
"fmt"
"net"
)
func main() {
fmt.Println("Starting the server ...")
// 创建 listener
listener, err := net.Listen("tcp", "localhost:50000")
if err != nil {
fmt.Println("Error listening", err.Error())
return //终止程序
}
// 监听并接受来自客户端的连接
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println("Error accepting", err.Error())
return // 终止程序
}
go doServerStuff(conn)
}
}
func doServerStuff(conn net.Conn) {
for {
buf := make([]byte, 512)
len, err := conn.Read(buf)
if err != nil {
fmt.Println("Error reading", err.Error())
return //终止程序
}
fmt.Printf("Received data: %v", string(buf[:len]))
}
}
我是客户端:
客户端通过 net.Dial() 创建了一个和服务器之间的连接。
它通过无限循环从 os.Stdin 接收来自键盘的输入,直到输入了“Q”。注意裁剪 \r 和 \n 字符(仅 Windows 平台需要)。裁剪后的输入被 connection 的 Write() 方法发送到服务器。
当然,服务器必须先启动好,如果服务器并未开始监听,客户端是无法成功连接的。
package main
import (
"bufio"
"fmt"
"net"
"os"
"strings"
)
func main() {
//打开连接:
conn, err := net.Dial("tcp", "localhost:50000")
if err != nil {
//由于目标计算机积极拒绝而无法创建连接
fmt.Println("Error dialing", err.Error())
return // 终止程序
}
inputReader := bufio.NewReader(os.Stdin)
fmt.Println("First, what is your name?")
clientName, _ := inputReader.ReadString('\n')
// fmt.Printf("CLIENTNAME %s", clientName)
trimmedClient := strings.Trim(clientName, "\r\n") // Windows 平台下用 "\r\n",Linux平台下使用 "\n"
// 给服务器发送信息直到程序退出:
for {
fmt.Println("What to send to the server? Type Q to quit.")
input, _ := inputReader.ReadString('\n')
trimmedInput := strings.Trim(input, "\r\n")
// fmt.Printf("input:--%s--", input)
// fmt.Printf("trimmedInput:--%s--", trimmedInput)
if trimmedInput == "Q" {
return
}
_, err = conn.Write([]byte(trimmedClient + " says: " + trimmedInput))
}
}
我是Dial:在网络编程中 net.Dial() 函数是非常重要的,一旦你连接到远程系统,函数就会返回一个 Conn 类型的接口,我们可以用它发送和接收数据。Dial() 函数简洁地抽象了网络层和传输层。所以不管是 IPv4 还是 IPv6,TCP 或者 UDP 都可以使用这个公用接口。
以下示例先使用 TCP 协议连接远程 80 端口,然后使用 UDP 协议连接,最后使用 TCP 协议连接 IPv6 地址:
// make a connection with www.example.org:
package main
import (
"fmt"
"net"
"os"
)
func main() {
conn, err := net.Dial("tcp", "192.0.32.10:80") // tcp ipv4
checkConnection(conn, err)
conn, err = net.Dial("udp", "192.0.32.10:80") // udp
checkConnection(conn, err)
conn, err = net.Dial("tcp", "[2620:0:2d0:200::10]:80") // tcp ipv6
checkConnection(conn, err)
}
func checkConnection(conn net.Conn, err error) {
if err != nil {
fmt.Printf("error %v connecting!", err)
os.Exit(1)
}
fmt.Printf("Connection is made with %v\n", conn)
}
我是socket,使用 net 包从 socket 中打开,写入,读取数据的例子:
package main
import (
"fmt"
"io"
"net"
)
func main() {
var (
host = "www.apache.org"
port = "80"
remote = host + ":" + port
msg string = "GET / \n"
data = make([]uint8, 4096)
read = true
count = 0
)
// 创建一个 socket
con, err := net.Dial("tcp", remote)
// 发送我们的消息,一个 http GET 请求
io.WriteString(con, msg)
// 读取服务器的响应
for read {
count, err = con.Read(data)
read = (err == nil)
fmt.Printf(string(data[0:count]))
}
con.Close()
}
我是demo
在 initServer() 函数中通过 net.ResolveTCPAddr() 得到了服务器地址和端口,这个函数最终返回了一个 *net.TCPListener
每一个连接都会以协程的方式运行 connectionHandler() 函数。函数首先通过 conn.RemoteAddr() 获取到客户端的地址并显示出来
它使用 conn.Write() 发送 Go 推广消息给客户端
它使用一个 25 字节的缓冲读取客户端发送的数据并一一打印出来。如果读取的过程中出现错误,代码会进入 switch 语句 default 分支,退出无限循环并关闭连接。如果是操作系统的 EAGAIN 错误,它会重试。
所有的错误检查都被重构在独立的函数 checkError 中,当错误产生时,利用错误上下文来触发 panic。
// Simple multi-thread/multi-core TCP server.
package main
import (
"flag"
"fmt"
"net"
"syscall"
)
const maxRead = 25
func main() {
flag.Parse()
if flag.NArg() != 2 {
panic("usage: host port")
}
hostAndPort := fmt.Sprintf("%s:%s", flag.Arg(0), flag.Arg(1))
listener := initServer(hostAndPort)
for {
conn, err := listener.Accept()
checkError(err, "Accept: ")
go connectionHandler(conn)
}
}
func initServer(hostAndPort string) net.Listener {
serverAddr, err := net.ResolveTCPAddr("tcp", hostAndPort)
checkError(err, "Resolving address:port failed: '"+hostAndPort+"'")
listener, err := net.ListenTCP("tcp", serverAddr)
checkError(err, "ListenTCP: ")
println("Listening to: ", listener.Addr().String())
return listener
}
func connectionHandler(conn net.Conn) {
connFrom := conn.RemoteAddr().String()
println("Connection from: ", connFrom)
sayHello(conn)
for {
var ibuf []byte = make([]byte, maxRead+1)
length, err := conn.Read(ibuf[0:maxRead])
ibuf[maxRead] = 0 // to prevent overflow
switch err {
case nil:
handleMsg(length, err, ibuf)
case syscall.EAGAIN: // try again
continue
default:
goto DISCONNECT
}
}
DISCONNECT:
err := conn.Close()
println("Closed connection: ", connFrom)
checkError(err, "Close: ")
}
func sayHello(to net.Conn) {
obuf := []byte{'L', 'e', 't', '\'', 's', ' ', 'G', 'O', '!', '\n'}
wrote, err := to.Write(obuf)
checkError(err, "Write: wrote "+string(wrote)+" bytes.")
}
func handleMsg(length int, err error, msg []byte) {
if length > 0 {
print("<", length, ":")
for i := 0; ; i++ {
if msg[i] == 0 {
break
}
fmt.Printf("%c", msg[i])
}
print(">")
}
}
func checkError(error error, info string) {
if error != nil {
panic("ERROR: " + info + " " + error.Error()) // terminate program
}
}
更多推荐
所有评论(0)