golang代码片段(摘抄)

以下是从golang并发编程实战2中摘抄过来的代码片段,主要是实现一个简单的tcp socket通讯(客户端发送一个数字,服务端计算该数字的立方根然后返回),写的不错,用到了go的并发以及看下郝林大神是如何处理socket通讯的。具体代码记录如下,多看多学习多共勉:

package main

import (
	"net"
	"strings"
	"fmt"
	"time"
	"io"
	"bytes"
	"strconv"
	"math"
	"math/rand"
	"sync"
)
const (
	SERVER_NETWORK = "tcp"
	SERVER_ADDRESS = "127.0.0.1:8085"
	DELIMITER = '\t'
)

var wg sync.WaitGroup

func main() {
	wg.Add(2)
	go serverGo()
	time.Sleep(500 * time.Millisecond)
	go clientGo(1)
	wg.Wait()
}

func serverGo() {
	defer wg.Done()
	listener, err := net.Listen(SERVER_NETWORK, SERVER_ADDRESS)
	if err != nil {
		printServerLog("Listen Error: %s", err)
		return
	}
	defer listener.Close()
	printServerLog("Got listener for the server.(local address: %s)", listener.Addr())
	for {
		conn, err := listener.Accept()
		if err != nil {
			printServerLog("Accept Error: %s", err)
		}
		printServerLog("Established a connection with a client application,(remote address: %s)", conn.RemoteAddr())
		go handleConn(conn)
	}
}

func printLog(role string, sn int, format string, args ...interface{})  {
	if !strings.HasSuffix(format, "\n") {
		format += "\n"
	}
	fmt.Printf("%s[%d]: %s", role, sn, fmt.Sprintf(format, args...))
}

func printServerLog(format string, args ...interface{})  {
	printLog("Server", 0, format, args...)
}

func printClientLog(sn int, format string, args ...interface{})  {
	printLog("Cient", sn, format, args...)
}

func handleConn(conn net.Conn)  {
	defer conn.Close()
	for {
		conn.SetDeadline(time.Now().Add(10 * time.Second))		// set read timeline 10s
		strReq, err := read(conn)
		if err != nil {
			if err == io.EOF {
				printServerLog("The connection is closed by another side.")
			} else {
				printServerLog("Read Error: %s", err)
			}
			break
		}
		printServerLog("Received request: %s", strReq)
		intReq, err := strToInt32(strReq)
		if err != nil {
			n, err := write(conn, err.Error())
			printServerLog("Sent error message (written %d bytes): %s", n, err)
			continue
		}
		floatResp := cbrt(intReq)
		respMsg := fmt.Sprintf("The cube root of %d is %f.", intReq, floatResp)
		n, err := write(conn, respMsg)
		if err != nil {
			printServerLog("Sent response message (written %d bytes: %s).", n, respMsg)
		}
	}
}

func read(conn net.Conn) (string, error){
	readBytes := make([]byte, 1)
	var buffer bytes.Buffer
	for {
		_, err := conn.Read(readBytes)
		if err != nil {
			return "", err
		}
		readByte := readBytes[0]
		if readByte == DELIMITER {
			break
		}
		buffer.WriteByte(readByte)
	}
	return buffer.String(), nil
}

func strToInt32(str string) (int32, error){
	i32, err := strconv.ParseInt(str, 10 ,32)
	return int32(i32), err
}

func write(conn net.Conn, content string) (int, error) {
	var buffer bytes.Buffer
	buffer.WriteString(content)
	buffer.WriteByte(DELIMITER)
	return conn.Write(buffer.Bytes())
}

func cbrt(intReq int32) float64 {
	return math.Cbrt(float64(intReq))
}

func clientGo(id int)  {
	defer wg.Done()
	conn, err := net.DialTimeout(SERVER_NETWORK, SERVER_ADDRESS, 2 * time.Second)
	if err != nil {
		printClientLog(id, "Dial Error: %s", err)
		return
	}
	defer conn.Close()
	printClientLog(id, "Connected to server.(remote address: %s,local address: %s)", conn.RemoteAddr(), conn.LocalAddr())
	time.Sleep(200 * time.Millisecond)

	requestNumber := 5
	conn.SetDeadline(time.Now().Add(5 * time.Millisecond))
	for i := 0; i< requestNumber; i++ {
		req := rand.Int31()
		n, err := write(conn, fmt.Sprintf("%d", req))
		if err != nil {
			printClientLog(id, "Write Error: %s", err)
			continue
		}
		printClientLog(id, "Sent request (written %d bytes)", n)
	}
	for j := 0; j< requestNumber; j++ {
		strResp, err := read(conn)
		if err != nil {
			if err == io.EOF {
				printClientLog(id, "The connection is closed by another side.")
			}else{
				printClientLog(id, "Read Error: %s", err)
			}
			break
		}
		printClientLog(id, "Received response: %s", strResp)
	}
}

执行效果:

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Kubernetes

kube-proxy源码分析

##kube-proxy介绍 请参考我的另一篇博文:kube-proxy工作原理 ##源码目录结构分析 cmd/kube-proxy //负责kub...

4545
来自专栏一只程序汪的自我修养

ASP.NET MVC 微信JS-SDK认证

1683
来自专栏岑玉海

sqoop 从sqlserver2008 导入数据到hadoop

  今天终于开始上手导入数据到hadoop了,哈哈,过程蛮崎岖的,和官方文档的还不太一样。   OK,let's go!试验对象是我第一个名为ST_Statis...

3535
来自专栏知识分享

51采集PCF8591数据通过ESP8266上传C#上位机android 之TCP客户端编程ESP8266使用详解NodeMCU初探ESP8266刷AT固件与nodemcu固件ESP8266使用详解-

这两天测试程序还发现一个bug就是如果客户端断开了,应该检测一下哪个断开了,数据就不应该发向那个连接,,,否则就会报错,然后模块会复位重启 所以加上这段代码 c...

3845
来自专栏WindCoder

iOS集中和解耦网络:具有单例类的AFNetworking教程

当涉及iOS架构模式时,模型 - 视图 - 控制器(MVC)设计模式对于应用程序的代码库的长寿和可维护性是非常有用的。通过将它们解耦从而使类可以很容易地被重用或...

781
来自专栏landv

c语言_头文件_windows.h

1193
来自专栏Golang语言社区

GO语言 TCP传输实例

package main import ( "net" "fmt" ) var ( maxRead = 1100 msgStop = []byt...

3316
来自专栏冰霜之地

Weex 是如何在 iOS 客户端上跑起来的

2016年4月21日,阿里巴巴在Qcon大会上宣布跨平台移动开发工具Weex开放内测邀请。Weex能够完美兼顾性能与动态性,让移动开发者通过简捷的前端语法写出N...

1263
来自专栏ASP.NET MVC5 后台权限管理系统

ASP.NET MVC5+EF6+EasyUI 后台管理系统(87)-MVC Excel导入和导出

按照之前的做法,更新到EF。并利用T4生成DAL,BLL,MODEL。再用代码生成器生成界面复制进解决方案,一步到位

1250
来自专栏杨建荣的学习笔记

关于oracle中的半连接(r3笔记55天)

表的连接在sql语句中尤为重要。外连接,内连接,半连接,反连接等等各种连接,看似简单的一个连接里面还是有不少的细节的。对于sql调优来说也是很重要的。 像下面的...

2638

扫码关注云+社区