tcp并发服务器
本文是Mihalis Tsoukalos的“围棋”系列的一部分。 阅读第1部分: 在Go中创建随机,安全的密码 。
TCP和UDP服务器无处不在,通过TCP / IP网络为网络客户端提供服务。 在本文中,我将解释如何使用Go编程语言开发并发TCP服务器,该服务器返回随机数。 对于来自TCP客户端的每个传入连接,TCP服务器将启动一个新的goroutine来处理该请求。
您可以在GitHub上找到该项目concTCP.go 。
处理TCP连接
程序的逻辑可以在handleConnection()
函数的Go代码中找到,该代码的实现如下:
func handleConnection
( c
net. Conn
)
{
fmt
. Printf
(
"Serving %s \n "
, c
. RemoteAddr
()
. String
())
for
{
netData
, err
:= bufio
. NewReader
( c
)
. ReadString
(
' \n '
)
if err
!=
nil
{
fmt
. Println
( err
)
return
}
temp
:= strings
. TrimSpace
(
string
( netData
))
if temp
==
"STOP"
{
break
}
result
:= strconv
. Itoa
( random
())
+
" \n "
c
. Write
([]
byte
(
string
( result
)))
}
c
. Close
()
}
for
循环可确保在TCP客户端需要的时间范围内为TCP客户端提供服务。
for
循环中的Go代码使用bufio.NewReader(c).ReadString('\n')
从TCP客户端读取数据,并使用c.Write([]byte(string(result)))
。
(您可能会发现网络标准Go软件包文档很有帮助。)
并发
main()
函数的实现告诉TCP服务器每次必须为TCP客户端提供服务时都要启动一个新的goroutine:
func main
()
{
arguments
:= os
. Args
if
len
( arguments
)
==
1
{
fmt
. Println
(
"Please provide a port number!"
)
return
}
PORT
:=
":"
+ arguments
[
1
]
l
, err
:= net
. Listen
(
"tcp4"
, PORT
)
if err
!=
nil
{
fmt
. Println
( err
)
return
}
defer l
. Close
()
rand
. Seed
( time
. Now
()
. Unix
())
for
{
c
, err
:= l
. Accept
()
if err
!=
nil
{
fmt
. Println
( err
)
return
}
go handleConnection
( c
)
}
}
首先, main()
确保程序具有至少一个命令行参数。 请注意,现有代码不会检查给定的命令行参数是否为有效的TCP端口号。 但是,如果给定的值不是有效的TCP端口号,则对net.Listen()
的调用将失败,并显示类似于以下内容的错误消息:
$
go run concTCP
.
go 12a
listen tcp4
: lookup tcp4
/ 12a
: nodename nor servname provided
, or not known
$
go run concTCP
.
go
-
10
listen tcp4
: address
-
10
: invalid port
net.Listen()
调用用于告诉Go程序接受网络连接,从而充当服务器。 net.Listen()
的返回值是net.Conn
类型,该类型实现io.Reader
和io.Writer
接口。 main()
函数还调用rand.Seed()
函数以初始化随机数生成器。 最后, for
循环允许程序继续使用Accept()
接受新的TCP客户端,这些客户端将由handleConnection()
函数的实例处理,该实例作为goroutine执行。
net.Listen()的第一个参数
net.Listen()
函数的第一个参数定义将使用的网络类型,而第二个参数定义服务器地址以及服务器将侦听的端口号。 第一个参数的有效值为tcp,tcp4(仅IPv4),tcp6(仅IPv6),udp,udp4(仅IPv4),udp6(仅IPv6),ip,ip4(仅IPv4),ip6(仅限IPv6),Unix(Unix套接字),Unixgram和Unixpacket。
运行中的并发TCP服务器
concTCP.go需要一个命令行参数,这是它将侦听的端口号。 在为TCP客户端提供服务时,将从concTCP.go中获得的输出将类似于以下内容:
$
go run concTCP
.
go
8001
Serving
127
.
0
.
0
.
1
:
62554
Serving
127
.
0
.
0
.
1
:
62556
netstat(1)
的输出可以验证concTCP.go在侦听更多连接时是否服务于多个TCP客户端:
$ netstat
- anp TCP
| grep
8001
tcp4
0
0
127
.
0
.
0
.
1
.
8001
127
.
0
.
0
.
1
.
62556 ESTABLISHED
tcp4
0
0
127
.
0
.
0
.
1
.
62556
127
.
0
.
0
.
1
.
8001 ESTABLISHED
tcp4
0
0
127
.
0
.
0
.
1
.
8001
127
.
0
.
0
.
1
.
62554 ESTABLISHED
tcp4
0
0
127
.
0
.
0
.
1
.
62554
127
.
0
.
0
.
1
.
8001 ESTABLISHED
tcp4
0
0
*.
8001
*.* LISTEN
前面命令输出的最后一行告诉我们,有一个侦听端口8001的进程,这意味着您仍然可以连接到TCP端口8001。前两行验证存在已建立的TCP网络连接使用端口号8001和62556。类似地,第三和第四行验证是否存在另一个使用端口号8001和62554的已建立TCP连接。
此图显示了服务多个TCP客户端时concTCP.go的输出:

concTCP.go TCP服务器正在运行。
类似地,下图显示了使用nc(1)
实用程序实现的两个TCP客户端的输出:

使用nc(1)
实用程序作为concTCP.go的TCP客户端。
您可以在Wikipedia上找到有关nc(1)
(也称为netcat(1)
更多信息。
摘要
因此,您刚刚学习了如何开发并发TCP服务器,该服务器使用大约65行Go代码生成随机数,这真是令人印象深刻! 如果希望TCP服务器执行其他工作,只需更改handleConnection()
函数的实现即可。
翻译自: https://opensource.com/article/18/5/building-concurrent-tcp-server-go
tcp并发服务器