Skip to content

Commit

Permalink
feat: add socket example 🚧
Browse files Browse the repository at this point in the history
  • Loading branch information
m9rco committed Oct 13, 2017
1 parent ba0ffdb commit 61dce9c
Show file tree
Hide file tree
Showing 4 changed files with 331 additions and 1 deletion.
181 changes: 180 additions & 1 deletion Chapter3-并发编程综述/Socket/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,185 @@
*/
package main

func main() {
import (
"bytes"
"fmt"
"io"
"math"
"math/rand"
"net"
"strconv"
"strings"
"sync"
"time"
)

const (
SERVER_NETWORK = "tcp"
SERVER_ADDRESS = "127.0.0.1:8085"
DELIMITER = '\t'
)

var wg sync.WaitGroup

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("Client", sn, format, args...)
}

func strToInt32(str string) (int32, error) {
num, err := strconv.ParseInt(str, 10, 0)
if err != nil {
return 0, fmt.Errorf("\"%s\" is not integer", str)
}
if num > math.MaxInt32 || num < math.MinInt32 {
return 0, fmt.Errorf("%d is not 32-bit integer", num)
}
return int32(num), nil
}

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

// 千万不要使用这个版本的read函数!
//func read(conn net.Conn) (string, error) {
// reader := bufio.NewReader(conn)
// readBytes, err := reader.ReadBytes(DELIMITER)
// if err != nil {
// return "", err
// }
// return string(readBytes[:len(readBytes)-1]), nil
//}

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 write(conn net.Conn, content string) (int, error) {
var buffer bytes.Buffer
buffer.WriteString(content)
buffer.WriteByte(DELIMITER)
return conn.Write(buffer.Bytes())
}

// 服务端建立Socket
func serverGo() {
var listener net.Listener
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 handleConn(conn net.Conn) {
defer func() {
conn.Close()
wg.Done()
}()
for {
conn.SetReadDeadline(time.Now().Add(10 * time.Second))
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("Write Error: %s", err)
}
printServerLog("Sent response (written %d bytes): %s.", n, respMsg)
}
}

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): %d.", n, req)
}
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)
}
}

func main() {
wg.Add(2)
go serverGo()
time.Sleep(500 * time.Millisecond)
go clientGo(1)
wg.Wait()
}
66 changes: 66 additions & 0 deletions Chapter3-并发编程综述/Socket/socket_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package main

import (
"net"
"time"
"Go-example/Debug"
"bytes"
"bufio"
"os"
"strings"
"fmt"
)

const (
RE = '\t'
)

func ClientInit(netWork, address string) {
conn, err := net.DialTimeout(netWork, address, 2*time.Second)
if err != nil {
Debug.RenderClient("Dial Error: %s", err)
return
}
defer conn.Close()
Debug.RenderClient("Connected to server. (remote address: %s, local address: %s)",
conn.RemoteAddr(), conn.LocalAddr())
for {
cmdReader := bufio.NewReader(os.Stdin)
cmdStr, err := cmdReader.ReadString('\n')
if err != nil{
break
}
//这里把读取的数据后面的换行去掉,对于Mac是"\r",Linux下面
//是"\n",Windows下面是"\r\n",所以为了支持多平台,直接用
//"\r\n"作为过滤字符
cmdStr = strings.Trim(cmdStr, "\r\n")
time.Sleep(200 * time.Millisecond)
conn.SetDeadline(time.Now().Add(5 * time.Millisecond))
var buffer bytes.Buffer
buffer.WriteString(cmdStr)
var delimiter byte
delimiter = '\t'
buffer.WriteByte(delimiter)
conn.Write(buffer.Bytes())
}
}

func readClient(conn net.Conn, delimiter string) (string, error) {
readBytes := make([]byte, 1)
var buffer bytes.Buffer
for {
_, err := conn.Read(readBytes)
if err != nil {
return "", err
}
readByte := readBytes[0]
if string(readByte) == delimiter {
break
}
buffer.WriteByte(readByte)
}
return buffer.String(), nil
}
func main() {
ClientInit("tcp", "127.0.0.1:9630")
}
69 changes: 69 additions & 0 deletions Chapter3-并发编程综述/Socket/socket_server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package main

import (
"net"
"Go-example/Debug"
"fmt"
"bytes"
"io"
"strings"
)

func serverInit(netWork, address, delimiter string) {
var listener net.Listener
listener, err := net.Listen(netWork, address) // 1. 开始监听9630 端口
if err != nil {
Debug.ErrorMsg(err)
return
}
defer listener.Close() // 2. 代码结束后释放监听资源
fmt.Printf("建立连接成功 %s\n", listener.Addr())
for {
conn, err := listener.Accept() // 阻塞直至新连接到来。
if err != nil {
Debug.RenderServer("Accept Error: %s", err)
}
go func(conn net.Conn) { // 3. 连接建立成功
defer func() { // 4. 连接结束释放资源
conn.Close()
//wg.Done()
}()
client := strings.Replace(conn.RemoteAddr().String(), "127.0.0.1:", "", 3)
Debug.RenderServer("%s 加入进来了", client)
for {
//conn.SetReadDeadline(time.Now().Add(30 * time.Second)) // 设置读取长
strReq, err := readServer(conn, delimiter)
if err != nil {
if err == io.EOF {
Debug.RenderServer(" %s 断开了连接", client)
} else {
Debug.RenderServer("Read Error: %s", err)
}
break
}
Debug.RenderServer("%s 说:%s", client, strReq)
}
}(conn)
}
}

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

func main() {
serverInit("tcp", "127.0.0.1:9630", "\t")
}
16 changes: 16 additions & 0 deletions Debug/Tools.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package Debug
import (
"runtime"
"fmt"
"strings"
)

/**
Expand All @@ -15,3 +16,18 @@ func ErrorMsg(entity error) {
}
return
}

func RenderLog(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 RenderServer(format string, args ...interface{}){
RenderLog("Server", 0, format, args...)
}

func RenderClient(format string, args ...interface{}){
RenderLog("Client", 0, format, args...)
}

0 comments on commit 61dce9c

Please sign in to comment.