Mobile wallpaper 1Mobile wallpaper 2Mobile wallpaper 3Mobile wallpaper 4Mobile wallpaper 5Mobile wallpaper 6
1789 字
9 分钟
网络编程
2025-07-15

引入#

【1】网络编程: 把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大、功能强的网络系统,从而使众多的计算机可以方便地互相传递信 息、共享硬件、软件、数据信息等资源。 设备之间在网络中进行数据的传输,发送/接收数据。

PixPin_2025-07-15_11-33-28

【2】通信两个重要的要素:IP+PORT

PixPin_2025-07-15_12-16-23

【3】设备之间进行传输的时候,必须遵照一定的规则---》通信协议:

PixPin_2025-07-15_12-18-18

PixPin_2025-07-15_12-19-53

【4】TCP协议:可靠的 建立连接:三次握手

PixPin_2025-07-15_12-21-13

释放连接:四次挥手

PixPin_2025-07-15_12-23-28

【5】UDP协议:不可靠的

PixPin_2025-07-15_12-23-46

基于TCP协议的网络通信#

创建客户端#

【1】调用Dial函数:(net包下)

func Dial#

func Dial(network, address string) (Conn, error)

在网络network上连接地址address,并返回一个Conn接口。可用的网络类型有:

“tcp”、“tcp4”、“tcp6”、“udp”、“udp4”、“udp6”、“ip”、“ip4”、“ip6”、“unix”、“unixgram”、“unixpacket”

对TCP和UDP网络,地址格式是host或[host],参见函数JoinHostPort和SplitHostPort。

Dial("tcp", "12.34.56.78:80")
Dial("tcp", "google.com:http")
Dial("tcp", "[2001:db8::1]:http")
Dial("tcp", "[fe80::1%lo0]:80")

对IP网络,network必须是”ip”、“ip4”、“ip6”后跟冒号和协议号或者协议名,地址必须是IP地址字面值。

Dial("ip4:1", "127.0.0.1")
Dial("ip6:ospf", "::1")

对Unix网络,地址必须是文件系统路径。

代码:

package main
import(
"fmt"
"net"//所需的网络编程全部都在net包下
)
func main() {
//打印:
fmt.Println("客户端启动。。")
//调用Dial函数:参数需要制定tcp协议,需要制定服务器端的IP+PORT
conn,err := net.Dial("tcp","127.0.0.1:8888")
if err != nil{//连接失败
fmt.Println("客户端连接失败:err:",err)
}
fmt.Println("连接成功,conn:",conn)
}

创建服务器端#

【1】进行监听:(Listen函数在net包下)

type Listener#

type Listener interface {
// Addr返回该接口的网络地址
Addr() Addr
// Accept等待并返回下一个连接到该接口的连接
Accept() (c Conn, err error)
// Close关闭该接口,并使任何阻塞的Accept操作都会不再阻塞并返回错误。
Close() error
}

Listener是一个用于面向流的网络协议的公用的网络监听器接口。多个线程可能会同时调用一个Listener的方法。

Example

func Listen#

func Listen(net, laddr string) (Listener, error)

返回在一个本地网络地址laddr上监听的Listener。网络类型参数net必须是面向流的网络:

“tcp”、“tcp4”、“tcp6”、“unix”或”unixpacket”。参见Dial函数获取laddr的语法。

【2】代码

package main
import(
"fmt"
"net"//所需的网络编程全部都在net包下
)
func main() {
//打印:
fmt.Println("服务器端启动。。")
//进行监听:需要制定服务器端TCP协议,服务器端的IP+PORT
listen,err := net.Listen("tcp","127.0.0.1:8888")
if err != nil{
fmt.Println("监听失败,err:",err)
return
}
//监听成功以后:
//循环等待客户端的连接:
for{
conn,err2 := listen.Accept()
if err2 != nil {//等待客户端的连接失败
fmt.Println("客户端的等待失败,err2:",err2)
}else{
//连接成功:
fmt.Printf("等待连接成功,con%v,接受到客户端信息:%v\n",conn,conn.RemoteAddr().String())
}
}
}

运行时注意:需要先启动服务器端

PixPin_2025-07-15_17-34-40

发送终端数据#

【1】客户端发送数据:

package main
import (
"bufio"
"fmt"
"net" //所需的网络编程全部都在net包下
"os"
)
func main() {
//打印:
fmt.Println("客户端启动。。")
//调用Dial函数:参数需要制定tcp协议,需要制定服务器端的IP+PORT
conn,err := net.Dial("tcp","127.0.0.1:8888")
if err != nil{//连接失败
fmt.Println("客户端连接失败:err:",err)
}
fmt.Println("连接成功,conn:",conn)
//通过客户端发送单行数据,然后退出:
reader := bufio.NewReader(os.Stdin)//os.Stdin代表终端标准输入
//从终端读取一行用户输入的信息:
str,err := reader.ReadString('\n')
if err!= nil {
fmt.Println("终端输入失败,err:",err)
}
//将str数据发送到服务器:
n,err := conn.Write([]byte(str))
if err != nil{
fmt.Println("连接失败,err:",err)
}else{
fmt.Printf("终端数据通过客户端发送成功,一共发送了%v字节的数据,并退出",n)
}
}

