net

TCP

公共结构体

//tcp连接
[heap]
pub struct TcpConn {  //实现io.Reader,io.Writer接口
pub mut:
	sock TcpSocket //Socket对象
mut:
	write_deadline time.Time
	read_deadline  time.Time
	read_timeout   time.Duration
	write_timeout  time.Duration
	is_blocking    bool
}

//tcp socket对象
struct TcpSocket {
pub:
	handle int //socket的文件描述符
}

方法:

pub fn (mut c TcpConn) close() !	//关闭连接,一般在函数的defer中调用

pub fn (mut c TcpConn) set_read_timeout(t time.Duration)	//设置读超时的时间
pub fn (mut c TcpConn) set_write_timeout(t time.Duration)	//设置写超时的时间

pub fn (c &TcpConn) read_timeout() time.Duration	//获取读超时的时间
pub fn (c &TcpConn) write_timeout() time.Duration	//获取写超时的时间

pub fn (mut c TcpConn) set_read_deadline(deadline time.Time) //设置读的限制时间点
pub fn (mut c TcpConn) set_write_deadline(deadline time.Time) //设置写的限制时间点

pub fn (mut c TcpConn) write_deadline() !time.Time //获取写的限制时间点

客户端

//客户端拨号,成功则返回一个TCP连接
pub fn dial_tcp(address string) !&TcpConn

客户端连接例子:

module main

import net
import io

fn main() {
	mut client_conn := net.dial_tcp('baidu.com:80') !
	defer {
		client_conn.close() or { println(err) }	// defer中,不可向上抛转错误
	}
	client_conn.write_string('GET /index.html HTTP/1.0\r\n\r\n') !
	client_conn.set_read_timeout(net.infinite_timeout)
	result := io.read_all(io.ReadAllConfig{ reader: client_conn }) !
	println(result.bytestr())
}

服务端

//服务端启动监听
pub fn listen_tcp(family AddrFamily, saddr string) !&TcpListener 
//TCP监听器
pub struct TcpListener {
	sock TcpSocket

mut:
	accept_timeout time.Duration
	accept_deadline time.Time
}

方法:

//监听成功后,等待客户端请求,调用accept以后,开始监听,接收一次请求成功后,返回TCP连接,
pub fn (l TcpListener) accept() !TcpConn

pub fn (mut c TcpListener) set_accept_deadline(deadline time.Time) 
pub fn (mut c TcpListener) set_accept_timeout(t time.Duration)

服务端连接例子:

module main

import net
import time

const (
	port = 9999
)

fn setup() (&net.TcpListener, &net.TcpConn, &net.TcpConn) {
	mut listener := net.listen_tcp(.ip6, ':$port') or { panic(err) }

	mut client := net.dial_tcp('127.0.0.1:$port') or { panic(err) }

	client.set_read_timeout(3 * time.second)
	client.set_write_timeout(3 * time.second)

	mut server := listener.accept() or { panic(err) }
	server.set_read_timeout(3 * time.second)
	server.set_write_timeout(3 * time.second)

	return listener, client, server
}

fn cleanup(mut listener net.TcpListener, mut client net.TcpConn, mut server net.TcpConn) {
	listener.close() or {}
	client.close() or {}
	server.close() or {}
}

fn main() {
	mut listener, mut client, mut server := setup()
	defer {
		cleanup(mut listener, mut client, mut server)
	}
	message := 'Hello World'
	// server
	server.write_string(message) !
	println('message send: $message')
	println('server socket: $server.sock.handle')
	// client
	mut buf := []u8{len: 1024}
	nbytes := client.read(mut buf) !
	received := buf[0..nbytes].bytestr()
	println('message received: $received')
	println('client socket: $client.sock.handle')
}

UDP

实现思路基本跟TCP一致

客户端

//客户端拨号
pub fn dial_udp(raddr string) !&UdpConn 
//返回udp连接
pub struct UdpConn { //实现io.Reader,io.Writer接口
	sock UdpSocket //Socket对象

mut:
	write_deadline time.Time
	read_deadline time.Time

