基于Go的socket代码实现
4.1、 聊天案例
服务端:
package main
import (
"fmt"
"net"
"strings"
)
func main() {
// 1.创建TCP服务端监听
listenner, err := net.Listen("tcp", "0.0.0.0:8888")
if err != nil {
fmt.Println(err)
return
}
defer listenner.Close()
// 2.服务端不断等待请求处理
for {
// 阻塞等待客户端连接
conn, err := listenner.Accept()
if err != nil {
fmt.Println(err)
continue
}
go ClientConn(conn)
}
}
// 处理服务端逻辑
func ClientConn(conn net.Conn) {
defer conn.Close()
// 获取客户端地址
ipAddr := conn.RemoteAddr().String()
fmt.Println(ipAddr, "连接成功")
// 缓冲区
buf := make([]byte, 1024)
for {
// n是读取的长度
// time.Sleep(time.Second*10) // 粘包
n, err := conn.Read(buf)
if err != nil {
fmt.Println(err)
return
}
// 切出有效数据
result := buf[:n]
fmt.Printf("接收到数据,来自[%s] [%d]:%s\n", ipAddr, n, string(result))
// 接收到exit,退出连接
if string(result) == "exit" {
fmt.Println(ipAddr, "退出连接")
return
}
// 回复客户端
conn.Write([]byte(strings.ToUpper(string(result))))
}
}
聊天案例客户端:
package main
import (
"fmt"
"net"
)
func main() {
// 1.连接服务端
conn, err := net.Dial("tcp", "127.0.0.1:8888")
if err != nil {
fmt.Println(err)
return
}
defer conn.Close()
// 缓冲区
for {
buf := make([]byte, 1024)
fmt.Printf("请输入发送的内容:")
fmt.Scan(&buf)
fmt.Printf("发送的内容:%s\n", string(buf))
// 发送数据
conn.Write(buf)
//conn.Write(buf) // 粘包
//conn.Write(buf) // 粘包
// 接收服务端返回信息
res := make([]byte, 1024)
n, err := conn.Read(res)
if err != nil {
fmt.Println(err)
return
}
result := res[:n]
fmt.Printf("接收到数据:%s\n", string(result))
}
}
4.2、 ssh案例
服务端:
package main
import (
"fmt"
"github.com/axgle/mahonia"
"net"
"os/exec"
)
func main() {
// 1.创建TCP服务端监听
listenner, err := net.Listen("tcp", "0.0.0.0:8888")
if err != nil {
fmt.Println(err)
return
}
defer listenner.Close()
for true {
// 阻塞等待客户端连接
conn, err := listenner.Accept()
if err != nil {
fmt.Println(err)
return
}
go ClientConn(conn)
}
}
// 处理服务端逻辑
func ClientConn(conn net.Conn) {
defer conn.Close()
// 获取客户端地址
ipAddr := conn.RemoteAddr().String()
fmt.Println(ipAddr, "连接成功")
for true {
// 缓冲区
data := make([]byte, 1024)
// n是读取的长度
n, err := conn.Read(data)
fmt.Println("命令字节数",n)
if err != nil {
fmt.Println(err)
return
}
// 切出有效数据
data = data[:n]
fmt.Printf("接收到命令,来自[%s] [%d]:%s\n", ipAddr, n, string(data))
// 接收到exit,退出连接
if string(data) == "exit" {
fmt.Println(ipAddr, "退出连接")
return
}
// 回复客户端
cmd := exec.Command("cmd","/C",string(data))
// 执行命令,并返回结果
output,err := cmd.Output()
if err != nil {
panic(err)
}
fmt.Println("命令结果字节数:",len(output))
dec := mahonia.NewDecoder("gbk")
_, cdata, _ := dec.Translate(output, true)
result := string(cdata)
fmt.Println(result)
conn.Write([]byte(string(result)))
}
}
客户端:
package main
import (
"bufio"
"fmt"
"net"
"os"
"strings"
)
func main() {
// 1.连接服务端
conn, err := net.Dial("tcp", "127.0.0.1:8888")
if err != nil {
fmt.Println(err)
return
}
defer conn.Close()
// 缓冲区
for true {
reader := bufio.NewReader(os.Stdin) // 从标准输入生成读对象
fmt.Println("输入执行命令>>>")
text, _ := reader.ReadString('\n') // 读到换行
text = strings.TrimSpace(text)
fmt.Println("text",text)
// 发送数据
conn.Write([]byte(text))
// 接收服务端返回信息
res := make([]byte, 100000) // 如何解决大文件传输问题呢?看下面的文件上传案例
n, err := conn.Read(res)
if err != nil {
fmt.Println("err:",err)
return
}
fmt.Println("n",n)
result := res[:n]
fmt.Printf("接收到数据:%s\n", string(result))
}
}
4.3、上传文件案例
服务端:
package main
import (
"bufio"
"fmt"
"net"
"os"
"strconv"
"strings"
)
func main() {
// 1.创建TCP服务端监听
listenner, err := net.Listen("tcp", "0.0.0.0:8888")
if err != nil {
fmt.Println(err)
return
}
defer listenner.Close()
for true {
// 阻塞等待客户端连接
conn, err := listenner.Accept()
if err != nil {
fmt.Println(err)
return
}
go ClientConn(conn)
}
}
// 处理服务端逻辑
func ClientConn(conn net.Conn) {
defer conn.Close()
// 获取客户端地址
ipAddr := conn.RemoteAddr().String()
fmt.Println(ipAddr, "连接成功")
for true {
// 缓冲区
infoByte := make([]byte, 1024)
// n是读取的长度
n, err := conn.Read(infoByte)
if err != nil {
fmt.Println(err)
return
}
//
nameAndSize := strings.Split(string(infoByte[:n])," ")
fileSize, err := strconv.Atoi(nameAndSize[1])
fileName := nameAndSize[0]
// 读数据和写文件
file, err := os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)
writer := bufio.NewWriter(file)
// 循环接收数据
var readSize = 0
fmt.Println(readSize, fileSize)
for readSize < fileSize {
data := make([]byte, 1024)
// n是读取的长度
n, _ := conn.Read(data)
fmt.Println("n", n)
_, _ = writer.WriteString(string(data[:n]))
readSize += len(data)
}
_ = writer.Flush()
fmt.Println("上传成功!")
}
}
客户端:
package main
import (
"bufio"
"fmt"
"io"
"net"
"os"
"strconv"
"strings"
)
func main() {
// 1.连接服务端
conn, err := net.Dial("tcp", "127.0.0.1:8888")
if err != nil {
fmt.Println(err)
return
}
defer conn.Close()
// 缓冲区
for true {
reader := bufio.NewReader(os.Stdin) // 从标准输入生成读对象
fmt.Println("输入执行命令>>>")
text, _ := reader.ReadString('\n') // 读到换行
text = strings.TrimSpace(text)
path := strings.Split(text," ")[1]
//打开文件
file, _ := os.Open(path)
// 获取文件大小
reader = bufio.NewReader(file)
f, _ := os.Stat(path)
// 发送文件大小
fsize := f.Size()
// 获取文件名称
fname := f.Name()
strInt64 := strconv.FormatInt(fsize, 10)
_, _ = conn.Write([]byte(fname+" "+strInt64))
// 发送文件数据
for {
// (1) 按行都字符串
bytes, err := reader.ReadBytes('\n') // 读取到换行符为止,读取内容包括换行符
// 发送数据
_, _ = conn.Write(bytes)
if err == io.EOF { //io.EOF 读取到了文件的末尾
// fmt.Println("读取到文件末尾!")
break
}
}
fmt.Println("上传成功")
}
}