欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Golang TCP網絡編程的具體實現(xiàn)

 更新時間:2024年06月13日 09:34:25   作者:2021dragon  
go語言是一門功能強大的編程語言,它提供了眾多的網絡編程庫,其中包括tcp/ip,本文主要介紹了Golang TCP網絡編程的具體實現(xiàn),具有一定的參考價值,感興趣的可以來了解一下

網絡編程介紹

網絡編程介紹

  • 網絡編程是指通過計算機網絡實現(xiàn)程序間通信的一種編程技術,涉及到在不同計算機之間建立連接、傳輸數據和協(xié)議解析等操作。
  • 套接字(Socket)編程是網絡編程的一種實現(xiàn)方式,其提供了一種機制,使得應用程序能夠通過網絡進行數據傳輸和通信。
  • Go中的net包是標準庫中提供的網絡編程包,是基于套接字編程的一種實現(xiàn)方式,提供了對TCP、UDP、IP、ICMP、Unix域套接字等常見網絡協(xié)議的支持,通過net包可以完成創(chuàng)建套接字、建立連接、發(fā)送和接收數據等操作,實現(xiàn)網絡通信。

TCP網絡編程

服務器監(jiān)聽

服務器監(jiān)聽

在Go的net包中,Listen函數用于創(chuàng)建并返回一個網絡監(jiān)聽器(Listener),以監(jiān)聽指定網絡地址和端口上的連接請求。該函數的函數原型如下:

func Listen(network, address string) (Listener, error)

參數說明:

  • network:用于指定網絡類型,其值必須是"tcp", “tcp4”, “tcp6”, “unix"或"unixpacket”。
  • address:用于指定需要被監(jiān)聽的IP地址和端口號,格式為"host:port"。

返回值說明:

  • 第一個返回值:表示創(chuàng)建的網絡監(jiān)聽器。
  • 第二個返回值:如果創(chuàng)建網絡監(jiān)聽器過程中出錯,將返回非nil的錯誤值。

通過Listen函數創(chuàng)建得到的網絡監(jiān)聽器是Listener類型的,該類型是一個接口類型,其定義如下:

type Listener interface {
	// Accept waits for and returns the next connection to the listener.
	Accept() (Conn, error)

	// Close closes the listener.
	// Any blocked Accept operations will be unblocked and return errors.
	Close() error

	// Addr returns the listener's network address.
	Addr() Addr
}

Listener接口中各方法說明:

  • Accept方法:從底層獲取下一個已經建立好的連接給監(jiān)聽器。
  • Close方法:關閉監(jiān)聽器。
  • Addr方法:返回監(jiān)聽器對應的網絡地址(由IP地址和端口號組成)。

當使用Listen函數創(chuàng)建TCP類型的監(jiān)聽器時,其返回的監(jiān)聽器底層具體的類型是TCPListener,其定義如下:

type TCPListener struct {
	fd *netFD
	lc ListenConfig
}

TCPListener結構體各字段說明:

  • fd:對底層網絡文件描述符的封裝,提供了對網絡連接的讀寫和控制操作。
  • lc:用于配置監(jiān)聽器創(chuàng)建的行為,比如設置監(jiān)聽地址、控制網絡參數等。

TCPListener結構體中的fd字段是netFD類型的,其定義如下:

type netFD struct {
	pfd poll.FD

	// immutable until Close
	family      int
	sotype      int
	isConnected bool // handshake completed or use of association with peer
	net         string
	laddr       Addr
	raddr       Addr
}

netFD結構體各字段說明:

  • pfd:用于與底層的操作系統(tǒng)文件描述符進行交互。
  • family:表示套接字的協(xié)議家族,比如IPv4或IPv6。
  • sotype:表示套接字的類型,比如TCP或UDP
  • isConnected:表示連接是否已完成握手或與對方建立關聯(lián)。
  • net:表示網絡協(xié)議,比如"tcp"或"udp"。
  • laddr:表示本地網絡連接的地址。
  • raddr:表示遠程網絡連接的地址。

服務器監(jiān)聽示例

服務器監(jiān)聽示例如下:

package main

import (
	"fmt"
	"net"
)

