net
حزمة net القياسية في لغة Go هي مكتبة قوية جداً، فهي توفر وظائف للتعامل مع الاتصالات الشبكية، وعناوين IP، وتحليل DNS، وبروتوكولات TCP/UDP، وبروتوكول HTTP والمهام الشائعة الأخرى. وبسبب خصائص التزامن الأصلي في لغة Go، فإن التعامل مع الإدخال/الإخراج الشبكي في Go بسيط وفعال جداً.
تحليل العناوين
توفر Go أربع دوال لتحليل العناوين الشبكية، سيتم شرحها واحدة تلو الأخرى.
عنوان MAC
التوقيع
func ParseMAC(s string) (hw HardwareAddr, err error)مثال
package main
import (
"fmt"
"net"
)
func main() {
hw, err := net.ParseMAC("00:1A:2B:3C:4D:5E")
if err != nil {
panic(err)
}
fmt.Println(hw)
}CIDR
التوقيع
func ParseCIDR(s string) (IP, *IPNet, error)مثال
package main
import (
"fmt"
"log"
"net"
)
func main() {
ipv4Addr, ipv4Net, err := net.ParseCIDR("192.0.2.1/24")
if err != nil {
log.Fatal(err)
}
fmt.Println(ipv4Addr)
fmt.Println(ipv4Net)
}عنوان IP
عنوان IP يدعم تحليل ipv4 و ipv6، توقيع الدالة كالتالي
func ResolveIPAddr(network, address string) (*IPAddr, error)مثال الاستخدام كالتالي
package main
import (
"fmt"
"net"
)
func main() {
ipv4Addr, err := net.ResolveIPAddr("ip4", "192.168.2.1")
if err != nil {
panic(err)
}
fmt.Println(ipv4Addr)
ipv6Addr, err := net.ResolveIPAddr("ip6", "2001:0db8:85a3:0000:0000:8a2e:0370:7334")
if err != nil {
panic(err)
}
fmt.Println(ipv6Addr)
}عنوان TCP
عنوان TCP يدعم tcp4 و tcp6، التوقيع كالتالي
func ResolveTCPAddr(network, address string) (*TCPAddr, error)مثال الاستخدام كالتالي
package main
import (
"fmt"
"net"
)
func main() {
tcp4Addr, err := net.ResolveTCPAddr("tcp4", "0.0.0.0:2020")
if err != nil {
panic(err)
}
fmt.Println(tcp4Addr)
tcp6Addr, err := net.ResolveTCPAddr("tcp6", "[::1]:8080")
if err != nil {
panic(err)
}
fmt.Println(tcp6Addr)
}عنوان UDP
عنوان UDP يدعم udp4 و udp6، التوقيع كالتالي
func ResolveUDPAddr(network, address string) (*UDPAddr, error)مثال الاستخدام كالتالي
package main
import (
"fmt"
"net"
)
func main() {
udp4Addr, err := net.ResolveUDPAddr("udp4", "0.0.0.0:2020")
if err != nil {
panic(err)
}
fmt.Println(udp4Addr)
udp6Addr, err := net.ResolveUDPAddr("udp6", "[::1]:8080")
if err != nil {
panic(err)
}
fmt.Println(udp6Addr)
}عنوان Unix
عنوان Unix يدعم unix و unixgram و unixpacket، التوقيع كالتالي
func ResolveUnixAddr(network, address string) (*UnixAddr, error)مثال الاستخدام كالتالي
package main
import (
"fmt"
"net"
)
func main() {
unixAddr, err := net.ResolveUnixAddr("unix", "/tmp/mysocket")
if err != nil {
panic(err)
}
fmt.Println(unixAddr)
}DNS
توفر Go أيضاً العديد من الدوال لاستعلامات DNS، المثال التالي يحل عنوان IP لنطاق معين
package main
import (
"fmt"
"net"
)
func main() {
addrs, err := net.LookupHost("github.com")
if err != nil {
panic(err)
}
fmt.Println(addrs)
}الاستعلام عن قيمة السجل
package main
import (
"fmt"
"net"
)
func main() {
mxs, err := net.LookupMX("github.com")
if err != nil {
panic(err)
}
fmt.Println(mxs)
}البرمجة الشبكية
منطق برمجة tcp بسيط جداً، بالنسبة للعميل فهو
- إنشاء اتصال
- إرسال البيانات أو قراءتها
- الخروج
بالنسبة للخادم فهو
- الاستماع على عنوان
- الحصول على اتصال
- إنشاء goroutine جديد للتعامل مع هذا الاتصال
فيما يلي مثال بسيط، كود العميل
package main
import (
"net"
)
func main() {
// إنشاء اتصال
conn, err := net.Dial("tcp", "0.0.0.0:1234")
if err != nil {
panic(err)
}
defer conn.Close()
// إرسال البيانات
for i := range 10 {
_, err := conn.Write([]byte{'a' + byte(i)})
if err != nil {
panic(err)
}
}
}كود الخادم
package main
import (
"errors"
"fmt"
"io"
"net"
"sync"
)
func main() {
// الاستماع على العنوان
listener, err := net.Listen("tcp", "0.0.0.0:1234")
if err != nil {
panic(err)
}
defer listener.Close()
var wg sync.WaitGroup
for {
// انتظار حظري حتى إنشاء الاتصال التالي
conn, err := listener.Accept()
if err != nil {
panic(err)
}
// فتح goroutine جديد للتعامل مع هذا الاتصال بشكل غير متزامن
wg.Add(1)
go func() {
defer wg.Done()
buf := make([]byte, 4096)
for {
// قراءة البيانات من الاتصال
n, err := conn.Read(buf)
if errors.Is(err, io.EOF) {
break
} else if err != nil {
panic(err)
}
data := string(buf[:n])
fmt.Println(data)
}
}()
}
wg.Wait()
}العميل يرسل البيانات، والخادم يستقبل البيانات، هذا المثال بسيط جداً، عندما ينشئ الخادم اتصالاً جديداً، يحتاج فقط لفتح goroutine جديد للتعامل معه، دون الحاجة للحظر، وطريقة كتابة UDP متشابهة بشكل عام.
