从零开始学golang之TCP

发布于 2018-03-11 作者 freedbg 2284次 浏览 版块 分享

package main

import (
	"flag"
	"fmt"
	"net"
	"os"
	"time"
)

/**
 *  tcp 启动 链接 三次握手  关闭四次
 *  慢启动 + 拥塞窗口
 *  门限控制 < 拥塞窗口 进入拥塞避免
 *  在发送数据后 检测 ack 确认超时 或者 收到重复ack 确认 操作门限值 和 拥塞窗口值 来限流
 *  接收方 使用通告窗口 告知发送可接受多少字节
 *
 *  发送方:滑动窗口协议
 */

//结构体内嵌接口
type Man struct {
	iTest
	name string
}

type iTest interface {
	hello()
}

type Em struct {
	good string
}

func (em *Em) hello() {
	fmt.Println(em.good)
}

func (man *Man) hello() {
	fmt.Println(man.name)
}

var workerChan = make(chan *net.TCPConn, 10000)
var graddr *string

func main() {

	// vman := Man{
	// 	&Em{
	// 		good: "goodman",
	// 	},
	// 	"helloman"}
	// vman.hello()
	// fmt.Println(vman)

	nf := flag.String("name", "server", "input server or client")
	graddr = flag.String("ip", "127.0.0.1:999", "ip:port")
	flag.Parse()
	fmt.Println(*nf)
	if *nf == "server" {
		server()
	} else {
		client()
	}

	var wait string
	fmt.Scanln(&wait)
}

func server() {
	laddr, aerr := net.ResolveTCPAddr("tcp", ":999")
	if aerr != nil {
		os.Exit(1)
	}
	listen, lerr := net.ListenTCP("tcp", laddr)
	defer listen.Close()
	if lerr != nil {
		os.Exit(2)
	}

	//plan2 code start
	for i := 0; i < 10; i++ {
		go sworker2(workerChan)
	}

	st := time.Now()
	var cn int
	cn = 0
	//plan2 code end
	for {

		tcpConn, cerr := listen.AcceptTCP()
		if cerr == nil {
			cn++
			//go sworker(tcpConn) //plan 1
			workerChan <- tcpConn //plan 2 减少了工作协程创建
		}
		if time.Since(st).Seconds() >= 2 {
			fmt.Println("accept tcp client :", cn)
			cn = 0
			st = time.Now()
		}
	}
}

/**
 * 通过chan,的工作线程
 */
func sworker2(conns <-chan *net.TCPConn) {
	fmt.Println("sworker2")
	var b [1500]byte
	for conn := range conns {
		//for {
		_, err := conn.Read(b[0:])

		if err == nil {
			//fmt.Println(string(b[0:len]))
		}

		conn.Write([]byte("HELLO WORLD"))
		//conn.Close()
		//}
	}
}

/**
 * 工作协程
 */
func sworker(conn *net.TCPConn) {
	fmt.Println("sworker")
	var b [1500]byte
	for {
		len, err := conn.Read(b[0:])

		if err == nil {
			fmt.Println(string(b[0:len]))
		}

		conn.Write([]byte("HELLO WORLD"))
	}
}

func client() {
	//linux 默认文件数打开1024
	//ulimit -n 50000 修改
	for i := 0; i < 40000; i++ {
		fmt.Println("create clint", i)
		go func() {
			defer func() {
				if err := recover(); err != nil {
					fmt.Println(err)
				}
			}()
			raddr, rerr := net.ResolveTCPAddr("tcp", *graddr)
			if rerr != nil {
				fmt.Println(rerr)
				return
				//os.Exit(3)
			}
			tcpConn, dterr := net.DialTCP("tcp", nil, raddr)

			if dterr != nil {
				fmt.Println(dterr)
				return
			}

			var b [1500]byte

			wlen, err := tcpConn.Write([]byte("ARE-U-THERE"))
			if err == nil && wlen > 0 {
				tcpConn.Read(b[0:])
				//fmt.Println(string(b[0:rlen]))
			} else {
				fmt.Println(err)
			}
		}()
	}
}

所有代码地址:https://github.com/godla/TCP-IP-Study

收藏
5回复
shen1001楼•2018-03-11

golang123的在线图书已经开发的差不多了,过段时间对外开放,敬请期待😀

shen1002楼•2018-03-23

在线图书正式对外开放了,你可以把你这一系列的教程制作成一本书哦

wuxin3楼•2018-04-22
shen1002楼回复

好的, 居然可以改?

hahalkj4楼•2018-05-19

最棒的golang社区

shen1005楼•2018-05-29
hahalkj4楼回复

谢支持