func main() {
	// 服務器監(jiān)聽
	listen, err := net.Listen("tcp", "0.0.0.0:8081")
	if err != nil {
		fmt.Printf("listen error, err = %v\n", err)
		return
	}
	defer listen.Close()
	fmt.Println("listen success...")
}

說明一下:

  • 服務器在創(chuàng)建監(jiān)聽套接字時,將其綁定到0.0.0.0(通常表示為INADDR_ANY)地址,這樣服務器就可以同時監(jiān)聽和接受來自不同網絡接口的連接請求,而不需要為每個接口分別創(chuàng)建監(jiān)聽套接字。
  • 為了避免網絡文件描述符資源泄露,在創(chuàng)建監(jiān)聽器后及時利用defer機制關閉監(jiān)聽器。監(jiān)聽器被關閉后會停止監(jiān)聽新的連接請求,并且任何被阻塞的Accept操作都會被解除阻塞并返回錯誤。

客戶端連接服務器

客戶端連接服務器

在Go的net包中,Dial函數用于客戶端應用程序與遠程服務器建立連接。該函數的函數原型如下:

func Dial(network, address string) (Conn, error)

參數說明:

  • network:用于指定網絡協(xié)議,比如"tcp", "udp"等。
  • address:用于指定連接的目標地址。

返回值說明:

  • 第一個返回值:表示建立的網絡連接。
  • 第二個返回值:如果建立網絡連接過程中出錯,將返回非nil的錯誤值。

通過Dial函數建立得到的連接Conn類型的,該類型是一個接口類型,其定義如下:

type Conn interface {
	// Read reads data from the connection.
	Read(b []byte) (n int, err error)

	// Write writes data to the connection.
	Write(b []byte) (n int, err error)

	// Close closes the connection.
	// Any blocked Read or Write operations will be unblocked and return errors.
	Close() error

	// LocalAddr returns the local network address, if known.
	LocalAddr() Addr

	// RemoteAddr returns the remote network address, if known.
	RemoteAddr() Addr

	// SetDeadline sets the read and write deadlines associated
	// with the connection. It is equivalent to calling both
	// SetReadDeadline and SetWriteDeadline.
	SetDeadline(t time.Time) error

	// SetReadDeadline sets the deadline for future Read calls
	// and any currently-blocked Read call.
	SetReadDeadline(t time.Time) error

	// SetWriteDeadline sets the deadline for future Write calls
	// and any currently-blocked Write call.
	SetWriteDeadline(t time.Time) error
}

Conn接口中各方法說明:

  • Read方法:從連接中讀取數據。
  • Write方法:向連接中寫入數據。
  • Close方法:關閉連接。
  • LocalAddr方法:返回連接對應的本地網絡地址(由IP地址和端口號組成)。
  • RemoteAddr方法:返回連接對應的遠程網絡地址(由IP地址和端口號組成)。
  • SetDeadline方法:設置連接讀取和寫入的截止時間。
  • SetReadDeadline方法:設置連接讀取的截止時間。
  • SetWriteDeadline方法:設置連接寫入的截止時間。

當使用Dial函數與TCP服務器建立連接時,其返回的網絡連接底層具體的類型是TCPConn,其定義如下:

type TCPConn struct {
	conn
}

TCPConn結構體中僅嵌套了一個conn類型的匿名結構體,其定義如下:

type conn struct {
	fd *netFD
}

可以看到,conn結構體中的fd字段與TCPListener結構體中的fd字段的類型相同,它們都是對底層網絡文件描述符的封裝,提供了對網絡連接的讀寫和控制操作。

客戶端連接服務器示例

客戶端連接服務器示例如下:

package main

import (
	"fmt"
	"net"
)

func main() {
	// 客戶端連接服務器
	conn, err := net.Dial("tcp", "127.0.0.1:8081")
	if err != nil {
		fmt.Printf("connect server error, err = %v\n", err)
		return
	}
	defer conn.Close()
	fmt.Println("connect server success...")
}

說明一下:

  • 當客戶端連接TCP服務器時,服務器必須處于監(jiān)聽狀態(tài)。
  • 為了避免網絡文件描述符資源泄露,客戶端在與服務器建立連接后及時利用defer機制關閉連接。

服務端獲取連接

