tcp编程、socket编程、redis

tcp编程(需要建立连接,三次握手,四次挥手,然后发送信息流,数据包是有序的)

udp编程(知道IP、端口直接发送数据,数据包可能是无序的)

1、客户端和服务器客

socket编程

1.服务端的处理流程
  a.监听端口
  b.接收客户端的链接
  c.创建goroutine,处理该链接

2.客户端的处理流程
  a.建立与服务端的链接
  b.进行数据收发
  c.关闭链接

3.服务端代码

1package main 2 3import ( 4 "fmt" 5 "net"//导入socket的包 6) 7 8func main() { 9 fmt.Println("start server...") 10 listen, err := net.Listen("tcp", "0.0.0.0:50000")//监听50000端口 11 if err != nil { 12 fmt.Println("listen failed, err:", err) 13 return 14 } 15 16 for { 17 conn, err := listen.Accept()//等待客户端连接 18 if err != nil { 19 fmt.Println("accept failed, err:", err) 20 continue 21 } 22 go process(conn) 23 } 24 25} 26 27func process(conn net.Conn) { 28 defer conn.Close() 29 for { 30 buf := make([]byte, 512) 31 _, err := conn.Read(buf)//读取客户端传输过来的数据 32 if err != nil { 33 fmt.Println("read err:", err) 34 return 35 } 36 fmt.Println("read: ", string(buf)) 37 } 38}

View Code

4.客户端代码

1package main 2 3import ( 4 "bufio" 5 "fmt" 6 "net" 7 "os" 8 "strings" 9) 10 11func main() { 12 conn, err := net.Dial("tcp", "localhost:50000") //建立链接 13 if err != nil { 14 fmt.Println("Error dialing", err.Error()) 15 return 16 } 17 18 defer conn.Close() 19 inputReader := bufio.NewReader(os.Stdin) //从终端读取数据 20 for { 21 input, _ := inputReader.ReadString('\n') //从终端读取一行数据 22 trimmedInput := strings.Trim(input, "\r\n")//去掉字符串\r\n 23 if trimmedInput == "Q" { 24 return 25 } 26 27 _, err = conn.Write([]byte(trimmedInput))//将信息发给服务端 28 if err != nil { 29 return 30 } 31 } 32}

View Code

5.发送http请求

1package main 2 3import ( 4 "fmt" 5 "io" "net" ) func main() { conn, err := net.Dial("tcp", "www.baidu.com:80") if err != nil { fmt.Println("Error dialing", err.Error()) return } defer conn.Close() msg := "GET / HTTP/1.1\r\n" msg += "Host: www.baidu.com\r\n" msg += "Connection: close\r\n" msg += "\r\n\r\n" _, err = io.WriteString(conn, msg) if err != nil { fmt.Println("write string failed, ", err) return } buf := make([]byte, 4096) for { count, err := conn.Read(buf) if err != nil { break } fmt.Println(string(buf[0:count])) } }

View Code

redis

redis是个开源的高性能的key-value的内存数据库,可以把它当成远程的数据结构。
支持的value类型 非常多, 比如string、list(链表)、set(集合)、hash表等等
redis性能非常高,单机能够达到15w qps,通常适合做缓存。

1PV=page view 是指页面被浏览的次数,比如你打开一网页,那么这个网站的pv就算加了一次; 2TPS=transactions per second 是每秒内的事务数 3QPS=queries per second 是指每秒内查询次数,比如执行了select操作,相应的qps会增加。RPS=requests per second 是指每秒请求数

1、redis使用

1安装使用第三方开源的redis库: github.com/garyburd/redigo/redis 2go get github.com/garyburd/redigo/redis 3import( 4 “github.com/garyburd/redigo/redis" 5)

2、连接redis

1package main 2 3import ( 4 "fmt" 5 "github.com/garyburd/redigo/redis" 6) 7 8 9func main() { 10 c, err := redis.Dial("tcp", "localhost:6379") //连接redis if err != nil { 11 fmt.Println("conn redis failed,", err) 12 return 13 } 14 defer c.Close() 15}

3、Set 接 口

1package main 2 3import ( 4 "fmt" 5 "github.com/garyburd/redigo/redis" 6) 7 8func main() { 9 c, err := redis.Dial("tcp", "localhost:6379") 10 if err != nil { 11 fmt.Println("conn redis failed,", err) 12 return 13 } 14 defer c.Close() 15 _, err = c.Do("Set", "abc", 100) //设置值 16 if err != nil { 17 fmt.Println(err) 18 return 19 } 20 21 r, err := redis.Int(c.Do("Get", "abc")) //获取设置的值 22 if err != nil { 23 fmt.Println("get abc failed,", err) 24 return 25 } 26 fmt.Println(r) 27}

View Code

4、Hash表

1package main 2 3import ( 4 "fmt" 5 "github.com/garyburd/redigo/redis" 6) 7 8func main() { 9 c, err := redis.Dial("tcp", "localhost:6379") 10 if err != nil { 11 fmt.Println("conn redis failed,", err) 12 return 13 } 14 defer c.Close() 15 _, err = c.Do("HSet", "books", "abc", 100) //设置hash表的名字books 16 if err != nil { 17 fmt.Println(err) 18 return 19 } 20 21 r, err := redis.Int(c.Do("HGet", "books", "abc")) //因为读取出来是字符串,所以redis.Int转换成整数 22 if err != nil { 23 fmt.Println("get abc failed,", err) 24 return 25 } 26 fmt.Println(r) 27}

View Code

5、批量Set

1package main 2 3import ( 4 "fmt" 5 "github.com/garyburd/redigo/redis" 6) 7 8func main() { 9 c, err := redis.Dial("tcp", "localhost:6379") 10 if err != nil { 11 fmt.Println("conn redis failed,", err) 12 return 13 } 14 15 defer c.Close() 16 _, err = c.Do("MSet", "abc", 100, "efg", 300) //批量设置 17 if err != nil { 18 fmt.Println(err) 19 return 20 } 21 22 r, err := redis.Ints(c.Do("MGet", "abc", "efg")) //读取出来是一个切片 23 if err != nil { 24 fmt.Println("get abc failed,", err) 25 return 26 } 27 for _, v := range r { 28 fmt.Println(v) 29 } 30}

View Code

6、过期时间

1package main 2 3import ( 4 "fmt" 5 "github.com/garyburd/redigo/redis" 6) 7 8func main() { 9 c, err := redis.Dial("tcp", "localhost:6379") 10 if err != nil { 11 fmt.Println("conn redis failed,", err) 12 return 13 } 14 15 defer c.Close() 16 _, err = c.Do("expire", "abc", 10) 17 //设置过期时间,abc为key值,10为超时时间,插入的时候不能设置超时时间,因为插入和设置超时时间是两个不同的接口 18 if err != nil { 19 fmt.Println(err) 20 return 21 } 22}

View Code

7、队列操作

1package main 2 3import ( 4 "fmt" 5 "github.com/garyburd/redigo/redis" 6) 7 8func main() { 9 10 c, err := redis.Dial("tcp", "localhost:6379") 11 if err != nil { 12 fmt.Println("conn redis failed,", err) 13 return 14 } 15 defer c.Close() 16 _, err = c.Do("lpush", "book_list", "abc", "ceg", 300) //book_list队列的名字 17 if err != nil { 18 fmt.Println(err) 19 return 20 } 21 r, err := redis.String(c.Do("lpop", "book_list")) //从队列里面取值 22 if err != nil { 23 fmt.Println("get abc failed,", err) 24 return 25 } 26 fmt.Println(r) 27}

View Code

8、连接池

1type Pool struct { 2 //Dial 是创建链接的方法 3 Dial func() (Conn, error) 4 5 //TestOnBorrow 是一个测试链接可用性的方法 6 TestOnBorrow func(c Conn, t time.Time) error 7 8 // 最大的空闲连接数,表示即使没有redis连接时依然可以保持N个空闲的连接,而不被清除,随时处于待命状态 9 MaxIdle int 10 11 // 最大的激活连接数,表示同时最多有N个连接 ,为0事表示没有限制 12 MaxActive int 13 14 //最大的空闲连接等待时间,超过此时间后,空闲连接将被关闭 15 IdleTimeout time.Duration 16 17 // 当链接数达到最大后是否阻塞,如果不的话,达到最大后返回错误 18 Wait bool 19 20}

1package main 2 3import ( 4 "encoding/json" 5 "flag" 6 "fmt" 7 "time" 8 9 "github.com/garyburd/redigo/redis" 10) 11 12//声明一些全局变量 13var ( 14 pool *redis.Pool 15 redisServer = flag.String("redisServer", ":6379", "") 16 //flag对命令参数进行解析是常见的需求 17 //go run main.go -redisServer "8000",启动程序是给redisServer赋值,第3个参数是使用说明 18 //如果执行程序不带有-fredisServer 那么flag.Sring()的第2个参数则为默认值 19 redisPassword = flag.String("redisPassword", "123456", "") 20) 21 22//初始化一个连接池pool 23func newPool(server, password string) *redis.Pool { 24 return &redis.Pool{ 25 MaxIdle: 64, //空闲连接数 26 MaxActive: 1000, //活跃连接数 27 IdleTimeout: 240 * time.Second, //240s超时时间,连接池没有使用,会关闭 28 Dial: func() (redis.Conn, error) { 29 c, err := redis.Dial("tcp", server) 30 if err != nil { 31 return nil, err 32 } 33 /* 34 //密码权限验证 35 if _, err := c.Do("AUTH", password); err != nil { 36 c.Close() 37 return nil, err 38 }*/ 39 return c, err 40 }, 41 //从连接池获取一个链接,测试连接是否可用 42 TestOnBorrow: func(c redis.Conn, t time.Time) error { 43 if time.Since(t) < time.Minute { 44 return nil 45 } 46 _, err := c.Do("PING") 47 return err 48 }, 49 } 50} 51 52type Student struct { 53 Id int `json:"id"` 54 Name string `json:"name"` 55 Age int `json:"age"` 56 Score float32 `json:"score"` 57} 58 59func main() { 60 flag.Parse() 61 pool = newPool(*redisServer, *redisPassword) 62 63 conn := pool.Get() 64 defer conn.Close() 65 66 var stu Student = Student{ 67 Id: 1000, 68 Name: "abc", 69 Age: 89, 70 Score: 99.2, 71 } 72 73 data, _ := json.Marshal(stu) 74 //redis操作结构体,需要转成json格式 75 v, err := conn.Do("SET", 1000, string(data)) 76 if err != nil { 77 fmt.Println(err) 78 return 79 } 80 fmt.Println(v) 81 ret, err := redis.String(conn.Do("GET", 1000)) 82 if err != nil { 83 fmt.Println(err) 84 return 85 } 86 87 var stu01 Student 88 json.Unmarshal([]byte(ret), &stu01) 89 fmt.Printf("stu01:%#v\n", stu01) 90 91}

View Code

socket练习:

client/main.go

1package main 2 3import ( 4 "bufio" 5 "encoding/json" 6 "fmt" 7 "net" 8 "os" 9 "github.com/sherlockhua/goproject/day9/proto" 10) 11 12var recvMsg chan interface{} 13 14func main() { 15 conn, err := net.Dial("tcp", "192.168.14.200:18080") 16 if err != nil { 17 fmt.Printf("dial server failed, err:%v\n", err) 18 return 19 } 20 21 fmt.Fprintf 22 recvMsg = make(chan interface{}, 1000) 23 defer conn.Close() 24 go read(conn) 25 26 err = login(conn) 27 if err != nil { 28 fmt.Printf("login failed, err:%v\n", err) 29 return 30 } 31 32 msg := <-recvMsg 33 loginResp, ok := msg.(*proto.LoginResponse) 34 if !ok { 35 fmt.Printf("unexpect msg:%T, %+v\n", msg, msg) 36 return 37 } 38 39 if loginResp.Errno != 0 { 40 fmt.Printf("login failed, err:%v\n", loginResp.Message) 41 return 42 } 43 44 fmt.Printf("login succ\n") 45 for { 46 var data string 47 reader := bufio.NewReader(os.Stdin) //在shell输入 48 data, err := reader.ReadString('\n') //从shell读取一行数据 49 if err != nil { 50 continue 51 } 52 53 err = sendMessage(conn, data) //开始发消息 54 if err != nil { 55 fmt.Printf("send message failed, err:%v\n", err) 56 return 57 } 58 } 59} 60 61func sendMessage(conn net.Conn, data string) (err error) { 62 var message proto.MessageRequest 63 message.Message = data 64 message.Username, _ = os.Hostname() //获取主机名 65 66 body, err := json.Marshal(message) 67 if err != nil { 68 fmt.Printf("marshal failed, err:%v\n", err) 69 return 70 } 71 72 err = proto.WritePacket(conn, proto.CmdSendMessageRequest, body) //将数据包发送给服务端 73 if err != nil { 74 fmt.Printf("send to server failed, err:%v\n", err) 75 return 76 } 77 return 78} 79 80func login(conn net.Conn) (err error) { 81 var loginReq proto.LoginRequest 82 loginReq.Password = "admin" 83 loginReq.Username = "admin" 84 85 body, err := json.Marshal(loginReq) 86 if err != nil { 87 fmt.Printf("marshal failed, err:%v\n", err) 88 return 89 } 90 91 err = proto.WritePacket(conn, proto.CmdLoginRequest, body) 92 if err != nil { 93 fmt.Printf("send to server failed, err:%v\n", err) 94 return 95 } 96 return 97} 98 99func read(conn net.Conn) { 100 for { 101 body, cmd, err := proto.ReadPacket(conn) 102 if err != nil { 103 fmt.Printf("read from server failed, err:%v\n", err) 104 return 105 } 106 107 switch cmd { 108 case proto.CmdLoginResponse: 109 err = processLoginResponse(conn, body) 110 case proto.CmdSendMessageResponse: 111 err = processSendMsgResponse(conn, body) 112 case proto.CmdBroadMessage: 113 err = processBroadMessage(conn, body) 114 default: 115 fmt.Printf("unsupport cmd[%v]\n", cmd) 116 return 117 } 118 } 119} 120 121func processLoginResponse(conn net.Conn, body []byte) (err error) { 122 //登录返回 123 var loginResponse proto.LoginResponse 124 err = json.Unmarshal(body, &loginResponse) 125 if err != nil { 126 fmt.Printf("unmarshal failed, err:%v\n", err) 127 return 128 } 129 130 recvMsg <- &loginResponse 131 return 132} 133 134func processSendMsgResponse(conn net.Conn, body []byte) (err error) { 135 var messageResp proto.MessageResponse 136 err = json.Unmarshal(body, &messageResp) 137 if err != nil { 138 fmt.Printf("unmarshal failed, err:%v\n", err) 139 return 140 } 141 142 if messageResp.Errno != 0 { 143 fmt.Printf("消息发送失败:%v\n", messageResp.Message) 144 return 145 } 146 return 147} 148 149func processBroadMessage(conn net.Conn, body []byte) (err error) { 150 151 var msg proto.BroadMessage 152 err = json.Unmarshal(body, &msg) 153 if err != nil { 154 fmt.Printf("unmarshal failed, err:%v\n", err) 155 return 156 } 157 158 fmt.Printf("%s:\n %s\n\n", msg.Username, msg.Message) 159 return 160}

main.go

server/

1package main 2 3import ( 4 "fmt" 5 "net" 6) 7 8var ( 9 clientMgr *ClientMgr 10) 11 12func startServer(addr string) (l net.Listener, err error) { 13 l, err = net.Listen("tcp", addr) //监听一个地址 14 if err != nil { 15 fmt.Printf("listen addr:%s failed, err:%v\n", addr, err) 16 return 17 } 18 19 return 20} 21 22func main() { 23 24 clientMgr = NewClientMgr(200) 25 fmt.Printf("start server...\n") 26 l, err := startServer("0.0.0.0:18080") 27 if err != nil { 28 fmt.Println("start server failed, err:", err) 29 return 30 } 31 32 err = runServer(l) 33 if err != nil { 34 fmt.Println("run server failed, err:", err) 35 return 36 } 37 38 fmt.Println("server is exied") 39}

main.go

1package main 2 3import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "net" 8 9 "github.com/sherlockhua/goproject/day9/proto" 10) 11 12func runServer(l net.Listener) (err error) { 13 fmt.Println("run server succ") 14 for { 15 conn, err := l.Accept() 16 if err != nil { 17 fmt.Println("accept failed, err:", err) 18 continue 19 } 20 21 clientMgr.newClientChan <- conn 22 go process(conn) 23 } 24} 25 26func process(conn net.Conn) { 27 28 defer func() { 29 clientMgr.closeChan <- conn 30 conn.Close() 31 }() 32 33 for { 34 body, cmd, err := proto.ReadPacket(conn) 35 if err != nil { 36 fmt.Printf("read from conn failed, err:%v\n", err) 37 return 38 } 39 40 err = processRequest(conn, body, cmd) 41 if err != nil { 42 fmt.Printf("processRequest[%v] failed, err:%v\n", cmd, err) 43 return 44 } 45 /* 46 var buf []byte = make([]byte, 512) 47 n, err := conn.Read(buf) 48 if err != nil { 49 fmt.Printf("read from conn failed, err:%v\n", err) 50 return 51 } 52 53 buf = buf[0:n] 54 clientMgr.addMsg(buf) 55 */ 56 } 57 58} 59 60func processRequest(conn net.Conn, body []byte, cmd int32) (err error) { 61 switch cmd { 62 case proto.CmdLoginRequest: 63 err = processLogin(conn, body) 64 case proto.CmdRegisterRequest: 65 err = processRegister(conn, body) 66 case proto.CmdSendMessageRequest: 67 err = processMessage(conn, body) 68 default: 69 fmt.Printf("unsupport cmd[%v]\n", cmd) 70 err = errors.New("unsupport cmd") 71 return 72 } 73 74 return 75} 76 77func processLogin(conn net.Conn, body []byte) (err error) { 78 79 fmt.Printf("begin process login request\n") 80 var loginRequest proto.LoginRequest 81 err = json.Unmarshal(body, &loginRequest) 82 if err != nil { 83 fmt.Printf("Unmarshal failed[%v]\n", err) 84 return 85 } 86 87 fmt.Printf(" process login request:%+v\n", loginRequest) 88 var loginResp proto.LoginResponse 89 loginResp.Errno = 100 90 loginResp.Message = "username or password not right" 91 92 if loginRequest.Username == "admin" && loginRequest.Password == "admin" { 93 loginResp.Errno = 0 94 loginResp.Message = "success" 95 } 96 97 data, err := json.Marshal(loginResp) 98 if err != nil { 99 fmt.Printf("Marshal failed[%v]\n", err) 100 return 101 } 102 103 fmt.Printf(" write login response %+v\n", loginResp) 104 return proto.WritePacket(conn, proto.CmdLoginResponse, data) //将登录响应信息传递给客户端 105} 106 107func processRegister(conn net.Conn, body []byte) (err error) { 108 return 109} 110 111//将消息广播出去 112func processMessage(conn net.Conn, body []byte) (err error) { 113 114 fmt.Printf("begin process login request\n") 115 var messageReq proto.MessageRequest 116 err = json.Unmarshal(body, &messageReq) 117 if err != nil { 118 fmt.Printf("Unmarshal failed[%v]\n", err) 119 return 120 } 121 122 var broadMessage proto.BroadMessage 123 broadMessage.Message = messageReq.Message 124 broadMessage.Username = messageReq.Username 125 126 body, err = json.Marshal(broadMessage) 127 if err != nil { 128 fmt.Printf("marshal failed, err:%v\n", err) 129 return 130 } 131 132 packet := &proto.Packet{ 133 Cmd: proto.CmdBroadMessage, 134 Body: body, 135 } 136 137 clientMgr.addMsg(packet) 138 return 139}

server.go

1package main 2 3import ( 4 "errors" 5 "fmt" 6 "net" 7 "sync" 8 "time" 9 10 "github.com/sherlockhua/goproject/day9/proto" 11) 12 13type ClientMgr struct { 14 //clientsMap维护所有客户端连接 15 clientsMap map[net.Conn]int 16 maxClientNums int 17 //msgChan用来保存客户端发送过来的消息 18 msgChan chan *proto.Packet 19 newClientChan chan net.Conn 20 closeChan chan net.Conn 21 lock sync.RWMutex //读写锁 22} 23 24func NewClientMgr(maxClients int) *ClientMgr { 25 mgr := &ClientMgr{ 26 clientsMap: make(map[net.Conn]int, 1024), //连接的客户端的map 27 maxClientNums: maxClients, //最大连接客户端数 28 msgChan: make(chan *proto.Packet, 1000), //消息管道 29 newClientChan: make(chan net.Conn, 1000), //新连接的客户端 30 closeChan: make(chan net.Conn, 1000), //关闭客户端连接 31 } 32 33 go mgr.run() //遍历所有客户端发送过来的消息,并广播到所有的其他客户端 34 go mgr.procConn() 35 return mgr 36} 37 38//监测新连接的客户端管道和需要关闭的客户端管道 39func (c *ClientMgr) procConn() { 40 for { 41 select { 42 case conn := <-c.newClientChan: //监测新连接的客户端的管道 43 c.lock.Lock() 44 c.clientsMap[conn] = 0 //将新连接的客户端写入处于连接的客户端的map 45 c.lock.Unlock() 46 case conn := <-c.closeChan: //监测需要关闭的客户端的管道 47 c.lock.Lock() 48 delete(c.clientsMap, conn) //从客户端连接的map中删除需要断开连接的客户端 49 c.lock.Unlock() 50 } 51 } 52} 53 54//遍历所有客户端发送过来的消息,并广播到所有的其他客户端 55func (c *ClientMgr) run() { 56 for msg := range c.msgChan { //遍历消息管道 57 c.transfer(msg) //广播消息 58 } 59} 60 61//广播消息,将消息发送给当前在线的客户端 62func (c *ClientMgr) transfer(msg *proto.Packet) { 63 64 c.lock.RLock() 65 defer c.lock.RUnlock() 66 for client, _ := range c.clientsMap { 67 err := c.sendToClient(client, msg) //将消息发送给当前在线的客户端 68 if err != nil { 69 continue 70 } 71 } 72 73} 74 75//发送消息给指定客户端 76func (c *ClientMgr) sendToClient(client net.Conn, msg *proto.Packet) (err error) { 77 return proto.WritePacket(client, msg.Cmd, msg.Body) 78 /* 79 var n int 80 var sendBytes int 81 msgLen := len(msg) 82 for { 83 n, err = client.Write(msg) 84 if err != nil { 85 fmt.Printf("send to client:%v failed, err:%v\n", client, err) 86 client.Close() 87 delete(c.clientsMap, client) 88 return 89 } 90 sendBytes += n 91 if sendBytes >= msgLen { 92 break 93 } 94 msg = msg[sendBytes:] 95 } 96 return 97 */ 98} 99 100//将消息广播出去 101func (c *ClientMgr) addMsg(msg *proto.Packet) (err error) { 102 103 ticker := time.NewTicker(time.Millisecond * 10) //设置一个超时时间 104 defer ticker.Stop() 105 106 select { 107 case c.msgChan <- msg: 108 fmt.Printf("send to chan succ\n") 109 case <-ticker.C: 110 fmt.Printf("add msg timeout\n") 111 err = errors.New("add msg timeout") 112 } 113 return 114}

conn_mgr.go

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )