go实现tcp 服务器
<p>我们将使用 TCP 协议和协程范式编写一个简单的客户端-服务器应用,一个(web)服务器应用需要响应众多客户端的并发请求:Go 会为每一个客户端产生一个协程用来处理请求。我们需要使用 net 包中网络通信的功能。它包含了处理 TCP/IP 以及 UDP 协议、域名解析等方法。</p><p>服务器端代码是一个单独的文件:</p>
<details>
<summary>代码 server.go</summary>
<pre><code class="language-go">package main
import (
"fmt"
"net"
)
func main() {
fmt.Println("Starting the server ...")
// 创建 listener
listener, err := net.Listen("tcp", "localhost:50000")
if err != nil {
fmt.Println("Error listening", err.Error())
return //终止程序
}
// 监听并接受来自客户端的连接
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println("Error accepting", err.Error())
return // 终止程序
}
go doServerStuff(conn)
}
}
func doServerStuff(conn net.Conn) {
for {
buf := make([]byte, 512)
len, err := conn.Read(buf)
if err != nil {
fmt.Println("Error reading", err.Error())
return //终止程序
}
fmt.Printf("Received data: %v\n", string(buf[:len]))
}
}
</code></pre>
</details>
<p>在 <code>main()</code> 中创建了一个 <code>net.Listener</code> 类型的变量 <code>listener</code>,他实现了服务器的基本功能:用来监听和接收来自客户端的请求(在 localhost 即 IP 地址为 127.0.0.1 端口为 50000 基于TCP协议)。<code>Listen()</code> 函数可以返回一个 <code>error</code> 类型的错误变量。用一个无限 for 循环的 <code>listener.Accept()</code> 来等待客户端的请求。客户端的请求将产生一个 <code>net.Conn</code> 类型的连接变量。然后一个独立的协程使用这个连接执行 <code>doServerStuff()</code>,开始使用一个 512 字节的缓冲 <code>data</code> 来读取客户端发送来的数据,并且把它们打印到服务器的终端,<code>len</code> 获取客户端发送的数据字节数;当客户端发送的所有数据都被读取完成时,协程就结束了。这段程序会为每一个客户端连接创建一个独立的协程。必须先运行服务器代码,再运行客户端代码。</p>
<p>客户端代码写在另一个文件 client.go 中:</p>
<details>
<summary>代码 client.go</summary>
<pre><code class="language-go">package main
import (
"bufio"
"fmt"
"net"
"os"
"strings"
)
func main() {
//打开连接:
conn, err := net.Dial("tcp", "localhost:50000")
if err != nil {
//由于目标计算机积极拒绝而无法创建连接
fmt.Println("Error dialing", err.Error())
return // 终止程序
}
inputReader := bufio.NewReader(os.Stdin)
fmt.Println("First, what is your name?")
clientName, _ := inputReader.ReadString('\n')
// fmt.Printf("CLIENTNAME %s", clientName)
trimmedClient := strings.Trim(clientName, "\r\n") // Windows 平台下用 "\r\n",Linux平台下使用 "\n"
// 给服务器发送信息直到程序退出:
for {
fmt.Println("What to send to the server? Type Q to quit.")
input, _ := inputReader.ReadString('\n')
trimmedInput := strings.Trim(input, "\r\n")
// fmt.Printf("input:--%s--", input)
// fmt.Printf("trimmedInput:--%s--", trimmedInput)
if trimmedInput == "Q" {
return
}
_, err = conn.Write([]byte(trimmedClient + " says: " + trimmedInput))
}
}
</code></pre>
</details>
<p>客户端通过 <code>net.Dial</code> 创建了一个和服务器之间的连接。</p>
<p>它通过无限循环从 <code>os.Stdin</code> 接收来自键盘的输入,直到输入了“Q”。注意裁剪 <code>\r</code> 和 <code>\n</code> 字符(仅 Windows 平台需要)。裁剪后的输入被 <code>connection</code> 的 <code>Write</code> 方法发送到服务器。</p>
<p>当然,服务器必须先启动好,如果服务器并未开始监听,客户端是无法成功连接的。</p>
<p>如果在服务器没有开始监听的情况下运行客户端程序,客户端会停止并打印出以下错误信息:<code>对tcp 127.0.0.1:50000发起连接时产生错误:由于目标计算机的积极拒绝而无法创建连接</code>。</p>
<p>可以同时启动多个客户端程序。</p>
<p>一下是服务器的输出:</p>
<p>在网络编程中 <code>net.Dial</code> 函数是非常重要的,一旦你连接到远程系统,函数就会返回一个 <code>Conn</code> 类型的接口,我们可以用它发送和接收数据。<code>Dial</code> 函数简洁地抽象了网络层和传输层。所以不管是 IPv4 还是 IPv6,TCP 或者 UDP 都可以使用这个公用接口。</p>
<p> </p>
<p>参考链接:https://github.com/unknwon/the-way-to-go_ZH_CN/blob/master/eBook/15.1.md</p>
</div>
<div id="MySignature" role="contentinfo">
个性签名:时间会解决一切<br><br>
来源:https://www.cnblogs.com/lfri/p/11769254.html
頁:
[1]