服務端獲取連接

在創(chuàng)建TCP網絡監(jiān)聽器后,調用Listener接口的Accept方法,本質調用的是TCPListener的Accept方法,該方法用于從底層獲取下一個已經建立好的連接給監(jiān)聽器,如果底層沒有建立好的連接則會進行阻塞等待。該方法的原型如下:

func (l *TCPListener) Accept() (Conn, error)

返回值說明:

  • 第一個返回值:表示獲取到的與客戶端建立好的連接。
  • 第二個返回值:如果在獲取連接過程中出錯,將返回非nil的錯誤值。

服務端獲取連接示例

服務端獲取連接示例如下:

package main

import (
	"fmt"
	"net"
)

func process(conn net.Conn) {
	defer conn.Close()

	fmt.Printf("handle a link %v...\n", conn.RemoteAddr())
}

func main() {
	// 服務器監(jiān)聽
	listen, err := net.Listen("tcp", "0.0.0.0:8081")
	if err != nil {
		fmt.Printf("listen error, err = %v\n", err)
		return
	}
	defer listen.Close()
	fmt.Println("listen success...")

	for {
		fmt.Println("waiting client connect...")
		// 服務端獲取連接
		conn, err := listen.Accept()
		if err != nil {
			fmt.Printf("accept error, err = %v\n", err)
			continue
		}
		fmt.Printf("get a link from %v...\n", conn.RemoteAddr())
		// 開啟新協(xié)程為客戶端提供服務
		go process(conn)
	}
}

說明一下:

  • 網絡監(jiān)聽器的任務就是不斷調用Accept方法,從底層獲取已經建立好的連接并為其提供服務,通常在獲取到一個連接后會開啟一個新協(xié)程為其提供服務,而主協(xié)程則繼續(xù)調用Accept方法獲取新的連接。
  • 為了讓新協(xié)程能夠獲取需要被處理的連接,需要將對應的連接通過參數傳遞的方式,傳遞給協(xié)程對應的處理函數。此外,為了避免網絡文件描述符資源泄露,需要在處理函數中利用defer機制關閉連接,保證連接處理完畢后能夠及時關閉連接。

向連接中寫入數據

向連接中寫入數據

在創(chuàng)建TCP連接后,調用Conn接口的Write方法,本質調用的是TCPConn的Write方法,該方法用于向連接中寫入數據。該方法的原型如下:

func (c *TCPConn) Write(b []byte) (int, error)

參數說明:

  • b:表示要寫入連接的數據。

返回值說明:

  • 第一個返回值:表示實際寫入的字節(jié)數。
  • 第二個返回值:如果在寫入數據過程中出錯,將返回非nil的錯誤值。

從連接中讀取數據

從連接中讀取數據

在創(chuàng)建TCP連接后,調用Conn接口的Read方法,本質調用的是TCPConn的Read方法,該方法用于從連接中讀取數據。該方法的原型如下:

func (c *TCPConn) Read(b []byte) (int, error)

參數說明:

  • b:輸出型參數,用于存儲讀取到的數據。

返回值說明:

  • 第一個返回值:表示實際讀取的字節(jié)數。
  • 第二個返回值:如果在讀取數據過程中出錯,將返回非nil的錯誤值。

關閉連接/監(jiān)聽器

關閉連接/監(jiān)聽器

為了避免網絡文件描述符泄露,TCP網絡監(jiān)聽器和TCP連接在使用完畢后都需要及時將其關閉,對應調用的分別是TCPListener和TCPConn的Close方法,這兩個方法的原型如下:

func (l *TCPListener) Close() error
func (c *TCPConn) Close() error

返回值說明:

  • 如果在關閉監(jiān)聽器或關閉連接過程中出錯,將返回非nil的錯誤值。

簡易的TCP回聲服務器

效果展示

效果展示

為了演示使用net包實現(xiàn)網絡通信,下面實現(xiàn)了一個簡易的TCP回聲服務器,其功能如下:

  • 服務端能夠同時處理多個客戶端的連接請求,在為每個客戶端提供服務時,能夠將各個客戶端發(fā)來的數據顯示在服務端,同時將客戶端發(fā)來的數據再發(fā)回給客戶端。
  • 客戶端在連接到服務器后,能夠不斷從控制臺讀取用戶輸入的數據發(fā)送給服務端,并將服務端發(fā)來的數據顯示在客戶端,用戶在控制臺輸入exit能夠退出客戶端。

