Go語言實現TCP通信TCP通信
client端
一個TCP客戶端進行TCP通信的流程如下:
- 向指定ip和端口撥號,請求建立連接(Tcp或Udp)
- 進行數據收發(從終端和從服務端讀數據)
- 關閉鏈接
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)
for {
//從終端讀取數據(會以文件的形式)
line, err := reader.ReadString('\n')
if err != nil {
fmt.Println("readstring err=", err)
}
//如多用戶輸入exit就退出
line = strings.Trim(line, "\r\n")
if line == "exit" {
fmt.Println("客戶端退出")
return
}
//將line發給服務器
n, err := conn.Write([]byte(line + "\n"))
if err != nil {
fmt.Println("conn.Write err=", err)
}
fmt.Printf("發送了%d個字節\n",n)
//創建切片
buf := make([]byte, 1024)
//1 等待客戶端通過conn發送信息
//2 如果沒有writer發送就一直阻塞在這
n, err = conn.Read(buf)
if err != nil {
fmt.Println("服務器read err=", err) //出錯退出
return
}
//3. 顯示讀取內容到終端
fmt.Print(string(buf[:n]))
}
}
server端
server端TCP服務端程序的處理流程:
- 監聽端口
- 接收客戶端請求建立鏈接
- 創建goroutine處理鏈接(數據的收發)。
package main
import (
"bufio"
"fmt"
"net"
"os"
"strings"
)
func process(conn net.Conn) {
//循環接受客戶端發送數據,不讓協程退出
defer conn.Close() //關閉conn連接
for {
//創建切片
buf := make([]byte, 1024)
//1 等待客戶端通過conn發送信息
//2 如果沒有writer發送就一直阻塞
n, err := conn.Read(buf)
if err != nil {
fmt.Println("服務器read err=", err) //出錯退出
return
}
//3. 顯示讀取內容到終端
fmt.Print(string(buf[:n]))
//發送消息給客戶端
reader := bufio.NewReader(os.Stdin)
//從終端讀取數據(會以文件的形式)
line, err := reader.ReadString('\n')
if err != nil {
fmt.Println("readstring err=", err)
}
//如多用戶輸入exit就退出
line = strings.Trim(line, "\r\n")
if line == "exit" {
fmt.Println("客戶端退出")
return
}
//將line發給服務器
_, err = conn.Write([]byte(line + "\n"))
if err != nil {
fmt.Println("conn.Write err=", err)
}
}
}
func main() {
fmt.Println("服務器開始監聽------")
listen, err := net.Listen("tcp", "0.0.0.0:8888")
if err != nil {
fmt.Println("listen err=", err)
return
}
defer listen.Close() //延時關閉listen
for {
fmt.Println("-----等待客戶連接----")
conn, err := listen.Accept()
if err != nil {
fmt.Println("Accept err=", err)
} else {
fmt.Printf("Accept success con類型%T,客戶ip%v\n", conn, conn.RemoteAddr().String())
}
//這里要起一個協程
go process(conn)
}
}
上面的client和server只是對tcp通信進行了簡單的模擬,旨在聯系tcp的通信過程。
代碼還有個bug,就是client和server都只能收一句、發一句、收一句...交替進行,因為程序中收發是順序進行的,例如client,發送一次數據之后,程序就阻塞到了
n, err := conn.Read(buf)
這個位置,所以只有再server發送來數據並讀取后,才可以再次在終端輸入數據發送。