	read_timeout time.Duration
	write_timeout time.Duration
}
//udp socket对象
struct UdpSocket {
        Socket
        l Addr
        // TODO(emily): replace with option again
        // when i figure out how to coerce it properly
mut:
        has_r bool
        r     Addr
}

服务端

//服务端启动监听,返回udp连接,udp不需要accept,直接开始
pub fn listen_udp(laddr string) !&UdpConn

服务端连接例子:

import net
import time

const (
	local_addr  = ':40003'
	remote_addr = '127.0.0.1:40003'
)

fn echo_server(mut c &net.UdpConn) {
	c.set_read_timeout(10 * time.second)
	c.set_write_timeout(10 * time.second)
	for { //无限循环监听,接收数据后,原样返回给客户端
		mut buf := []u8{len: 100, init: 0}
		read, addr := c.read(mut buf) or { continue }
		c.write_to(addr, buf[..read]) or {
			println('Server: connection dropped')
			return
		}
	}
}

fn echo() ! {
	//客户端拨号
	mut c := net.dial_udp(remote_addr) !
	defer {
		c.close() or {}
	}

	c.set_read_timeout(10 * time.second)
	c.set_write_timeout(10 * time.second)

	data := 'Hello from vlib/net!'
	c.write_string(data) !
	mut buf := []u8{len: 100, init: 0}
	read, addr := c.read(mut buf) !
	assert read == data.len
	println('Got address $addr')
	for i := 0; i < read; i++ {
		assert buf[i] == data[i]
	}
	println('Got "$buf.bytestr()"')
	c.close() !
	return
}

fn main() {
	mut l := net.listen_udp(local_addr) or { //服务端启动udp监听
		println(err)
		panic(err)
	}
	go echo_server(mut l)
	echo() or { println(err) }
	l.close() or {}
}

websocket

客户端

