go语言中的socket和http

简介: go语言中的socket和http

Socket 编程

以前我们使用Socket编程时,会按照如下步骤展开。

(1) 建立Socket:使用socket()函数。

(2) 绑定Socket:使用bind()函数。

(3) 监听:使用listen()函数。或者连接:使用connect()函数。

(4) 接受连接:使用accept()函数。

(5) 接收:使用receive()函数。或者发送:使用send()函数。

Go语言标准库对此过程进行了抽象和封装。无论我们期望使用什么协议建立什么形式的连接,都只需要调用net.Dial()即可。

Dial()函数

Dial()函数的原型如下:

func Dial(net, addr string) (Conn, error) 

其中net参数是网络协议的名字,addr参数是IP地址或域名,而端口号以“:”的形式跟随在地址或域名的后面,端口号可选。如果连接成功,返回连接对象,否则返回error。

TCP链接:

conn, err := net.Dial(“tcp”, “192.168.0.10:2100”)

UDP链接:

conn, err := net.Dial(“udp”, “192.168.0.12:975”)

ICMP链接:

conn, err := net.Dial(“ip4:icmp”, “www.baidu.com”)

ICMP链接

conn, err := net.Dial(“ip4:1”, “10.0.0.3”)

链接查看协议编号的含义:http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml

目前,Dial()函数支持如下几种网络协议:“tcp”、“tcp4”(仅限IPv4)、“tcp6”(仅限IPv6)、“udp”、“udp4”(仅限IPv4)、“udp6”(仅限IPv6)、“ip”、“ip4”(仅限IPv4)和"ip6"

(仅限IPv6)。

在成功建立连接后,我们就可以进行数据的发送和接收。发送数据时,使用conn的Write()成员方法,接收数据时使用Read()方法。

ICMP示例程序

下面我们实现这样一个例子:我们使用ICMP协议向在线的主机发送一个问候,并等待主机返回。

package main 
import ( 
 "net" 
 "os" 
 "bytes" 
 "fmt" 
) 
func main() { 
 if len(os.Args) != 2 { 
 fmt.Println("Usage: ", os.Args[0], "host") 
 os.Exit(1) 
 } 
 service := os.Args[1] 
 conn, err := net.Dial("ip4:icmp", service) 
 checkError(err) 
 var msg [512]byte
 msg[0] = 8 // echo 
 msg[1] = 0 // code 0 
 msg[2] = 0 // checksum 
 msg[3] = 0 // checksum 
 msg[4] = 0 // identifier[0] 
 msg[5] = 13 //identifier[1] 
 msg[6] = 0 // sequence[0] 
 msg[7] = 37 // sequence[1] 
 len := 8 
 check := checkSum(msg[0:len]) 
 msg[2] = byte(check >> 8) 
 msg[3] = byte(check & 255) 
 _, err = conn.Write(msg[0:len]) 
 checkError(err) 
 _, err = conn.Read(msg[0:]) 
 checkError(err) 
 fmt.Println("Got response") 
 if msg[5] == 13 { 
 fmt.Println("Identifier matches") 
 } 
 if msg[7] == 37 { 
 fmt.Println("Sequence matches") 
 } 
 os.Exit(0) 
} 
func checkSum(msg []byte) uint16 { 
 sum := 0 
 // 先假设为偶数
for n := 1; n <len(msg)-1; n += 2 { 
 sum += int(msg[n])*256 + int(msg[n+1]) 
 } 
 sum = (sum >> 16) + (sum & 0xffff) 
 sum += (sum >> 16) 
var answer uint16 = uint16(^sum) 
return answer 
} 
func checkError(err error) { 
if err != nil { 
 fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error()) 
 os.Exit(1) 
 } 
} 
func readFully(conn net.Conn) ([]byte, error) { 
 defer conn.Close() 
 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
} 

执行结果如下:

$ go build icmptest.go

$ ./icmptest www.baidu.com

Got response

Identifier matches

Sequence matches

TCP示例程序

下面我们建立TCP链接来实现初步的HTTP协议,通过向网络主机发送HTTP Head请求,读取网络主机返回的信息

package main 
import ( 
 "net" 
 "os" 
 "bytes" 
 "fmt" 
) 
func main() { 
if len(os.Args) != 2 { 
 fmt.Fprintf(os.Stderr, "Usage: %s host:port", os.Args[0]) 
 os.Exit(1) 
 } 
 service := os.Args[1] 
 conn, err := net.Dial("tcp", service) 
 checkError(err) 
 _, err = conn.Write([]byte("HEAD / HTTP/1.0\r\n\r\n")) 
 checkError(err) 
 result, err := readFully(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) 
 } 
} 
func readFully(conn net.Conn) ([]byte, error) { 
 defer conn.Close() 
 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
} 

执行这段程序并查看执行结果:

$ go build simplehttp.go

$ ./simplehttp qbox.me:80

HTTP/1.1 301 Moved Permanently

Server: nginx/1.0.14

Date: Mon, 21 May 2012 03:15:08 GMT

Content-Type: text/html

Content-Length: 184

Connection: close