最終效果如下:

在這里插入圖片描述

服務端處理邏輯

服務端處理邏輯

服務端處理邏輯如下:

  • 主協(xié)程調用Listen函數完成服務器的監(jiān)聽后,通過監(jiān)聽器不斷調用Accept方法從底層獲取已經建立好的連接,并為每一個獲取到的連接創(chuàng)建一個新協(xié)程為其提供服務,而主協(xié)程則繼續(xù)獲取新的連接。
  • 每個新協(xié)程在為其對應的連接提供服務時,通過調用連接的Read方法不斷讀取客戶端發(fā)來的數據,將數據其顯示在服務端,同時通過調用連接的Write方法將客戶端發(fā)來的數據再發(fā)回給客戶端。
  • 每個新協(xié)程在為其對應的連接提供服務的過程中,如果從連接中讀取數據或向連接中寫入數據時出錯,或是客戶端退出,則通過調用連接的Close方法將對應的連接關閉。

服務端代碼如下:

package main

import (
	"fmt"
	"io"
	"net"
)

func process(conn net.Conn) {
	defer conn.Close()

	data := make([]byte, 1024)
	for {
		// 1、讀取客戶端發(fā)來的數據
		n, err := conn.Read(data)
		if err != nil {
			if err == io.EOF {
				fmt.Printf("client %v quit\n", conn.RemoteAddr())
			} else {
				fmt.Printf("read client message error, err = %v\n", err)
			}
			return
		}
		fmt.Printf("client message[%v]: %v\n", conn.RemoteAddr(), string(data[:n]))

		// 2、發(fā)送數據給客戶端
		len, err := conn.Write(data[:n])
		if err != nil || len != n {
			fmt.Printf("send back message error, err = %v\n", err)
			return
		}
	}
}

func main() {
	// 服務器監(jiān)聽
	listen, err := net.Listen("tcp", "0.0.0.0:8081")
	if err != nil {
		fmt.Printf("listen error, err = %v\n", err)
		return
	}
	defer listen.Close()
	fmt.Println("listen success...")

	for {
		fmt.Println("waiting client connect...")
		// 服務端獲取連接
		conn, err := listen.Accept()
		if err != nil {
			fmt.Printf("accept error, err = %v\n", err)
			continue
		}
		fmt.Printf("get a link from %v...\n", conn.RemoteAddr())
		// 開啟新協(xié)程為客戶端提供服務
		go process(conn)
	}
}

說明一下:

  • 當服務端從某個連接中讀取數據時,如果該連接對應的客戶端已經將連接關閉,那么服務端的讀操作將會返回io.EOF錯誤。

客戶端處理邏輯

客戶端處理邏輯

客戶端處理邏輯如下:

  • 客戶端在調用Dial函數與服務端建立連接后,不斷讀取用戶的輸入,通過調用連接Write方法將用戶輸入的數據發(fā)送給服務端,然后通過調用連接的Read方法讀取服務端發(fā)來的數據并顯示在客戶端,如果用戶輸入exit則調用連接的Close方法將連接關閉。

客戶端代碼如下:

package main

import (
	"bufio"
	"fmt"
	"net"
	"os"
)

func main() {
	// 客戶端連接服務器
	conn, err := net.Dial("tcp", "127.0.0.1:8081")
	if err != nil {
		fmt.Printf("connect server error, err = %v\n", err)
		return
	}
	defer conn.Close()
	fmt.Println("connect server success...")

	reader := bufio.NewReader(os.Stdin)
	data := make([]byte, 1024)
	for {
		// 1、讀取用戶輸入
		str, err := reader.ReadString('\n')
		if err != nil {
			fmt.Printf("read input error, err = %v\n", err)
			continue
		}
		str = str[:len(str)-2] // 去掉\r\n
		if str == "exit" {
			fmt.Printf("exit success...")
			break
		}

		// 2、發(fā)送數據給服務端
		n, err := conn.Write([]byte(str))
		if err != nil || n != len(str) {
			fmt.Printf("send message error, err = %v\n", err)
			continue
		}
		fmt.Printf("send %d byte message to server...\n", n)

		// 3、讀取服務端發(fā)來的數據
		n, err = conn.Read(data)
		if err != nil {
			fmt.Printf("read message error, err = %v\n", err)
			continue
		}
		fmt.Printf("server message: %v\n", string(data[:n]))
	}
}

