---
# System prepended metadata

title: 網路編程基本技術
tags: [觀念重點區]

---

# 網路編程基本技術
![](https://hackmd.io/_uploads/HkcSl3ob6.png)
https://www.youtube.com/watch?v=P6SZLcGE4us&ab_channel=ByteByteGo
## TCP IP UDP
https://www.youtube.com/watch?v=Iuvjwrm_O5g


https://blog.csdn.net/freekiteyu/article/details/72236734
![](https://i.imgur.com/asiBMFt.png)

## ip


ip是osi 會自動帶入的
然後lb例如nginx自動帶入到 x-forward
所以我們要抓第一個

```
func ParseIP(ctx context.Context, positionWithZeroBase int) (net.IP, error) {
	md, ok := metadata.FromIncomingContext(ctx)
	if !ok {
		return nil, errors.New("ParseIP: failed to read metadata")
	}

	ips, err := getIPStringFromMetadata(md, positionWithZeroBase)
	if err != nil {
		return nil, err
	}

	log.Debug("ParseIP from md: ", ips)
	ipValue, err := getIPValue(ctx, ips)
	if err != nil {
		return nil, err
	}

	ip := net.ParseIP(ipValue)
	if ip == nil {
		return nil, errors.New("ParseIP: invalid IP address")
	}

	return ip, nil
}

func getIPStringFromMetadata(md metadata.MD, positionWithZeroBase int) ([]string, error) {
	check := md.Get("x-forwarded-for")
	if len(check) < 1 {
		return []string{}, errors.New("ParseIP: no IP found")
	}

	ips := strings.Split(check[0], ",")
	if len(ips)-1 < positionWithZeroBase {
		return []string{}, errors.New("ParseIP: no IP in specific position")
	}

	return ips, nil
}

func getIPValue(ctx context.Context, ips []string) (string, error) {
	for i, ip := range ips {
		isGoogle, err := IsGoogleLoadBalancerIP(ip)
		if err != nil {
			return "", fmt.Errorf("ParseIP: IsGoogleLoadBalancerIP: %v: %v", ip, err)
		}
		if isGoogle {
			if i > 0 {
				return strings.Split(ips[i-1], ":")[0], nil
			}
			break
		}
	}
	peerMd, ok := peer.FromContext(ctx)
	if !ok {
		return "", errors.New("ParseIP: failed to read peer data")
	}
	return strings.Split(peerMd.Addr.String(), ":")[0], nil
}
```

抓google白名單
```
package gocom

import (
	"errors"
	"fmt"
	"net"
	"regexp"
	"strings"
	"sync"

	"github.com/lctech-tw/face-front-api/pkg/iprange"
)

var gcpTxtRecordAll []string
var gcpTxtRecordOnce sync.Once
var gcpIpRangeAll []string
var gcpIsDeveloperTriggered bool

// ErrGcpMustLookup usually panic to alert developers to lookup and make sure the system is secured by correct Google IP Range.
var ErrGcpMustLookup = errors.New("Developers are responsible to call LookupGoogleIPs prior to Application execution")

// LookupGoogleIPs loads IP range from _cloud-eoips.googleusercontent.com and store them in memory to prevent Ddos of dns lookup.
// According to https://cloud.google.com/load-balancing/docs/negs/internet-neg-concepts#authenticating_requests,
// https://cloud.google.com/load-balancing/docs/https#x-forwarded-for_header
func LookupGoogleIPs(moreIpRange []string) (err error) {
	gcpTxtRecordOnce.Do(func() {
		gcpTxtRecordAll, err = net.LookupTXT("_cloud-eoips.googleusercontent.com")
		if err != nil {
			err = fmt.Errorf("LookupGoogleIPs: %v", err)
			return
		}

		for _, txt := range gcpTxtRecordAll {
			finder, errRegex := regexp.Compile(`ip4:([^ ]+)`)
			if err != nil {
				err = fmt.Errorf("failed to detect GCP IP: %v", errRegex)
				return
			}
			for _, ipCIDR := range finder.FindAllStringSubmatch(txt, -1) {
				gcpIpRangeAll = append(gcpIpRangeAll, ipCIDR[1])
			}
		}

		// according to https://cloud.google.com/load-balancing/docs/https#x-forwarded-for_header
		gcpIpRangeAll = append(gcpIpRangeAll, "130.211.0.0/22", "35.191.0.0/16")
		if len(moreIpRange) > 0 {
			gcpIpRangeAll = append(gcpIpRangeAll, moreIpRange...)
		}
		gcpIsDeveloperTriggered = true
	})
	return
}

func GetGoogleIpRangeAll() []string {
	if gcpIsDeveloperTriggered == false {
		panic(ErrGcpMustLookup)
	}
	return gcpIpRangeAll
}

func IsGoogleLoadBalancerIP(ipStr string) (result bool, err error) {
	if gcpIsDeveloperTriggered == false {
		err = ErrGcpMustLookup
		return
	}
	ipStr = strings.TrimSpace(ipStr)
	ipAddr := net.IP{}
	err = ipAddr.UnmarshalText([]byte(ipStr))
	if err != nil {
		err = fmt.Errorf("IsGoogleLoadBalancerIP:invalid:%v", err)
		return
	}
	for _, ipr := range GetGoogleIpRangeAll() {
		r, errRange := iprange.ParseRange(ipr)
		if errRange != nil {
			err = fmt.Errorf(":%v", errRange)
			return
		}
		if r.Contains(ipAddr) {
			result = true
			return
		}
	}
	return
}
```


## data corruption
預防外部重複呼叫造成的數據破壞
在設計API時，特別是那些修改數據的API（例如命令或寫操作），确保操作的幂等性是非常重要的。幂等性指的是多次執行同一操作的效果與執行一次相同。這可以預防由於用戶操作不當或重試機制引起的重複調用導致的數據破壞。實現幂等性的方法可能包括：

使用唯一的事務ID來檢測和忽略重複的請求。
確保操作的重複執行不會更改系統狀態。

## 服務器推送、在線遊戲和電子郵件背後的網絡協議Network Protocols behind Server Push, Online Gaming, and Emails
https://blog.bytebytego.com/p/network-protocols-behind-server-push


## SSE
![image](https://hackmd.io/_uploads/Hk-v1JXXJl.png)


## 位元操作
https://loesspie.com/2019/12/15/go-bitwise-operators%20/


## websocket注意
https://github.com/jiajianrong/documents/blob/master/node/WebSocket%E9%93%BE%E6%8E%A5%E7%9A%84%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88.md

https://tsh.io/blog/how-to-scale-websocket/


https://www.linkedin.com/pulse/websocket-horizontal-scalability-issues-solution-ashish-wakde-jbvuf/
## webhook


## CDN
除了靜態等會比較快 他還會中與tls 讓client不用跟server去聯繫
還有安全 能擋住ddos

## http
http 1 要三次握手 而且會阻塞 所以會一次多個請求
http 2 rpc 走stream 不會阻塞 每個獨立 不會有順序等問題 而且能向客戶傳資料

http 3 使用upc (QUIC) 不用握手 是為了解決手機 5g 4g切換問題


###### tags: `觀念重點區`