一、TCP/UDP協議
TCP (Transmission Control Protocol)和UDP(User Datagram Protocol)協議屬於傳輸層協議。其中TCP提供IP環境下的數據可靠傳輸,它提供的服務包括數據流傳送、可靠性、有效流控、全雙工操作和多路複用。通過面向連接、端到端和可靠的數據包發送。通俗說,它是事先爲所發送的數據開闢出連接好的通道,然後再進行數據發送;而UDP則不爲IP提供可靠性、 流控或差錯恢復功能。一般來說,TCP對應的是可靠性要求高的應用,而UDP對應的則是可靠性要求低、傳輸流量大,傳輸速度快的應用
TCP支持的應用協議主要 有:Telnet、FTP、SMTP等;UDP支持的應用層協議主要有:NFS(網絡文件系統)、SNMP(簡單網絡管理協議)、DNS(主域名稱系 統)、TFTP(通用文件傳輸協議)等。
TCP/IP協議與低層的數據鏈路層和物理層無關,這也是TCP/IP的重要特點。
二、TCP 和 UDP 區別
- 面向連接vs無連接
TCP 有三次握手的連接過程,UDP 適合消息的多播發布,從單個點向多個點傳輸消息。 - 可靠性
TCP 利用握手, 確認(ACK) 和重傳的機制,提供了可靠性保證,而 UDP 可能丟失,不知道到底有沒有接收。 - 有序性
TCP 利用序列號保證了消息包的的順序交付,到達可能無序,但 TCP 會排序。 - 速度
TCP 速度比較慢,因爲要創建連接,保證消息的可靠性和有序性等,需要做額外的很多事情,UDP 更適合對速度比較敏感的應用,比如在線視頻媒體,電視廣播,多人在線遊戲等。 - 頭字節大小
TCP 20字節,UDP 8字節
三、 Go語言TCP客戶端與服務端實現
Go語言實現的tcp服務端通信模型
TCPServer
package main
import (
"fmt"
"io"
"net"
"os"
)
func main(){
//服務器端一般不定位具體的客戶端套接字
tcpaddr, err := net.ResolveTCPAddr("tcp",":8848")
if err != nil {
fmt.Fprintf(os.Stderr,"Server ResolveTCPAddr fail,err :%v", err)
return
}
serverfd, err := net.ListenTCP("tcp",tcpaddr)
if err != nil {
fmt.Fprintf(os.Stderr,"Server ListenTCP fail,err :%v", err)
return
}
defer serverfd.Close()
for{
conn, err := serverfd.AcceptTCP()
if err != nil {
fmt.Fprintf(os.Stderr,"Server Accept fail,err :%v",err)
return
}
go handleClient(conn)
}
}
func handleClient(conn net.Conn){
defer conn.Close()
fmt.Printf("Welcome %v connect",conn.RemoteAddr().String())
for{
buf := make([]byte,1024)
_, err := conn.Read(buf)
if err != nil{
fmt.Fprintf(os.Stderr,"Server read fail,err: %v",err)
break
}
fmt.Printf("Read Buf:%s",string(buf))
_, err = conn.Write(buf)
if err != nil {
fmt.Fprintf(os.Stderr,"Server write fail")
break
}
}
}
Go server端程序模型爲:
//go-tcpsock/server.go
func HandleConn(conn net.Conn) {
defer conn.Close()
for {
// read from the connection
// ... ...
// write to the connection
//... ...
}
}
func main() {
listen, err := net.Listen("tcp", ":8888")
if err != nil {
fmt.Println("listen error: ", err)
return
}
for {
conn, err := listen.Accept()
if err != nil {
fmt.Println("accept error: ", err)
break
}
// start a new goroutine to handle the new connection
go HandleConn(conn)
}
}
Go語言實現的TCP客戶端通信模型
TCPClient
package main
import (
"bufio"
"fmt"
"net"
"os"
)
func main(){
tcpaddr, err := net.ResolveTCPAddr("tcp","127.0.0.1:8848")
if err != nil {
fmt.Fprintf(os.Stderr,"Client ResolveTCPAddr fail, err: %v",err)
return
}
conn, err := net.DialTCP("tcp",nil,tcpaddr)
if err != nil {
fmt.Fprintf(os.Stderr,"Client DialTCP fail, err: %v",err)
return
}
defer conn.Close()
reader := bufio.NewReader(os.Stdin)
for{
buf, err := reader.ReadString('\n')
if err != nil{
fmt.Fprintf(os.Stderr,"ReadString fail,err :%v",err)
return
}
_, err = conn.Write([]byte(buf))
if err != nil {
fmt.Fprintf(os.Stderr,"Write fail,err: %v",err)
return
}
//readBuf 記住需要分配內存
readBuf := make([]byte,1024)
_, err = conn.Read(readBuf)
if err != nil {
fmt.Fprintf(os.Stderr,"Read fail,err :%v",err)
return
}
fmt.Printf("read buf:%s\n",string(readBuf))
}
}
四、Go語言UDP服務端與客戶端實現
Go語言udp服務端實現
package main
import (
"fmt"
"net"
"os"
)
func main() {
addr, err := net.ResolveUDPAddr("udp", ":8848")
if err != nil {
fmt.Fprintf(os.Stderr, "udp server ResolveUDPAddr fail,err :%v", err)
return
}
conn, err := net.ListenUDP("udp", addr)
if err != nil {
fmt.Fprintf(os.Stderr, "udp server ListenUDP fail,err :%v", err)
return
}
defer conn.Close()
for {
buf := make([]byte, 1024)
_, clientAddr, err := conn.ReadFromUDP(buf)
if err != nil {
fmt.Fprintf(os.Stderr, "udp server ReadFromUDP fail,err: %v", err)
continue
}
fmt.Printf("Recv Msg:%s\n", string(buf))
go func() {
_, err = conn.WriteToUDP(buf, clientAddr)
if err != nil {
fmt.Printf("udp server WriteToUDP fail,err: %v\n", err)
return
}
}()
}
}
Go語言udp客戶端實現
package main
import (
"bufio"
"fmt"
"net"
"os"
)
func main(){
if len(os.Args) != 2 {
fmt.Fprintf(os.Stderr,"Usage:%v host:port",os.Args[0])
return
}
addr, err := net.ResolveUDPAddr("udp",os.Args[1])
if err != nil {
fmt.Fprintf(os.Stderr,"udp client ResolveUDPAddr fail,err :%v",err)
return
}
conn, err := net.DialUDP("udp",nil,addr)
if err != nil {
fmt.Fprintf(os.Stderr,"udp client DialUDP fail,err :%v",err)
return
}
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
buf := scanner.Text()
fmt.Printf("input buf:%s\n",buf)
_, err := conn.Write([]byte(buf))
if err != nil {
fmt.Fprintf(os.Stderr,"udp client Write fail,err :%v",err)
return
}
readBuf := make([]byte,1024)
_, err = conn.Read(readBuf)
if err != nil{
fmt.Fprintf(os.Stderr,"udp client read fail,err :%v",err)
return
}
fmt.Printf("Read buf:%s\n",readBuf)
}
}