十六、网络编程-tcp socket编程

18.1 基本介绍

Golang的主要设计目标之一,就是面向大规模后端服务,网路通信这块是服务端程序必不可少也是至关重要的一部分。

网络编程有两种

1、TCP socket编程,是网络编程的主流。之所以叫Tcp socket编程,是因为是基于tcp/ip协议的。比如:QQ聊天

2、b/s结构的http编程,我们使用浏览器去访问服务器时,使用的就是http协议,而http底层依旧是用tcp socket实现的。 比如:京东商城 (这属于 go web开发范畴)

18.1.1 协议tcp/ip

TCP/IP 中文名为传输控制协议/因特网互联协议,又叫网络通讯协议,这个协议是Internet最基本的协议,Internet国际互联网络的基础,简单的说,就是由网络层的IP协议和传输层的TCP协议组成的。

NINOOI.PNG


18.1.2 OSI与TCP/IP参考模型

NINOOI.PNG

追踪一个路由:windows下 tracert www.baidu.com

18.1.3 ip地址

​ 概述:每个internet上的主机和路由器都有一个IP地址,它包括网络号和主机号,地址有ipv4(32位)和ipv6(128位),可以通过ipconfig来查看

18.1.4 端口

​ 这里所指的端口不是物理意义上的端口,而是特指TCP/IP协议中的E端口,是逻辑意义上的端口

​ 如果把IP地址比作一间房子,端口欧式出入这间房子懂的门。真正的房子只有几个们,但是一个IP地址的端口可以有65536(即:255 × 255)个之多!端口是通过端口号来标记的,端口号只有整数,范围是从0到65535(即:255 × 255 - 1)

NINOOI.PNG

端口分类:

  • 0是保留端口
  • 1-1024是固定端口,又叫有名端口,即被某些程序固定使用,一般程序员不使用
  • 1025-65535是动态端口,这些端口,程序员可以使用

端口使用注意

  • 在计算机(尤其是做服务器)要尽可能的少开端口
  • 一个端口只能被一个程序监听
  • 如果使用 netstat -an 可以查看本机有哪些端口在监听
  • 可以使用 netstat -anb 来查看监听端口的pid,在结合任务管理器关闭不安全的端口

18.2 tcp socket编程的客户端和服务器端

下图为Golang socket编程中客户端和服务器端的网络分布。

NINOOI.PNG

18.3 tcp socket编程的入门

18.3.1 服务端的处理流程:

  • 监听端口 8888
  • 接收客户端的tcp链接,建立客户端和服务器端的链接
  • 创建gorotine,处理该链接的请求(通常客户端会通过链接发送请求包)

18.3.2 客户端的处理流程:

  • 建立与服务端的链接
  • 发送请求数据[终端],接收服务器端返回的结果数据
  • 关闭链接

简单的示意图

NA4G34.png

18.3.3 代码实现

服务端功能:

编写一个程序,在8888端口监听

可以和多个客户端创建链接

链接成功后,客户端可以发送数据,服务器端接收数据,并显示在终端上

先用telnet来测试,然后编写客户端程序来测试

服务端代码: server.go

package main
import (
	"fmt"
	"net"  //做网络开发时,net包含了我们需要的所有的包
)

func process(conn net.Conn) {
	// 这里循环接收客户端发送的数据
	defer conn.Close() //关闭conn
	for {
		// 创建一个新的切片
		buf := make([]byte, 1024)
		// 1、等待客户端通过conn发送信息给我,
		// 2、如果客户端没有write[发送],那么协程就阻塞在这里
		// fmt.Printf("服务器在等待客户端%s 发送数据\n" + conn.RemoteAddr().String())
		n, err := conn.Read(buf)  //从conn获取
		if err != nil {
			fmt.Printf("客户端退出  err=%v", err)
			return  //!!!!!!!!!!!!!!
		}
		// 3、显示客户端发送的内容到服务器的终端
		fmt.Print(string(buf[:n]))
	}
}

func main() {

	fmt.Println("服务器开始监听....")
	// 1、TCP表示使用网络协议是tcp
	// 2、0.0.0.0:8888表示在本地监听 8888端口
	listen, err := net.Listen("tcp", "0.0.0.0:8888")
	if err != nil {
		fmt.Println("listen err=", err)
		return
	}
	defer listen.Close() //延时关闭

	// 循环等待客户端来链接我
	for {
		// 等待客户端来链接我
		fmt.Println("等待客户端来链接我....")
		conn, err := listen.Accept()
		if err != nil {
			fmt.Printf("Accept() err=%v", err)
		} else {
			fmt.Printf("Accept() sucess con=%v 客户端IP=%v\n", conn, conn.RemoteAddr().String())
		}
		// 这里准备起一个协程,为客户端服务
		go process(conn)
	}
}

客户端功能:

编写一客户端程序,能链接到服务器端的8888端口

客户端可以发送单行数据 ,然后就退出

能通过终端输入数据(输入一行,发送一行),并发送给服务器端口

在终端输入exit,表示退出程序

客户端代码:client.go

package main
import (
	"fmt"
	"net"
	"bufio"
	"os"
	"strings"
)

func main() {
	conn, err := net.Dial("tcp", "192.168.1.6:8888")
	if err != nil {
		fmt.Println("client dial err=", err)
		return
	}
	//功能1:客户端可以发送单行数据,然后就退出
	reader := bufio.NewReader(os.Stdin)  //os.Stdin  表示标准输入
	
	for {
	// 从终端读取一行用户输入,并准备发送给服务器
		line, err := reader.ReadString('\n')
		if err != nil {
		fmt.Println("readerString err=", err)
		}

		// 如果用户输入的是exit就退出
		line = strings.Trim(line, " \r\n")
		if line == "exit" {
			fmt.Println("客户端退出了......")
			break
		}

		// 再将line发送给服务器
		_, err = conn.Write([]byte(line + "\n"))
		if err != nil {
		fmt.Println("conn.Write err=", err)
		}
	}
}

运行结果

NA7v38.png

posted on 2020-06-16 18:35  九酒馆  阅读(265)  评论(0编辑  收藏  举报

导航