Location: https://qbox.me/

HTTP 编程

HTTP(HyperText Transfer Protocol,超文本传输协议)是互联网上应用最为广泛的一种网络协议,定义了客户端和服务端之间请求与响应的传输标准。

Go语言标准库内建提供了net/http包,涵盖了HTTP客户端和服务端的具体实现。使用net/http包,我们可以很方便地编写HTTP客户端或服务端的程序。

HTTP客户端

Go内置的net/http包提供了最简洁的HTTP客户端实现,

基本方法

net/http包的Client类型提供了如下几个方法,让我们可以用最简洁的方式实现 HTTP 请求:

func (c *Client) Get(url string) (r *Response, err error) 
func (c *Client) Post(url string, bodyType string, body io.Reader) (r *Response, err error) 
func (c *Client) PostForm(url string, data url.Values) (r *Response, err error) 
func (c *Client) Head(url string) (r *Response, err error) 
func (c *Client) Do(req *Request) (resp *Response, err error) 

http.Get()

要请求一个资源,只需调用http.Get()方法(等价于http.DefaultClient.Get())即可,示例代码如下:

resp, err := http.Get("http://example.com/") 
if err != nil { 
 // 处理错误 ... 
 return
} 
defer resp.Body.close() 
io.Copy(os.Stdout, resp.Body) 

http.Post()

要以POST的方式发送数据,也很简单,只需调用http.Post()方法并依次传递下面的3个参数即可:

 请求的目标 URL

 将要 POST 数据的资源类型(MIMEType)

 数据的比特流([]byte形式)

下面的示例代码演示了如何上传一张图片:

resp, err := http.Post("http://example.com/upload", "image/jpeg", &imageDataBuf) 
if err != nil { 
 // 处理错误 
 return
} 
if resp.StatusCode != http.StatusOK { 
 // 处理错误
 return
} 

http.PostForm()

http.PostForm()方法实现了标准编码格式为application/x-www-form-urlencoded的表单提交。下面的示例代码模拟HTML表单提交一篇新文章:

resp, err := http.PostForm("http://example.com/posts", url.Values{"title": 
 {"article title"}, "content": {"article body"}}) 
if err != nil { 
 // 处理错误
 return
} 

 **http.Head() **

HTTP 中的 Head 请求方式表明只请求目标 URL 的头部信息,即 HTTP Header 而不返回 HTTP Body。Go 内置的 net/http 包同样也提供了 http.Head() 方法,该方法同 http.Get() 方法一样,只需传入目标 URL 一个参数即可。下面的示例代码请求一个网站首页的 HTTP Header信息:

resp, err := http.Head("http://example.com/") 

 *(http.Client).Do()

在多数情况下,http.Get()和http.PostForm() 就可以满足需求,但是如果我们发起的HTTP 请求需要更多的定制信息,我们希望设定一些自定义的 Http Header 字段,比如:

 设定自定义的"User-Agent",而不是默认的 “Go http package”

 传递 Cookie

此时可以使用net/http包http.Client对象的Do()方法来实现:

req, err := http.NewRequest("GET", "http://example.com", nil) 
// ... 
req.Header.Add("User-Agent", "Gobook Custom User-Agent") 
// ... 
client := &http.Client{ //... } 
resp, err := client.Do(req) 
// ... 


相关文章
|
1月前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
144 1
|
3月前
|
Cloud Native 安全 Java
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
281 1
|
3月前
|
Cloud Native Go API
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
358 0
|
3月前
|
Cloud Native Java Go
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
229 0
|
3月前
|
Cloud Native Java 中间件
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
210 0
|
3月前
|
Cloud Native Java Go
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
300 0
|
3月前
|
数据采集 Go API
Go语言实战案例:多协程并发下载网页内容
本文是《Go语言100个实战案例 · 网络与并发篇》第6篇,讲解如何使用 Goroutine 和 Channel 实现多协程并发抓取网页内容,提升网络请求效率。通过实战掌握高并发编程技巧,构建爬虫、内容聚合器等工具,涵盖 WaitGroup、超时控制、错误处理等核心知识点。
|
3月前
|
数据采集 JSON Go
Go语言实战案例:实现HTTP客户端请求并解析响应
本文是 Go 网络与并发实战系列的第 2 篇,详细介绍如何使用 Go 构建 HTTP 客户端,涵盖请求发送、响应解析、错误处理、Header 与 Body 提取等流程,并通过实战代码演示如何并发请求多个 URL,适合希望掌握 Go 网络编程基础的开发者。
|
4月前
|
JSON 前端开发 Go
Go语言实战:创建一个简单的 HTTP 服务器
本篇是《Go语言101实战》系列之一,讲解如何使用Go构建基础HTTP服务器。涵盖Go语言并发优势、HTTP服务搭建、路由处理、日志记录及测试方法,助你掌握高性能Web服务开发核心技能。
|
4月前
|
Go
如何在Go语言的HTTP请求中设置使用代理服务器
当使用特定的代理时,在某些情况下可能需要认证信息,认证信息可以在代理URL中提供,格式通常是:
381 0