golang(9):网络编程 & redis
网络编程
TCP/IP 协议:
. TCP(传输控制协议) -- 应用程序之间通信
. UDP(用户数据包协议)-- 应用程序之间的简单通信
. IP(网际协议) -- 计算机之间的通信
. DHCP(动态主机配置协议) -- 针对动态寻址
TCP 编程
go服务端的处理流程:
a. 监听端口
b. 接收客户端的连接
c. 创建 goroutine,处理该连接
示例代码:
package main import (
"fmt"
"net" // 网络相关的包都在这个 net 包里面
) func main(){
fmt.Println("start server...") // 1. 监听ip和端口
listen,err := net.Listen("tcp","0.0.0.0:50000") // 监听端口;第一个参数是监听什么类型的协议,第二个参数是监听的 端口, 0.0.0.0 表示监听这台机器上的所有 ip (监听所有的网卡)
if err != nil {
fmt.Println("listen failed,err:",err)
return
} // 2. 接收连接
for {
conn,err := listen.Accept() // 接收连接;conn 表示与当前用户之间的通信的管道(连接)
if err != nil {
fmt.Println("accept failed,err:",err)
continue
} // 3. 创建 goroutine 去处理该连接
go process(conn) // 新起一个 goroutine 去处理这个连接
}
} func process(conn net.Conn){ // net.Conn 类型
defer conn.Close() // 执行完后要把连接关掉,要不然会造成资源泄露
for {
buf := make([]byte,) // 网络连接发过来的是字节流,所以定义一个 byte 切片
_ , err := conn.Read(buf) // conn.Read()接收的是一个 byte切片; 从 conn 这个对象里面 读取客户端发来的数,保存到 buf数组 中; conn.Read() 返回两个参数:第一个参数是读取到了多少个字节,第二个是 error
if err != nil {
fmt.Println("read err:",err)
return
}
fmt.Print("read:",string(buf)) // 把 byte切片 转换为 字符串
}
}
go客户端的处理流程:
a. 建立与服务端的连接
b. 进行数据接收
c. 关闭连接
示例代码:
// 示例代码:
package main import (
"bufio"
"fmt"
"net"
"os"
"strings"
) func main(){
// 1. 建立连接
conn,err := net.Dial("tcp","127.0.0.1:50000") // 建立连接;net.Dial() 参数:第一个是指定协议类型,第二个 ip 和 端口
if err != nil {
fmt.Println("dial err:",err)
return
} // 3. 关闭连接
defer conn.Close() // 2. 接收数据
inputReader := bufio.NewReader(os.Stdin)
// 从终端读取用户输入
for {
input, _ := inputReader.ReadString('\n')
trimmedInput := strings.Trim(input,"\r\n") // 去掉 \r\n
if trimmedInput == "Q"{ // 退出
return
} _, err := conn.Write([]byte(trimmedInput)) // 把读取到的用户输入的内容写入到 conn 进行传输;传输是 字节流 byte
if err != nil {
return
}
} }
发送HTTP请求
. HTTP协议是基于TCP协议之上的文本协议
. 每行文本使用 \r\n 结尾,当连续两个 \r\n 时,表示整个数据包结束
示例代码:
package main import (
"fmt"
//"io"
"net"
) func main(){
conn,err := net.Dial("tcp","www.baidu.com:80")
if err != nil{
fmt.Println("Error dialing:",err)
} defer conn.Close()
msg := "GET / HTTP/1.1\r\n" // HTTP版本号
msg += "HOST: www.baidu.com\r\n"
msg += "Connection: close\r\n" // 该行表示是 短连接
msg += "\r\n\r\n" // 结束 // _,err = io.WriteString(conn,msg) // 把msg写入到 conn中并发送(给百度发送GET请求)
_, err = conn.Write([]byte(msg)) // 这两种发送方式都可以
if err != nil {
fmt.Println("write string failed,",err)
return
} buf := make([]byte,)
for {
n,err := conn.Read(buf) // 读取从百度返回的数据(html代码),给buf
if err != nil {
fmt.Println("err:",err)
break
}
fmt.Println(string(buf[:n])) // 不明白为啥一定 buf 要加上 [:n] ,要不然打印出来的数据(html代码)不完整 。。。(Aug 12 2019)
}
}
UDP协议:
. 用户数据报协议
. 无连接,直接进行数据发送
. 不可靠、没有时序
. 实时性比较好,通常用于视频、直播相关领域
redis
redis是个开源的高性能的key-value的内存数据库,可以把它当成远程的数据结构。
支持的value类型非常多,比如string、list(链表)、set(集合)、hash表等等
redis性能非常高,单机能够达到15w qps,通常适合做缓存。
go中redis 的使用
使用第三方开源的redis库: github.com/garyburd/redigo/redis import(
"github.com/garyburd/redigo/redis"
)
安装 redis 包
利用 go get 命令,如下:
go get github.com/garyburd/redigo/redis
1. 连接redis
// 示例代码:
package main import (
"fmt"
"github.com/garyburd/redigo/redis"
) func main(){
redisConn,err := redis.Dial("tcp","localhost:6379") // 连接redis
if err != nil{
fmt.Println("connect redis failed,err:",err)
return
}
defer redisConn.Close() // 关闭redis连接
}
2. 字符串类型 : Set 和 Get 接口
// 示例代码:
package main import (
"fmt"
"github.com/garyburd/redigo/redis"
) func main(){
redisConn,err := redis.Dial("tcp","localhost:6379")
if err != nil{
fmt.Println("connect redis failed,err:",err)
return
}
defer redisConn.Close() // 往 redis 中写入字符串型数据
_,err = redisConn.Do("Set","abc",) // 在 redis中存入字符串
if err != nil{
fmt.Println("set failed,err:",err)
return
} // 从 redis 中读取数据
read,err := redis.Int(redisConn.Do("Get","abc")) // redisConn.Do("Get",key) ---> 从redis 中读取数据;redis.Int() --> 把读取出来的数据转化为 int 类型
if err != nil {
fmt.Println("read from redis failed, err:",err)
return
} fmt.Printf("read:%v\n",read)
} // 运行结果:
[root@NEO example02_redis_set_get]# go run main/main.go
read:
[root@NEO example02_redis_set_get]#
2.2 批量 set
package main import (
"fmt"
"github.com/garyburd/redigo/redis"
) func main(){
redisConn,err := redis.Dial("tcp","localhost:6379")
if err != nil {
fmt.Println("connect redis failed,err:",err)
return
}
defer redisConn.Close() _,err = redisConn.Do(
"MSet",
"name","neo",
"age","") // 这个小括号不能写到下一行,要不然语法报错
if err != nil {
fmt.Println("MSet failed,err:",err)
return
} read,err := redis.Strings(redisConn.Do("MGet","name","age")) // "MGet" 返回的是 type []interface {}
if err != nil {
fmt.Println("MGet failed,err:",err)
return
}
fmt.Printf("MGet read:%v\n",read) for k,v := range read{
fmt.Printf("read[%d]=%v\n",k,v)
}
} // 运行结果:
[root@NEO example02_redis_hash_mset]# go run main/main.go
MGet read:[neo ]
read[]=neo
read[]=
[root@NEO example02_redis_hash_mset]#
3. 散列类型hash
package main import (
"fmt"
"github.com/garyburd/redigo/redis"
) func main(){
redisConn,err := redis.Dial("tcp","localhost:6379")
if err != nil {
fmt.Println("connect redis failed,err:",err)
return
} defer redisConn.Close() _,err = redisConn.Do("HSet","book","price",) // 在 redis 中存储 hash类型的值
if err != nil {
fmt.Println("set hash failed,err:",err)
return
} read,err := redis.Int(redisConn.Do("HGet","book","price")) // 从 redis 中获取 hash 类型的值
if err != nil{
fmt.Println("read redis hash failed,err:",err)
return
}
fmt.Printf("readMap:%v\n",read)
} // 运行结果:
[root@NEO example02_redis_hash]# go run main/main.go
read:
[root@NEO example02_redis_hash]#
4. list 列表操作
// 示例代码:
package main import (
"fmt"
"github.com/garyburd/redigo/redis"
) func main(){
redisConn,err := redis.Dial("tcp","localhost:6379")
if err != nil {
fmt.Println("dial redis failed,err:",err)
return
}
defer redisConn.Close() _,err = redisConn.Do("lpush","book_list","abc","d","ef") // 列表操作 : lpush; key --> book_list;
if err != nil{
fmt.Println("lpush failed,err:",err)
return
} read,err := redis.String(redisConn.Do("lpop","book_list")) // 列表操作: lpop
if err != nil{
fmt.Println("lpop failed,err:",err)
return
} fmt.Println("read:",read)
} // 运行结果:
[root@NEO example02_redis_list_lpush]# go run main/main.go
read: ef
[root@NEO example02_redis_list_lpush]#
5. 设置过期时间
package main import (
"fmt"
"github.com/garyburd/redigo/redis"
) func main(){
redisConn,err := redis.Dial("tcp","localhost:6379")
if err != nil {
fmt.Println("dial failed,err:",err)
return
}
defer redisConn.Close() _,err = redisConn.Do("expire","name",) // 设置过期时间
if err != nil {
fmt.Println("set expire failed,err:",err)
return
} }
golang(9):网络编程 & redis的更多相关文章
- [golang note] 网络编程 - RPC编程
net包 • 官方文档 http://godoc.golangtc.com/pkg/net/ Package net provides a portable interface for network ...
- golang 网络编程之如何正确关闭tcp连接以及管理它的生命周期
欢迎访问我的个人网站获取更佳阅读排版 golang 网络编程之如何正确关闭tcp连接以及管理它的生命周期 | yoko blog (https://pengrl.com/p/47401/) 本篇文章部 ...
- 脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?
1.引言 本文接上篇<脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手>,继续脑残式的网络编程知识学习 ^_^. 套接字socket是大多数程序员都非常熟悉的概念,它是计算机 ...
- TCP网络编程杂谈
作为一名IT工程师,网络通信编程相信都会接触到,比如Web开发的HTTP库,Java中的Netty,或者C/C++中的Libevent,Libev等第三方通信库,甚至是直接使用Socket API,但 ...
- [转帖]脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?
脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么? http://www.52im.net/thread-1732-1-1.html 1.引言 本文接上篇<脑残式网 ...
- 【游戏开发】网络编程之浅谈TCP粘包、拆包问题及其解决方案
引子 现如今手游开发中网络编程是必不可少的重要一环,如果使用的是TCP协议的话,那么不可避免的就会遇见TCP粘包和拆包的问题,马三觉得haifeiWu博主的 TCP 粘包问题浅析及其解决方案 这篇博客 ...
- 猫哥网络编程系列:详解 BAT 面试题
从产品上线前的接口开发和调试,到上线后的 bug 定位.性能优化,网络编程知识贯穿着一个互联网产品的整个生命周期.不论你是前后端的开发岗位,还是 SQA.运维等其他技术岗位,掌握网络编程知识均是岗位的 ...
- 基于ASIO的协程与网络编程
协程 协程,即协作式程序,其思想是,一系列互相依赖的协程间依次使用CPU,每次只有一个协程工作,而其他协程处于休眠状态.协程可以在运行期间的某个点上暂停执行,并在恢复运行时从暂停的点上继续执行. 协程 ...
- Netty与网络编程
Netty什么? Netty项目是一个提供异步事件驱动网络应用框架和快速开发可维护的高性能高扩展性服务端和客户端协议工具集的成果.换句话说,Netty是一个NIO客户端服务端框架,它使得快速而简单的开 ...
随机推荐
- svg简单的应用
1.可以直接在html内写svg (1)width宽度,height高度 (2)xmlns svg的规则 <svg xmlns="http://www.w3.org/2000/svg& ...
- 性能分析 | Linux 内存占用分析
这篇博客主要介绍 linux 环境下,查看内存占用的两种方式:使用 ps,top等命令:查看/proc/[pid]/下的文件.文章简要介绍了命令的使用方法与一些参数意义,同时对/proc/[pid]/ ...
- C#Application:Exit与ExitThread 解释
Application.Exit(); 方法停止在所有线程上运行的所有消息循环,并关闭应用程序的所有窗口 Application.ExitThread 方法 退出当前线程上的消息循环,并关闭该线程上的 ...
- 小D课堂 - 新版本微服务springcloud+Docker教程_6-05 高级篇幅之高并发情况下
笔记 5.高级篇幅之高并发情况下接口限流特技 简介:谷歌guava框架介绍,网关限流使用 1.nginx层限流 2.网关层限流 开始 mysql最大的连接数就是3千多.如果想把应用搞好 ...
- java安装配置
1.下载 https://www.oracle.com/technetwork/java/javase/downloads/index.html 2.配置环境变量 点击"新建" 变 ...
- DS1302时钟基础使用(含代码)
了解其管脚 X1 X2 32.768KHz 晶振管脚 GND 地 RST 复位脚 I/O 数据输入/输出引脚,具有三态 SCLK 串行时钟 Vcc1,Vcc2(备用电源供电) 电源供电管脚 DS130 ...
- 异步模型 requestAnimationFrame
异步模型 requestAnimationFrame 前言 window.requestAnimationFrame() 告诉浏览器--你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函 ...
- nRF5 SDK Bootloader and DFU moudles(1)
在嵌入式操作系统中,BootLoader是在操作系统内核运行之前运行.可以初始化硬件设备.建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境. 在嵌 ...
- day37 GIL、同步、异步、进程池、线程池、回调函数
1.GIL 定义: GIL:全局解释器锁(Global Interpreter Lock) 全局解释器锁是一种互斥锁,其锁住的代码是全局解释器中的代码 为什么需要全局解释器锁 在我们进行代码编写时,实 ...
- ZOJ Problem Set - 1005
注意,条件:B>=C .应考虑B=C的情况. #include<iostream> using namespace std; int A,B,C; void jugs(int a,i ...