說明一下:

  • Stdin、Stdout和Stderr是os包中的全局變量,分別表示標準輸入流、標準輸出流和標準錯誤流。
  • 客戶端在讀取用戶輸入時,通過bufio包中的Reader,以帶緩沖的方式每次從標準輸入流中讀取一行數據。
  • Windows系統(tǒng)中通常使用\r\n作為換行符,因此客戶端在每次讀取一行用戶輸入的數據后需要將末尾的兩個字符去掉。

到此這篇關于Golang TCP網絡編程的具體實現(xiàn)的文章就介紹到這了,更多相關Golang TCP網絡編程內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家! 

相關文章

  • Golang跨平臺GUI框架Fyne的使用教程詳解

    Golang跨平臺GUI框架Fyne的使用教程詳解

    Go 官方沒有提供標準的 GUI 框架,在 Go 實現(xiàn)的幾個 GUI 庫中,Fyne 算是最出色的,它有著簡潔的API、支持跨平臺能力,且高度可擴展,下面我們就來看看它的具體使用吧
    2024-03-03
  • Go語言fmt.Sprintf格式化輸出的語法與實例

    Go語言fmt.Sprintf格式化輸出的語法與實例

    Go 可以使用 fmt.Sprintf 來格式化字符串,下面這篇文章主要給大家介紹了關于Go語言fmt.Sprintf格式化輸出的語法與實例,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-07-07
  • Go語言CSP并發(fā)模型實現(xiàn)MPG

    Go語言CSP并發(fā)模型實現(xiàn)MPG

    這篇文章主要為大家介紹了Go語言CSP并發(fā)模型實現(xiàn)MPG圖文詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-05-05
  • 關于升級go1.18的goland問題詳解

    關于升級go1.18的goland問題詳解

    作為一個go語言程序員,覺得自己有義務為go新手開一條更簡單便捷的上手之路,下面這篇文章主要給大家介紹了關于升級go1.18的goland問題的相關資料,需要的朋友可以參考下
    2022-11-11
  • Golang構建WebSocket服務器和客戶端的示例詳解

    Golang構建WebSocket服務器和客戶端的示例詳解

    這篇文章主要為大家詳細介紹了如何使用Go語言構建WebSocket服務器和客戶端,以實現(xiàn)雙向通信,文中的示例代碼講解詳細,需要的小伙伴可以參考一下
    2023-11-11
  • golang使用swagger的過程詳解

    golang使用swagger的過程詳解

    這篇文章主要介紹了golang使用swagger的過程詳解,本文給大家介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧
    2024-06-06
  • 基于Go和Gin的環(huán)境配置方法

    基于Go和Gin的環(huán)境配置方法

    今天小編就為大家分享一篇基于Go和Gin的環(huán)境配置方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-07-07
  • 從淺入深帶你掌握Golang數據結構map

    從淺入深帶你掌握Golang數據結構map

    在?Go?語言中,map?是一種非常常見的數據類型,它可以用于快速地檢索數據。本篇文章將介紹?Go?語言中的?map,包括?map?的定義、初始化、操作和優(yōu)化,需要的可以參考一下
    2023-04-04
  • Go中調用JS代碼(otto)的實現(xiàn)示例

    Go中調用JS代碼(otto)的實現(xiàn)示例

    Otto是一個用Go語言實現(xiàn)的JavaScript解釋器,可用于執(zhí)行和操作JavaScript代碼,適合在Go項目中執(zhí)行簡單的JS腳本,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-10-10
  • 使用go實現(xiàn)刪除sql里面的注釋和字符串功能(demo)

    使用go實現(xiàn)刪除sql里面的注釋和字符串功能(demo)

    這篇文章主要介紹了使用go實現(xiàn)刪除sql里面的注釋和字符串功能,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11

最新評論