【2】服务器端接收数据:

package main
import(
"fmt"
"net"//所需的网络编程全部都在net包下
)
func process(conn net.Conn) {
//连接用完一定要关闭:
defer conn.Close()
for{
//创建一个切片,准备:将读取的数据放入切片
buf := make([]byte,1024)
//从conn连接中读取数据:
n,err := conn.Read(buf)
if err != nil{
return
}
//将读取的内容在服务器端输出:
fmt.Println(string(buf[0:n]))
}
}
func main() {
//打印:
fmt.Println("服务器端启动。。")
//进行监听:需要制定服务器端TCP协议,服务器端的IP+PORT
listen,err := net.Listen("tcp","127.0.0.1:8888")
if err != nil{
fmt.Println("监听失败,err:",err)
return
}
//监听成功以后:
//循环等待客户端的连接:
for{
conn,err2 := listen.Accept()
if err2 != nil {//等待客户端的连接失败
fmt.Println("客户端的等待失败,err2:",err2)
}else{
//连接成功:
fmt.Printf("等待连接成功,con=%v,接受到客户端信息:%v\n",conn,conn.RemoteAddr().String())
}
//准备一个协程,协程处理客户端服务请求:
go process(conn)//不同的客户端的请求,连接conn不一样的
}
}

【3】处理结果:

PixPin_2025-07-15_17-51-35

PixPin_2025-07-15_17-50-39

🌱 核心原理:TCP 通信三要素#

要让两台机器通过 TCP 通信,需要: 1️⃣ 服务器端监听端口(listen) 2️⃣ 客户端连接到这个端口(dial/connect) 3️⃣ 双方通过连接(conn)进行数据读写(Read/Write)

这段程序正好是最典型的「一问一答」结构:

  • 客户端只发送一行数据
  • 服务端接收后打印出来

✅ 服务器端原理详解#

① 开始监听#

listen, err := net.Listen("tcp", "127.0.0.1:8888")
  • net.Listen 用来监听本机 IP 和端口
  • 协议是 “tcp”
  • 返回 listen 对象(Listener),专门接收新连接

② 循环等待客户端连接#

for {
conn, err2 := listen.Accept()
}
  • listen.Accept():阻塞等待,直到有客户端连接过来
  • 返回一个 conn 对象(类型:net.Conn),表示与客户端之间的这次连接
  • 之后通过 conn 可以收发数据

③ 为每个连接启动一个协程处理#

go process(conn)
  • 每当有新客户端连接,就开一个 goroutine 专门服务它
  • 不会影响主协程继续监听新连接(支持并发处理多个客户端)

④ 从客户端接收数据#

buf := make([]byte, 1024)
n, err := conn.Read(buf)
  • 从 conn 中读数据放入 buf 切片
  • 返回读取的字节数 n
  • 打印出来:
fmt.Println(string(buf[0:n]))

✏ 关键点总结(服务器端)#

  • net.Listen:监听端口
  • listen.Accept():接受一个客户端连接
  • conn.Read(buf):从客户端读数据
  • 多客户端用 go process(conn) 实现并发

✅ 客户端原理详解#

① 连接服务器#

conn, err := net.Dial("tcp", "127.0.0.1:8888")
  • net.Dial:连接目标服务器
  • 返回 conn,用来和服务器通信

② 从终端读取用户输入#

reader := bufio.NewReader(os.Stdin)
str, err := reader.ReadString('\n')
  • 用户输入一行回车结束

③ 发送到服务器#

conn.Write([]byte(str))
  • 把读到的字符串转成字节切片发送
  • TCP 是流式协议,不保证一次写对方就一次读,需要程序自己确定分界(这里简单用一行字符串)

✏ 关键点总结(客户端)#

  • net.Dial:建立 TCP 连接
  • conn.Write:发送数据
  • 只发送一次,发送后退出

📦 为什么能成功通信?#

  • 客户端 Dial 的 IP 和端口与服务器监听的一样 → 成功建立 TCP 连接
  • 建立连接后,双方有了一个 conn 对象(各自一边一个)
  • 通过这个连接,可以互相 Read/Write
网络编程
https://mikufun.dpdns.org/posts/网络编程/
作者
Roxy-DD
发布于
2025-07-15
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

封面
Sample Song
Sample Artist
封面
Sample Song
Sample Artist
0:00 / 0:00