网络编程

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的更多相关文章

  1. [golang note] 网络编程 - RPC编程

    net包 • 官方文档 http://godoc.golangtc.com/pkg/net/ Package net provides a portable interface for network ...

  2. golang 网络编程之如何正确关闭tcp连接以及管理它的生命周期

    欢迎访问我的个人网站获取更佳阅读排版 golang 网络编程之如何正确关闭tcp连接以及管理它的生命周期 | yoko blog (https://pengrl.com/p/47401/) 本篇文章部 ...

  3. 脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?

    1.引言 本文接上篇<脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手>,继续脑残式的网络编程知识学习 ^_^. 套接字socket是大多数程序员都非常熟悉的概念,它是计算机 ...

  4. TCP网络编程杂谈

    作为一名IT工程师,网络通信编程相信都会接触到,比如Web开发的HTTP库,Java中的Netty,或者C/C++中的Libevent,Libev等第三方通信库,甚至是直接使用Socket API,但 ...

  5. [转帖]脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?

    脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?     http://www.52im.net/thread-1732-1-1.html   1.引言 本文接上篇<脑残式网 ...

  6. 【游戏开发】网络编程之浅谈TCP粘包、拆包问题及其解决方案

    引子 现如今手游开发中网络编程是必不可少的重要一环,如果使用的是TCP协议的话,那么不可避免的就会遇见TCP粘包和拆包的问题,马三觉得haifeiWu博主的 TCP 粘包问题浅析及其解决方案 这篇博客 ...

  7. 猫哥网络编程系列:详解 BAT 面试题

    从产品上线前的接口开发和调试,到上线后的 bug 定位.性能优化,网络编程知识贯穿着一个互联网产品的整个生命周期.不论你是前后端的开发岗位,还是 SQA.运维等其他技术岗位,掌握网络编程知识均是岗位的 ...

  8. 基于ASIO的协程与网络编程

    协程 协程,即协作式程序,其思想是,一系列互相依赖的协程间依次使用CPU,每次只有一个协程工作,而其他协程处于休眠状态.协程可以在运行期间的某个点上暂停执行,并在恢复运行时从暂停的点上继续执行. 协程 ...

  9. Netty与网络编程

    Netty什么? Netty项目是一个提供异步事件驱动网络应用框架和快速开发可维护的高性能高扩展性服务端和客户端协议工具集的成果.换句话说,Netty是一个NIO客户端服务端框架,它使得快速而简单的开 ...

随机推荐

  1. mysql中的utf8mb4、utf8mb4_unicode_ci、utf8mb4_general_ci的关系

    mysql中的utf8mb4.utf8mb4_unicode_ci.utf8mb4_general_ci的关系 一.总结 一句话总结: utf8mb4是utf8的超集并完全兼容utf8,能够用四个字节 ...

  2. ccf 2017-9-1 打酱油(dfs)

    ccf 2017-9-1 打酱油(dfs) 问题描述 小明带着N元钱去买酱油.酱油10块钱一瓶,商家进行促销,每买3瓶送1瓶,或者每买5瓶送2瓶.请问小明最多可以得到多少瓶酱油. 输入格式 输入的第一 ...

  3. 如何将ubuntu16.04升级到ubuntu 18.04?

    答:步骤如下: 1. sudo apt update (更新软件源) 2. sudo apt upgrade (更新内核相关的包) 3. sudo apt dist-upgrade 4.  sudo ...

  4. springBoot2.X---过滤器,监听器,拦截器

    过滤器,监听器,拦截器 一.画图理解 过滤器(filter),监听器(listener),拦截器(Interceptor). 通过两幅图我们可以理解拦截器和过滤器的特点 1.过滤器 过滤器是在请求进入 ...

  5. LC 740. Delete and Earn

    Given an array nums of integers, you can perform operations on the array. In each operation, you pic ...

  6. NetUtils网络连接工具类

    import android.app.Activity; import android.content.ComponentName; import android.content.Context; i ...

  7. CentOS7安装后无法使用鼠标选中

    运行命令:yum install gpm*  安装gpm 启动gpm服务:service gpm start 运行systemctl enable gpm.servicere 添加到后台服务. 备注: ...

  8. Linux 查看 MySQL的版本信息

    Linux 查看 MySQL的版本信息 如何查看某台 Linux 主机上的 安装的 MySQL版本信息? 使用如下命令,查看 MySQL的版本信息: mysql -V 或者 mysql --versi ...

  9. CentOS7.5下,MySQL安装配置指南

    [root@host---- home]# grep 'temporary password' /var/log/mysqld.log --20T02::.457613Z [Note] A tempo ...

  10. IO模型,非阻塞IO模型,select实现多路复用

    1. IO阻塞模型 IO问题: 输入输出 我要一个用户名用来执行登陆操作,问题用户名需要用户输入,输入需要耗时, 如果输入没有完成,后续逻辑无法继续,所以默认的处理方式就是 等 将当前进程阻塞住,切换 ...