Golang: TCP 简单并发服务器

一个简单的多协程并发服务器,客户端从标准输入读取内容,服务器处理后返回。

专栏的介绍可以参考 《CaseGolang专栏》,代码可以看《宝库-Case》

案例比较简单:客户端从标准输入读取内容发送给服务器,服务器处理之后返回给客户端。
(中间关于读写的时候,有些小细节要注意;不展开直接看代码吧)

直接贴代码:(server.go)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package main

import (
"io"
"strings"
"fmt"
"log"
"net"
)

func main() {
listener, err := net.Listen("tcp", "127.0.0.1:8000")
if err != nil {
log.Fatalln("err = ", err)
}
defer listener.Close()

//并发接收多个请求
for {
conn, err := listener.Accept()
if err != nil {
log.Fatalln("err = ", err)
}
//为每一个连接开一个协程
go HandleConn(conn)
}
}

func HandleConn(conn net.Conn) {
defer conn.Close()

//获取对端地址
addr := conn.RemoteAddr().String()
fmt.Println(addr + "addr connect succeed")

//读取用户请求
buf := make([]byte, 1024*4)

for {
n, err := conn.Read(buf)
if err != nil {
if err != io.EOF {
fmt.Println("err = ", err)
}
return
}
fmt.Println("read buf = ", string(buf[:n])) //查看读取到的内容

conn.Write([]byte(strings.ToUpper(string(buf[:n])))) //转成大写返回给客户端
}

}

然后 client.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package main

import (
"os"
"fmt"
"net"
)

/*直接发送内容*/
/* func main() {
conn, err := net.Dial("tcp", "127.0.0.1:8000")
if err != nil {
fmt.Println("err = ", err)
return
}
defer conn.Close()

conn.Write([]byte("big")) //发送数据
} */

//从 os.Stdin读取内容,然后在发送

func main() {
conn, err := net.Dial("tcp", "127.0.0.1:8000")
if err != nil {
fmt.Println("dial err : ", err)
return
}
defer conn.Close()

go func() {
//从键盘设备文件读
str := make([]byte, 1024)
for {
n, err := os.Stdin.Read(str) //读取标准输入
if err != nil {
fmt.Println("os.Stdin, err = ", err)
return
}

//把输入的内容给服务器发送
conn.Write(str[:n]) //读多少写多少
}

}()

//主协程负责死循环在这守着服务器的回写
//(好处是服务器关闭,这边儿可以退出; 否则放到子协程中读,主协程进行 stdin输出,
//则即使读到服务器关闭的异常,程序也无法退出)
buf := make([]byte, 1024)
for {
n, err := conn.Read(buf) //接收服务器的写回
if err != nil {
fmt.Println("read err = ", err)
return
}
fmt.Println(string(buf[:n])) //打印服务器拿过来的数据
}
}

不解释了,注意下 IO 的处理,还有一种方式,判断读取的字节数 n 。

运行大致如下:

并发服务器


Merlin 网络小案例 upload

文章目录
|