分类
- TCP socket编程,是网编的主流,底层用的是TCP/ip协议
- b/s结构的http编程,使用浏览器去访问服务器时,使用的http协议,但是底层依旧是tcp socket实现。
基础知识
协议
TCP/IP是Internet最基本的协议,是由网络层的IP协议和传输层的TCP协议组成。
OSI模型约TCP/IP参考模型
| 层级(从高到低) | OSI 模型(7 层) | 主要功能 | TCP/IP 模型(4 层) | 对应关系说明 |
|---|---|---|---|---|
| 7 | 应用层(Application) | 提供用户接口和网络服务(如邮件、文件传输) | 应用层 | |
| 6 | 表示层(Presentation) | 数据格式转换、加密解密、压缩等 | 应用层 | OSI 的应用层 + 表示层 + 会话层 合并为 TCP/IP 应用层 |
| 5 | 会话层(Session) | 建立、管理和终止会话 | 应用层 | |
| 4 | 传输层(Transport) | 端到端通信,提供可靠(TCP)或高效(UDP)传输 | 传输层 | 功能基本一致 |
| 3 | 网络层(Network) | 逻辑寻址(IP)、路由选择 | 网络层(Internet Layer) | 功能基本一致,使用 IP 协议 |
| 2 | 数据链路层(Data Link) | 节点间帧传输、错误检测、流量控制 | 链路层(Link Layer) | TCP/IP 链路层 ≈ OSI 数据链路层 + 物理层 |
| 1 | 物理层(Physical) | 传输原始比特流,定义电缆、电压、接口等物理特性 | 链路层(Link Layer) |
案例:

IP地址
每个Internet上的主机和路由器都有一个ip地址,它包括网络号和主机号,ip地址有ipv4和ipv6,可以通过ipconfig来查看
端口
这里的端口不是物理意义上的端口,式TCP/IP协议中的端口,是逻辑意义上的端口。
只要是做服务的程序,都必须监听一个端口,该端口就是其他程序和该服务通讯的通道,所以一个端口一旦呗某个程序监听,其他程序就不能在该端口监听。
注意:
- 0号为保留端口
- 1-1024为固定端口,也叫又名端口,被某些程序固定使用,一般程序员不使用:22–SSH远程登陆协议,23–telnet使用,21–ftp使用等等
- 1025-65535是动态端口程序员可以使用
- 尽可能少开端口。
netstat -an可以查看本机监听哪些端口,用netstat -anb来查看查看监听端口的pid,结合任务管理器关闭不安全的端口。
快速入门
流程
服务器端
- 监听端口
- 接收客户端的tcp链接,建立客户端和服务器端的链接
- 创建goroutine,处理链接的请求
客户端
- 建立与服务器的链接
- 发送请求数据,接受服务器端的返回结果数据
- 关闭链接
常用包
需求:
服务器端
- 写一个服务器端程序,在8888端口监听
- 可以和多个客户端创建链接
- 连接成功后,客户端可以发送数据,服务器端接收数据显示在终端上
- 使用telnet来测还是,然后编写客户端程序来测试
server.go
package main
import (
"fmt"
"net"
)
func process(conn net.Conn) {
/*循环接收数据*/
defer conn.Close() /*要及时关闭,要不一直不释放容易炸*/
for {
buf := make([]byte, 1024)
fmt.Printf("服务器等待%s输入\n", conn.RemoteAddr().String())
n, err := conn.Read(buf) /*等待客户端通过conn发送信息,如果客户端没有write,协程就阻塞在这里*/
if err != nil {
fmt.Println("服务器端Read err:", err)
return
}
/*显示发送的内容*/
fmt.Print(string(buf[:n]))
}
}
func main() {
fmt.Println("服务器开始监听")
listen, err := net.Listen("tcp", "0.0.0.0:8888")
/*使用tcp协议,监听8888端口*/
if err != nil {
fmt.Println("err:", err)
return
}
defer listen.Close()
/*循环等待客户端链接*/
for {
fmt.Println("等待连接ing")
conn, err := listen.Accept()
if err != nil {
fmt.Println("accepy err", err)
}
fmt.Printf("accept =%v 客户端Ip为:%v", conn, conn.RemoteAddr())
go process(conn)
}
}
客户端
- 链接服务器端的8888端口
- 客户端可以发送单行数据然后退出
- 能通过终端输入数据,输入一行发一行
- 在终端输入exit退出程序
client.go
package main
import (
"bufio"
"fmt"
"net"
"os"
"strings"
)
func main() {
conn, err := net.Dial("tcp", "127.0.0.1:8888")
if err != nil {
fmt.Println("client dial err = ", err)
return
}
/*获取一行*/
reader := bufio.NewReader(os.Stdin) /*os.Stdin表示标准输入(终端)*/
for {
line, err := reader.ReadString('\n')
if err != nil {
fmt.Println("readstring err:", err)
}
line = strings.Trim(line, "\n\r")
if line == "exit" {
fmt.Println("客户端退出")
break
}
/*发送*/
n, err := conn.Write([]byte(line + "\n"))
if err != nil {
fmt.Println("conn.Write err:", err)
}
fmt.Println(n)
}
}
结语
这里就只是简单讲解喵(后面在慢慢深入学习)










