Skip to content

Latest commit

 

History

History
81 lines (63 loc) · 3.72 KB

golang101_Web01_TCP_Server.md

File metadata and controls

81 lines (63 loc) · 3.72 KB

Golang 101系列网络篇——TCP Server

本文将从回顾TCP的基本概念出发,到了解Golang下网络Socket编程的理念,再到使用Golang搭建几个简单的TCP Server Demo。

TCP简述

TCP位于传输层,在TCP/IP五层协议中,处于网络层之上,应用层之下。具体来看,TCP链接是一个典型的C-S模型,也就是客户端(Client)-服务端(Server)模型。客户端发出连接请求,服务端接受请求,并返回一个ACK,客服端收到ACK之后,明白了Server已经接受了自己的请求,然后发送一个ACK回去,告知Server,“我知道你接受我了,我们可以开始传输数据了。”至此,TCP三次握手完成。

TCP通过传输序列有序的数据并附加ACK的方式,来保证其稳定性,来防止连接过程中发生丢包。除此之外,有一些有名的TCP改进机制,比如TCP-Reno,这个以后有机会再重新开一篇文章详细聊。

题外话:TCP vs UDP

直接搬出学校的笔记 2333:

  • TCP is connection-oriented protocol(3-Way handshake), UDP is connection less (multicast).
  • TCP is reliable, delivery guaranteed(resend), UDP is unreliable.
  • TCP is ordered (has sequence), UDP may not in the order.
  • TCP is slow and heavy weight(20 bytes header), UDP is fast and light-weight (8 b header).
  • TCP has flow control and congestion control.
  • TCP is used by HTTP, HTTPS, FTP, SMP; UDP is used by DHCP, DNS, NFS...

Golang的网络编程理念

以前在学校做Project的时候,遇到用C++写TCP的时候有时还挺头痛的,体验不好。使用Golang写TCP/IP层,相比C++,简直不要简单太多。难能可贵的是在简单的同时,Golang还保持着不俗的性能。

Golang下写TCP Server

基于Golang的I/O机制和并发原语的原生支持,再加上对网络API的封装,我们可以比较轻松地实现一个高效的服务端或者客户端程序。一般的实现就是调用net.Listen(“tcp4”, address)得到一个net.Listener,然后无限循环调用net.Listener.Accept,之后就可以得到一个net.Conn,可以调用net.Conn的接口设置发送和接收缓冲区大小,可以设置KEEPALIVE等。因为TCP的双工特性,所以可以针对一个net.Conn可以专门启动一个goroutine去无限循环接收对端发来的数据,然后解包等。

Echo Server

我们下面来写一个简单的回音服务器(Echo Server),就是client发送一个信息,server稍微处理一下,就把原信息返回来给client。整个过程是,Server在监听,拿到监听到的信息后,通过写网络文件传回给Client,然后继续监听接下来的信息。

package main

import (
	"bufio"
	"fmt"
	"log"
	"net"
)

func main() {
	//Server gets a listener, listening to localhost:8080
	li, err := net.Listen("tcp", ":8080")
	if err != nil {
		log.Panic(err)
	}
	//Don't forget to close later, otherwise resourse will leak.
	defer li.Close()

	//Keep listening
	for {
		//Listener accepts the request, and build the connection
		conn, err := li.Accept()
		if err != nil {
			log.Panic(err)
		}
		//Do the job.
		go handle(conn)
	}
}

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

	//returns a new Scanner to read from connection io.Reader.
	scanner := bufio.NewScanner(conn)
	//Scan will get next token, which will then be available through the Bytes or Text method.
	for scanner.Scan() {
		//Get most recent token generated by a call to Scan
		ln := scanner.Text()
		//Server prints the info from the connection
		fmt.Println(ln)
		//Write back to connection:
		fmt.Fprintf(conn, "I heard you said: %s\n", ln)
	}
}