目录
1、TCP协议
TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的网络传输协议。它是互联网协议套件(TCP/IP)中的核心协议之一,用于在计算机网络中可靠地传输数据。
TCP 的特点和工作原理如下:
面向连接:在进行数据传输之前,发送方和接收方必须先建立一个连接。连接建立的过程包括三次握手,即发送方发送连接请求,接收方回复确认,最后发送方再次回复确认。连接建立后,双方可以通过该连接进行数据的传输。
可靠性:TCP 提供可靠的数据传输,确保数据按正确的顺序到达目的地。它使用序列号、确认应答和重传等机制来实现可靠性。如果接收方检测到丢失的数据或者乱序的数据,它会向发送方发送相应的确认应答,并要求发送方重新发送。
字节流传输:TCP 将数据视为一连串的字节流,而不是分割成固定长度的包。发送方将数据分割成适当大小的数据块,并将它们封装在 TCP 报文段中发送。接收方负责重新组装报文段,以便恢复原始的数据流。
拥塞控制:TCP 实现了拥塞控制机制,用于避免网络拥塞并确保网络资源的公平共享。通过动态调整发送速率,TCP 可以在网络拥塞时减少数据的发送量,以防止丢包和性能下降。
基于 IP:TCP 是建立在 IP 协议之上的。它使用 IP 协议提供的网络传输服务来实现数据的可靠传输,同时还提供了自己的可靠性机制。
TCP 在应用层和传输层之间起到重要的桥梁作用,它为应用程序提供了一种可靠的、面向连接的数据传输方式。许多常见的应用层协议(如 HTTP、FTP、SMTP 等)都基于 TCP 来进行数据传输。
2、TCP服务端
下面是一个简单的TCP服务器端的工作流程:
创建Socket:服务器端首先创建一个Socket对象,用于监听客户端的连接请求。在Socket创建时,需要指定IP地址和端口号。
绑定地址和端口:服务器端将Socket绑定到一个特定的IP地址和端口上,以便客户端能够找到服务器并连接。通常服务器应该选择一个固定的、不会与其他服务冲突的端口号。
监听连接:服务器调用监听函数,开始等待客户端的连接请求。监听函数会进入阻塞状态,直到有新的连接请求到达。一般使用
listen
函数来启动监听。接受连接:当有客户端连接请求到达时,服务器通过
accept
函数接受连接,并创建一个新的Socket对象与客户端进行通信。服务器可以通过这个新的Socket对象与客户端进行数据交换。数据交换:一旦连接建立,服务器和客户端之间可以通过读取和写入Socket来进行数据的传输和交换。服务器可以接收客户端发送的数据,并根据协议进行处理和回复。
关闭连接和释放资源:当通信结束时,服务器端可以调用
close
函数关闭连接,释放相关的资源,并通知客户端连接已关闭。通常情况下,服务器会通过循环来接受多个客户端的连接请求。
需要注意的是,服务器端可能需要使用多线程或者多进程来处理多个客户端的并发连接。这样可以同时为多个客户端提供服务,而不阻塞其他客户端的连接请求。
Go语言的net包实现的TCP服务端代码如下:
package main
import (
"bufio"
"fmt"
"net"
)
// 处理函数
func process(conn net.Conn) {
defer conn.Close() // 关闭连接
for {
reader := bufio.NewReader(conn)
var buf [128]byte
n, err := reader.Read(buf[:]) // 读取数据
if err != nil {
fmt.Println("read from client failed, err:", err)
break
}
recvStr := string(buf[:n])
fmt.Println("收到client端发来的数据:", recvStr)
conn.Write([]byte(recvStr)) // 发送数据
}
}
func main() {
listen, err := net.Listen("tcp", "127.0.0.1:20000")
if err != nil {
fmt.Println("listen failed, err:", err)
return
}
for {
conn, err := listen.Accept() // 建立连接
if err != nil {
fmt.Println("accept failed, err:", err)
continue
}
go process(conn) // 启动一个goroutine处理连接
}
}
3、TCP客户端
使用Go语言的net包实现的TCP客户端代码如下:
package main
import (
"bufio"
"fmt"
"net"
"os"
"strings"
)
// 客户端
func main() {
conn, err := net.Dial("tcp", "127.0.0.1:20000")
if err != nil {
fmt.Println("err :", err)
return
}
defer conn.Close() // 关闭连接
inputReader := bufio.NewReader(os.Stdin)
for {
input, _ := inputReader.ReadString('\n') // 读取用户输入
inputInfo := strings.Trim(input, "\r\n")
if strings.ToUpper(inputInfo) == "Q" { // 如果输入q就退出
return
}
_, err = conn.Write([]byte(inputInfo)) // 发送数据
if err != nil {
return
}
buf := [512]byte{}
n, err := conn.Read(buf[:])
if err != nil {
fmt.Println("recv failed, err:", err)
return
}
fmt.Println(string(buf[:n]))
}
}