4

Go语言Socket编程

 2 years ago
source link: https://allenwind.github.io/blog/2521/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

大部分底层网络的编程都离不开socket编程。HTTP编程、Web开发、IM通信、视频流传输的底层都是socket编程。关于socket编程的基础知识参考TCP/IP协议栈的相关知识。

socket源于Unix,C语言世界中的socket编程。Python采用C语言实现,其自带的socket接口可以看作是Unix socket的OOP风格的socket编程接口。大致的过程如下:

服务器端:

  1. 创建套接字
  2. 设置监听队列
  3. 关闭套接字
  1. 创建套接字
  2. 连接服务器
  3. 关闭套接字

但Go语言采用一套新的接口,该接口比Unix中的socket简介多。由于Go的静态编译,使用Go编写的socket网络工具使用起来很方便。

本文先从TCP socket编程开始,然后到UDP socket,最后以一个简单的socket工具作为结尾。

TCP Socket

Go net包中TCPConn用来建立TCP客户端、TCP服务器端间的通信通道。类似于Python中的socket对象(通过socket.socket创建)通过DialTCP函数创建该对象。TCPListener服务器端socket,监听网络请求,通过ListenTCP函数创建该对象。形象地理解,可以把TCPConn看作是TCP的连接器;TCPListener看作是TCP监听器。监听器等待客户端连接,一旦有连接进来,创建TCP连接器,然后通过TCP连接器进行服务器端和客户端的通信。

下面通过TCP心跳(返回服务器端时间)来举例,编程中还有一些细节问题,这里不详细说,看代码注释。

TCP Server

TCP服务器端通过ListenTCP创建TCPListener对象。调用Accept方法进入LISTEN状态(参考TCP状态机)

编写tcp_tick_time.go代码。

package main

import (
"fmt"
"log"
"net"
"os"
"time"
)

func echo(conn *net.TCPConn) {
tick := time.Tick(5 * time.Second) // 五秒的心跳间隔
for now := range tick {
n, err := conn.Write([]byte(now.String()))
if err != nil {
log.Println(err)
conn.Close()
return
}
fmt.Printf("send %d bytes to %s\n", n, conn.RemoteAddr())
}
}

func main() {

address := net.TCPAddr{
IP: net.ParseIP("127.0.0.1"), // 把字符串IP地址转换为net.IP类型
Port: 8000,
}

listener, err := net.ListenTCP("tcp4", &address) // 创建TCP4服务器端监听器

if err != nil {
log.Fatal(err) // Println + os.Exit(1)
}

for {
conn, err := listener.AcceptTCP()
if err != nil {
log.Fatal(err) // 错误直接退出
}

fmt.Println("remote address:", conn.RemoteAddr())
go echo(conn)
}
}

通过终端直接启动。

go run tcp_tick_time.go

通过简单的客户端连接,我们可以看到该程序终端的显示信息:

remote address: 127.0.0.1:1915
send 37 bytes to 127.0.0.1:1915
send 37 bytes to 127.0.0.1:1915
send 37 bytes to 127.0.0.1:1915
send 35 bytes to 127.0.0.1:1915
send 37 bytes to 127.0.0.1:1915
send 37 bytes to 127.0.0.1:1915
send 37 bytes to 127.0.0.1:1915
2017/08/29 9:23:49 write tcp4 127.0.0.1:8000->127.0.0.1:1915: wsasend: An established connection was aborted by the software in your host machine.
send 0 bytes to 127.0.0.1:1915

TCP Client

通过func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error)创建TCP客户端。net需要指定具体的TCP
网络类型:”tcp”, “tcp4”, “tcp6”。laddr表示本地地址,一般为nil。raddr为要连接的服务器地址。

我们写一个简单的HTTP客户端。

package main 

import (
"net"
"log"
"fmt"
"io/ioutil"
"os"
)

func main() {
if len(os.Args) != 2 {
log.Fatalf("Usage: %s host:port", os.Args[0])
}

service := os.Args[1]
tcpAddr, err := net.ResolveTCPAddr("tcp4", service)
if err != nil {
log.Fatal(err)
}

conn, err := net.DialTCP("tcp4", nil, tcpAddr)
if err != nil {
log.Fatal(err)
}

n, err := conn.Write([]byte("HEAD / HTTP/1.1\r\n\r\n"))
if err != nil {
log.Fatal(err)
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK