1 TCP编程
1.1 C/S模型
// 查看本机所有端口信息
netstat -an
// 查看所有端口 pid
netstat -anb
C/S模型
Server
package main
import (
"fmt"
"io"
"net"
)
func doProcess(conn net.Conn) {
defer conn.Close()
for{
buf := make([]byte, 1024)
n, err := conn.Read(buf)
if err == io.EOF{
fmt.Printf("conn.Read close: %s\n", err)
break
}else if err != nil{
fmt.Printf("conn.Read err : %s\n", err)
break
}
fmt.Printf("read byte[%d] info[%s]\n", n, string(buf[:n]))
if n == 4 && "exit" == string(buf[:n]){
fmt.Printf("[Exit] gorutine\n")
break
}
}
}
func main() {
listen, err := net.Listen("tcp", "192.168.19.1:8888")
fmt.Println("[1] 监听端口 192.168.19.1:8888...")
if err != nil{
fmt.Printf("Listen err : %s\n", err)
return
}
defer listen.Close()
fmt.Printf("listen type : %T val : %v\n", listen, listen)
for{
fmt.Println("[2] 阻塞等待客户端连接 192.168.19.1:8888...")
conn, err := listen.Accept()
if err != nil{
fmt.Printf("Accept err : %s\n", err)
continue
}
fmt.Printf("conn type : %T val : %v\n", conn, conn)
fmt.Printf("conn client ip: %s server ip: %s\n", conn.RemoteAddr(), conn.LocalAddr())
go doProcess(conn)
}
}
Client
package main
import (
"bufio"
"fmt"
"net"
"os"
"strings"
)
func main() {
conn, err := net.Dial("tcp", "192.168.19.1:8888")
if err != nil{
fmt.Printf("net.Dial err : %s\n", err)
return
}
defer conn.Close()
fmt.Printf("client conn success conn type : %T val : %v \n", conn, conn)
for{
reader := bufio.NewReader(os.Stdin)
readString, err := reader.ReadString('\n')
readString = strings.Trim(readString, "\r\n")
if err != nil{
fmt.Printf("reader.ReadString err : %s\n", err)
return
}
n, err := conn.Write([]byte(readString))
if err != nil{
fmt.Printf("conn.Write err : %s\n", err)
return
}
fmt.Printf("client send byte[%d] info[%s]\n", n, readString)
if "exit" == readString {
fmt.Printf("[Exit] gorutine\n")
break
}
}
}
1.2 others
2 Redis
2.1 简介
port:6379
2.2 CLI操作:快速入门
DOC操作
127.0.0.1:6379> set k1 xhh
OK
127.0.0.1:6379> get k1
"xhh"
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> get k1
(nil)
127.0.0.1:6379> dbsize
(integer) 1
flushdb
flushall
2.3 string
string是redis最基本类型,二进制安全的,除了存储字符串外也可以存储图片数据 一个key对应一个val 类似于addr := "henan-loyang" 一个字符串最大为512M
127.0.0.1:6379> set addr henan-loyang
OK
127.0.0.1:6379> get addr
"henan-loyang"
127.0.0.1:6379> del addr
(integer) 1
127.0.0.1:6379> setex k1 5 newxhh
OK
127.0.0.1:6379> get k1
"newxhh"
127.0.0.1:6379> get k1
(nil)
127.0.0.1:6379> mset k1 xhh k2 abc k3 mcy
OK
127.0.0.1:6379> mget k1 k2 k3
1) "xhh"
2) "abc"
3) "mcy"
2.4 hash
类似于:var user1 map[string]string 方便用于存储对象、结构变量
_op_ key field [field ...]
- hset/hget/hgetall/hdel
- hmset/hmget // 一次设置多个值
- hlen // 统计hash有几个元素
- hexists key field // 判断field是否存在
127.0.0.1:6379[1]> hset user1 name "xhh"
(integer) 1
127.0.0.1:6379[1]> hset user1 age 18
(integer) 1
127.0.0.1:6379[1]> hget user1 name
"xhh"
127.0.0.1:6379[1]> hget user1 age
"18"
127.0.0.1:6379[1]> hgetall user1
1) "name"
2) "xhh"
3) "age"
4) "18"
2.5 list
本质是链表,用法理解为栈 按照插入的顺序排序,可以头插和尾插(采用的是头插,遍历时刚好相反)
_op_ key field [field ...]
- lpush/rpush // 左or右加入
- lrange // 执行区间元素
- lpop/rpop // 左or右出
- del
- llen // 返回链表的长度
127.0.0.1:6379> lpush city bj tj ly
(integer) 3
127.0.0.1:6379> lrange city 0 -1
1) "ly"
2) "tj"
3) "bj"
2.6 set
无序集合,不能重复,底层HashTable
- sadd
- smembers // 获取全部
- sismember // 判断是否是成员
- srem // 删除成员
127.0.0.1:6379> sadd emails xhh@123 mcy@456
(integer) 2
127.0.0.1:6379> smembers emails
1) "xhh@123"
2) "mcy@456"
2.7 Go操作Redis
【版本一】安装第三方开源redis库
在GOPATH路径下执行以下指令
go get github.com/garyburd/redigo/redis
【版本二】安装第三方开源redis库
把命令封装为函数
go get gopkg.in/redis.v4
import "gopkg.in/redis.v4"
写入和读取字符串
package main
import (
"fmt"
"github.com/garyburd/redigo/redis"
)
func main() {
conn, err := redis.Dial("tcp", "localhost:6379")
if err != nil{
fmt.Printf("redis.Dial err: %s\n", err)
return
}
defer conn.Close()
fmt.Printf("conn success conn type %T\n", conn)
_, err = conn.Do("set", "k1", "xhhinfo")
if err != nil{
fmt.Printf("conn.Do err: %s\n", err)
return
}
fmt.Printf("write success cli [set k1 xhhinfo]\n")
retStr, err := redis.String(conn.Do("get", "k1"))
if err != nil{
fmt.Printf("redis.String err: %s\n", err)
return
}
fmt.Printf("read success cli [get k1]: %s\n", retStr)
}
批量操作多个
package main
import (
"fmt"
"github.com/garyburd/redigo/redis"
)
func main() {
conn, err := redis.Dial("tcp", "localhost:6379")
if err != nil{
fmt.Printf("redis.Dial err: %s\n", err)
return
}
defer conn.Close()
fmt.Printf("conn success conn type %T\n", conn)
_, err = conn.Do("hmset", "person1", "name", "xhh", "age", "18")
if err != nil{
fmt.Printf("conn.Do err: %s\n", err)
return
}
fmt.Printf("write success cli [hmset person1 name xhh age 18]\n")
strs, err := redis.Strings(conn.Do("hmget", "person1", "name", "age"))
if err != nil{
fmt.Printf("redis.String err: %s\n", err)
return
}
for idx, str := range strs{
fmt.Printf("read success cli [hget person1 name age] line[%d]: %s\n", idx, str)
}
}
2.8 连接池
package main
import (
"fmt"
"github.com/garyburd/redigo/redis"
)
var (
pool *redis.Pool
)
func init() {
pool = &redis.Pool{
MaxIdle: 8,
MaxActive: 0,
IdleTimeout: 100,
Dial: func() (redis.Conn, error) {
return redis.Dial("tcp", "localhost:6379")
},
}
}
func main() {
conn := pool.Get()
defer conn.Close()
_, _ = conn.Do("set", "name", "xhh")
str, _ := redis.String(conn.Do("get", "name"))
fmt.Printf("read str: %s\n", str)
pool.Close()
}
3 用户聊天系统
3.1 数据传输流程
3.2
3.3
|