Golang实现简单的Socket网络编程(代码+详细注释)

前言

用Go语言实现Socket网络编程

基于C/S开发模型

实现客户端与服务端之间的通信

客户端发送消息给服务端

服务端进行业务处理

服务端将处理好的数据返回给客户端

基础版

服务端只能同时服务一个客户端

只进行一次通话(收发消息)

客户端

客户端开发代码如下

package main

import (
	"fmt"
	"net"//Socket编程使用的包 需要引入
)

func main() {

	//与服务器建立连接
    //参数1表示使用TCP协议
    //参数2是"127.0.0.1:666"的省略写法
    //如果IP地址是本地回环IP 可以省略冒号之前的内容
	conn, err := net.Dial("tcp", ":666")
    
    //err == nil 时表示没有错误
	if err != nil {
		fmt.Println("net.Dial err:", err)
		return
	}

	fmt.Println("Dial success")

    //发送的数据是字符切片的格式
	sendData := []byte("hello")

	//向服务器发送数据
	cnt, err := conn.Write(sendData)

	if err != nil {
		fmt.Println("conn.Write err:", err)
		return
	}

	fmt.Println("Client to Server...")
	fmt.Println("length:", cnt, "data", string(sendData))

	//接收服务器返回的数据
	buf := make([]byte, 1024)

	cnt, err = conn.Read(buf)
	if err != nil {
		fmt.Println("conn.Read err:", err)
		return
	}

	fmt.Println("Server to Client...")
	fmt.Println("length:", cnt, "data", string(buf[:cnt])) //只处理前cnt个字符

	//关闭连接
	conn.Close()

}

服务端

服务端开发代码如下

package main

import (
	"fmt"
	"net"
	"strings"
)

func main() {

	//创建监听
	ip := "127.0.0.1"
	port := 666

    //.Sprintf函数往address变量中写入IP和端口信息
	address := fmt.Sprintf("%s:%d", ip, port)

    //开始监听 选择TCP协议 和 监听的方向
	listener, err := net.Listen("tcp", address)

	if err != nil {
		fmt.Println("net.Listen err:", err)
		return
	}

	//提取连接
	conn, err := listener.Accept()
	if err != nil {
		fmt.Println("listener.Accept err:", err)
		return
	}

	fmt.Println("Accept success")

	//创建容器用于接收读取到的数据
	buf := make([]byte, 1024) //使用make函数创建切片

	//cnt是实际读到的字符数
	cnt, err := conn.Read(buf)
	if err != nil {
		fmt.Println("conn.Read err:", err)
		return
	}

	fmt.Println("Client to Server...")
	fmt.Println("length:", cnt, "data", string(buf))

	//服务器业务实现 小写转成大写
	upperData := strings.ToUpper(string(buf[:cnt])) //只处理前cnt个字符
	cnt, err = conn.Write([]byte(upperData))

	fmt.Println("Server to Client...")
	fmt.Println("length:", cnt, "data", upperData)

	//关闭连接
	conn.Close()

}

效果展示 

使用GoLand开发

效果截图如下

升级版

服务端可以同时服务多个客户端

并且每个客户端可以实现多次收发数据

核心思想

主GO程负责监听处理连接


子GO程负责处理数据 实现客户端与服务端互动的具体逻辑

客户端

客户端开发代码如下

package main

import (
	"fmt"
	"net"
	"time"
)

func main() {

	//与服务器建立连接
	conn, err := net.Dial("tcp", ":666")
	if err != nil {
		fmt.Println("net.Dial err:", err)
		return
	}

	fmt.Println("Dial success")
	//client0发送的内容是 "hello this is client 0"
	//client1发送的内容是 "hello this is client 1"
	sendData := []byte("hello this is client 0")

	//向服务器多次发送数据
	for {
		cnt, err := conn.Write(sendData)

		if err != nil {
			fmt.Println("conn.Write err:", err)
			return
		}

		fmt.Println("send data to server...")

		//接收服务器返回的数据
		buf := make([]byte, 1024)

		cnt, err = conn.Read(buf)
		if err != nil {
			fmt.Println("conn.Read err:", err)
			return
		}

		fmt.Println("Server to Client...")
		fmt.Println("length:", cnt, "data", string(buf[:cnt])) //只处理前cnt个字符

        //休息5秒再发送
		time.Sleep(5 * time.Second)
	}
}

服务端

服务端开发代码如下

package main

import (
	"fmt"
	"net"
	"strings"
)

//业务处理函数需要接收conn参数 对应一个具体的客户端方向
func handle(conn net.Conn) {
	for {
		//创建容器用于接收读取到的数据
		buf := make([]byte, 1024) //使用make创建切片
		//cnt是实际读到的字符数
		cnt, err := conn.Read(buf)
		if err != nil {
			fmt.Println("conn.Read err:", err)
			return
		}

		fmt.Println("Client to Server...")
		fmt.Println("length:", cnt, "data", string(buf))

		//服务器业务 小写转成大写
		upperData := strings.ToUpper(string(buf[:cnt])) //只处理前cnt个字符
		cnt, err = conn.Write([]byte(upperData))

		fmt.Println("Server to Client...")
		fmt.Println("length:", cnt, "data", upperData)
	}
}

func main() {

	//创建监听
	ip := "127.0.0.1"
	port := 666
	address := fmt.Sprintf("%s:%d", ip, port)
	listener, err := net.Listen("tcp", address)

	if err != nil {
		fmt.Println("net.Listen err:", err)
		return
	}

	//主GO程负责监听处理连接
	//子GO程负责处理数据 实现客户端与服务端互动的具体逻辑

	//主GO程提取多个连接
	for {
		fmt.Println("listening...")
		conn, err := listener.Accept()

		if err != nil {
			fmt.Println("listener.Accept err:", err)
			return
		}

		fmt.Println("Accept success!")

		//启动一个子GO程 执行业务处理函数
		go handle(conn)
	}
}

效果展示 

使用GoLand开发

效果截图如下

补充

这是socket_client1.go的主函数

上文代码段是socket_client0.go的主函数

func main() {

   //与服务器建立连接
   conn, err := net.Dial("tcp", ":666")
   if err != nil {
      fmt.Println("net.Dial err:", err)
      return
   }

   fmt.Println("Dial success")
   //client0发送的内容是 "hello this is client 0"
   //client1发送的内容是 "hello this is client 1"
   sendData := []byte("hello this is client 1")

   //向服务器多次发送数据
   for {
      cnt, err := conn.Write(sendData)

      if err != nil {
         fmt.Println("conn.Write err:", err)
         return
      }

      fmt.Println("send data to server...")

      //接收服务器返回的数据
      buf := make([]byte, 1024)

      cnt, err = conn.Read(buf)
      if err != nil {
         fmt.Println("conn.Read err:", err)
         return
      }

      fmt.Println("Server to Client...")
      fmt.Println("length:", cnt, "data", string(buf[:cnt])) //只处理前cnt个字符

      time.Sleep(5 * time.Second)
   }
}
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

没伞的男孩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值