一、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)
}
}