//创建websocket客户端
pub fn new_client(address string) !&Client
//返回客户端对象
pub struct Client {
	is_server bool
mut:
	ssl_conn          &openssl.SSLConn // secure connection used when wss is used
	flags             []Flag     // flags used in handshake
	fragments         []Fragment // current fragments
	message_callbacks []MessageEventHandler // all callbacks on_message
	error_callbacks   []ErrorEventHandler   // all callbacks on_error
	open_callbacks    []OpenEventHandler    // all callbacks on_open
	close_callbacks   []CloseEventHandler   // all callbacks on_close
pub:
	is_ssl bool   // true if secure socket is used
	uri    Uri    // uri of current connection
	id     string // unique id of client
pub mut:
	header            http.Header  // headers that will be passed when connecting
	conn              &net.TcpConn // underlying TCP socket connection
	nonce_size        int = 16 // size of nounce used for masking
	panic_on_callback bool     // set to true of callbacks can panic
	state             State    // current state of connection
	logger            &log.Log // logger used to log messages
	resource_name     string   // name of current resource
	last_pong_ut      i64      // last time in unix time we got a pong message
}
//定义4个回调函数
ws.on_open(fn (mut ws websocket.Client)  !	//连接回调
ws.on_error(fn (mut ws websocket.Client, err string) !	//报错回调
ws.on_message(fn (mut ws websocket.Client, msg &websocket.Message) ! //接收消息回调
ws.on_close(fn (mut ws websocket.Client, code int, reason string) ! //关闭连接回调
//跟服务端建立连接
pub fn (mut ws Client) connect() !
//监听服务端发送的消息
pub fn (mut ws Client) listen() !
//实现io模块的读写接口,读写消息
pub fn (mut ws Client) write(bytes []u8, code OPCode) !
pub fn (mut ws Client) write_str(str string) !

服务端

//创建websocket服务端
pub fn new_server(family net.AddrFamily, port int, route string) &Server
//返回服务端对象
pub struct Server {
mut:
	logger                  &log.Log // logger used to log
	ls                      &net.TcpListener      // listener used to get incoming connection to socket
	accept_client_callbacks []AcceptClientFn      // accept client callback functions
	message_callbacks       []MessageEventHandler // new message callback functions
	close_callbacks         []CloseEventHandler   // close message callback functions
pub:
	family net.AddrFamily = .ip
	port   int  // port used as listen to incoming connections
	is_ssl bool // true if secure connection (not supported yet on server)
pub mut:
	clients       map[string]&ServerClient // clients connected to this server
	ping_interval int = 30 // interval for sending ping to clients (seconds)
	state         State // current state of connection
}

struct ServerClient {
pub:
	resource_name string // resource that the client access
	client_key    string // unique key of client
pub mut:
	server &Server
	client &Client
}
//创建3个回调函数
s.on_connect(fn (mut s websocket.ServerClient) !bool //连接回调
s.on_message(fn (mut ws websocket.Client, msg &websocket.Message) ! //消息接收回调
s.on_close(fn (mut ws websocket.Client, code int, reason string) !  //关闭连接回调            
//开始启动监听
pub fn (mut s Server) listen() !

演示实例代码

module main

import net.websocket
import time

fn main() {
	go start_server()
	time.sleep(100 * time.millisecond)
	ws_client('ws://127.0.0.1:30000') ! 
}

fn start_server() ! {
	mut s := websocket.new_server(.ip6, 30000, '')
	s.ping_interval = 100
	s.on_connect(fn (mut s websocket.ServerClient) !bool {
		// Here you can look att the client info and accept or not accept
		// just returning a true/false
		if s.resource_name != '/' {
			panic('unexpected resource name in test')
			return false
		}
		return true
	}) !
	s.on_message(fn (mut ws websocket.Client, msg &websocket.Message) ! {
		ws.write(msg.payload, msg.opcode) or { panic(err) }
	})
	s.on_close(fn (mut ws websocket.Client, code int, reason string) ! {
		println('client ($ws.id) closed connection')
	})
	s.listen() or { println('error on server listen: $err') }
}

fn ws_client(uri string) ! {
	eprintln('connecting to $uri ...')
	mut ws := websocket.new_client(uri) !
	ws.on_open(fn (mut ws websocket.Client) ! {
		println('open!')
		ws.pong() or { panic(err) }
	})
	ws.on_error(fn (mut ws websocket.Client, err string) ! {
		println('error: $err')
		// this can be thrown by internet connection problems
	})
	ws.on_close(fn (mut ws websocket.Client, code int, reason string) ! {
		println('closed')
	})
	ws.on_message(fn (mut ws websocket.Client, msg &websocket.Message) ! {
		println('client got type: $msg.opcode payload:\n$msg.payload')
		if msg.opcode == .text_frame {
			smessage := msg.payload.bytestr()
			println('Message: $smessage')
		} else {
			println('Binary message: $msg')
		}
	})
	ws.connect() or { panic('fail to connect') }
	go ws.listen()
	text := ['a'].repeat(2)
	for msg in text {
		ws.write(msg.bytes(), .text_frame) or { panic('fail to write to websocket') }
		// wait to give time to recieve response before send a new one
		time.sleep(100 * time.millisecond)
	}
	// wait to give time to recieve response before asserts
	time.sleep(500 * time.millisecond)
}

urllib

把url字符串解析成URL类型:

pub fn parse(rawurl string) !URL

URL结构体:

pub struct URL {
pub mut:
	scheme      string
	opaque      string    // encoded opaque data
	user        &Userinfo // username and password information
	host        string    // host or host:port
	path        string    // path (relative paths may omit leading slash)
	raw_path    string    // encoded path hint (see escaped_path method)
	force_query bool      // append a query ('?') even if raw_query is empty
	raw_query   string    // encoded query values, without '?'
	fragment    string    // fragment for references, without '#'
}

struct Userinfo {
pub:
	username     string
	password     string
	password_set bool
}

URL方法:

pub fn (u &URL) hostname() string 
pub fn (u &URL) port() string
pub fn (u &URL) query() Values

其他函数:

pub fn parse_query(query string) !Values
struct Value {
pub mut:
	data []string
}

struct Values {
pub mut:
	data map[string]Value
	len  int
}

附录:TCP网络连接示意图


最后更新于