Go语言实现TCP通信
TCP协议为传输控制协议,TCP协议有以下几个特点:
1. TCP是面向连接的传输层协议;
2. 每条TCP连接只能有两个端点,每条TCP连接是点到点的通信;
3. TCP提供可靠的交付服务,保证传送的数据无差错,不丢失,不重要且有序;
4. TCP提供全双工通信,允许双方在任何时候都能发送数据,为此TCP连接的两端都设有发送缓存和接收缓存,用来临时存放双向通信的数据;
5. TCP是面向字节流的;
发送缓存用来暂存以下数据:
① 发送应用程序传送给发送方TCP准备发送的数据;
② TCP已发送但尚未收到确认的数据;
接收缓存用来暂存以下数据:
① 按序到达但尚未被接收应用程序读取的数据;
② 不按序到达的数据;
因为是面向连接的协议,数据像水流一样传输,会存在黏包问题。
TCP连接
一个TCP服务端可以同时连接很多个客户端,Go语言可以使用go关键字开启goroutine,每建立一个连接就创建一个goroutine,这样可以并发执行每一个创建的连接,tcp服务端主要的处理流程有:1. 监听端口;2. 接收客户端请求创建tcp连接;3. 使用go关键字开启goroutine处理每一个建立的连接,收发数据;4. 关闭连接;tcp客户端主要的处理流程有:1. 建立与服务端的连接;2. 收发数据;3. 关闭连接;关于tcp通信我们一般会使用到bufio,net,strings,os包,其中bufio包主要用来做输入输出数据的缓存,bufio.NewReader()函数可以传递os.Stdin类型(任何实现了io.Reader接口中的read()方法都可以作为参数传递进来,通常是传递一个实现了io.Reader接口中的read()方法的结构体或者是结构体指针),os.Stdin为标准输入,我们可以接受读取从控制台输入的数据,os.NewReader()函数返回的是一个新的带有4096 byte大小缓冲区的Reader结构体指针类型,通过Reader结构体指针类型我们就可以调用很多的方法,比如可以调用ReadString(delim byte) (string,error)方法,ReadString方法可以一直从标准输入中读取数据,直到遇到指定的终止符号delim,并且读取的内容会包含当前的delim,所以bufio包主要用来对输入和输出的数据进行缓冲;net包主要是连接的监听、创建,以及连接数据的读取和写入(例如tcp,udp等网络编程)等相关工作,tcp服务端中可以使用一个process()函数传递一个net.Conn类型也即*net.TCPConn类型的变量conn(TCPConn结构体实现了Conn接口),*TCPConn类型那么就可以调用很多的方法,因为我们需要从tcp连接中读取客户端或者是服务端发送的数据,所以可以调用*TCPConn类型的read()方法读取tcp连接的数据,然后输出数据即可,服务端可以使用net.Listen()函数监听连接,使用Accept()方法建立tcp连接,客户端则可以使用net.Dial()连接创建的tcp连接,使用conn接口的实现*TCPConn(Dial()方法的返回值就是*TCPConn类型)调用conn的read()方法将读取tcp连接的内容,write()方法将数据写入到tcp连接中;strings包主要是对读取到的数据的字符串形式进行处理,比如去除掉字符串的一些符号等等。
下面的代码需要先运行服务端的代码,再运行客户端的代码:
TCP服务端
package main import (
"bufio"
"fmt"
"net"
"os"
"strings"
) // TCP 服务端
func process(conn net.Conn) {
// 函数执行完之后关闭连接
defer conn.Close()
// 输出主函数传递的conn可以发现属于*TCPConn类型, *TCPConn类型那么就可以调用*TCPConn相关类型的方法, 其中可以调用read()方法读取tcp连接中的数据
fmt.Printf("服务端: %T\n", conn)
for {
var buf [128]byte
// 将tcp连接读取到的数据读取到byte数组中, 返回读取到的byte的数目
n, err := conn.Read(buf[:])
if err != nil {
// 从客户端读取数据的过程中发生错误
fmt.Println("read from client failed, err:", err)
break
}
recvStr := string(buf[:n])
fmt.Println("服务端收到客户端发来的数据:", recvStr)
// 由于是tcp连接所以双方都可以发送数据, 下面接收服务端发送的数据这样客户端也可以收到对应的数据
inputReader := bufio.NewReader(os.Stdin)
s, _ := inputReader.ReadString('\n')
t := strings.Trim(s, "\r\n")
// 向当前建立的tcp连接发送数据, 客户端就可以收到服务端发送的数据
conn.Write([]byte(t))
}
} func main() {
// 监听当前的tcp连接
listen, err := net.Listen("tcp", "127.0.0.1:20000")
fmt.Printf("服务端: %T=====\n", listen)
if err != nil {
fmt.Println("listen failed, err:", err)
return
}
for {
conn, err := listen.Accept() // 建立连接
fmt.Println("当前建立了tcp连接")
if err != nil {
fmt.Println("accept failed, err:", err)
continue
}
// 对于每一个建立的tcp连接使用go关键字开启一个goroutine处理
go process(conn)
}
}
TCP客户端
package main import (
"bufio"
"fmt"
"net"
"os"
"strings"
) func main() {
// 连接到服务端建立的tcp连接
conn, err := net.Dial("tcp", "127.0.0.1:20000")
// 输出当前建Dial函数的返回值类型, 属于*net.TCPConn类型
fmt.Printf("客户端: %T\n", conn)
if err != nil {
// 连接的时候出现错误
fmt.Println("err :", err)
return
}
// 当函数返回的时候关闭连接
defer conn.Close()
// 获取一个标准输入的*Reader结构体指针类型的变量
inputReader := bufio.NewReader(os.Stdin)
for {
// 调用*Reader结构体指针类型的读取方法
input, _ := inputReader.ReadString('\n') // 读取用户输入
// 去除掉\r \n符号
inputInfo := strings.Trim(input, "\r\n")
// 判断输入的是否是Q, 如果是Q则退出
if strings.ToUpper(inputInfo) == "Q" { // 如果输入q就退出
return
}
_, err = conn.Write([]byte(inputInfo)) // 发送数据
if err != nil {
return
}
buf := [512]byte{}
// 读取服务端发送的数据
n, err := conn.Read(buf[:])
if err != nil {
fmt.Println("recv failed, err:", err)
return
}
fmt.Println("客户端接收服务端发送的数据: ", string(buf[:n]))
}
}
Go语言实现TCP通信的更多相关文章
- Go语言网络通信---TCP通信上传一个小文件
		
server: package main import ( "fmt" "net" "os" ) func SHandleError(err ...
 - [C语言]一个很实用的服务端和客户端进行TCP通信的实例
		
本文给出一个很实用的服务端和客户端进行TCP通信的小例子.具体实现上非常简单,只是平时编写类似程序,具体步骤经常忘记,还要总是查,暂且将其记下来,方便以后参考. (1)客户端程序,编写一个文件clie ...
 - 艺萌文件上传下载及自动更新系统(基于networkComms开源TCP通信框架)
		
1.艺萌文件上传下载及自动更新系统,基于Winform技术,采用CS架构,开发工具为vs2010,.net2.0版本(可以很容易升级为3.5和4.0版本)开发语言c#. 本系统主要帮助客户学习基于TC ...
 - 【学习笔记】TCP通信的细节及TCP连接对HTTP事务处理性能影响
		
从三次握手的细节说起 刚开始尝试使用java等后端语言写IO流,或用套接字(socket)实现简单C/S通信的同学们,常常会接触到的一个概念:就是所谓的"三次握手",socket作 ...
 - 【计算机网络】TCP通信的细节及TCP连接对HTTP事务处理性能影响
		
从三次握手的细节说起 刚开始尝试使用java等后端语言写IO流,或用套接字(socket)实现简单C/S通信的同学们,常常会接触到的一个概念:就是所谓的“三次握手”,socket作为一个API接口,封 ...
 - Java 之 TCP 通信程序
		
一.概述 TCP 通信能实现两台计算机之间的数据交互,通信的两端,要严格区分为客户端(Client)与服务端(Server). 两端通信时步骤: 1.服务端程序,需要事先启动,等待客户端的连接: 2. ...
 - TCP通信
		
//网络套接字编程实例,服务器端,TCP通信. #include <WinSock2.h> #pragma comment(lib,"ws2_32.lib") #inc ...
 - 清晰易懂TCP通信原理解析(附demo、简易TCP通信库源码、解决沾包问题等)C#版
		
目录 说明 TCP与UDP通信的特点 TCP中的沾包现象 自定义应用层协议 TCPLibrary通信库介绍 Demo演示 未完成功能 源码下载 说明 我前面博客中有多篇文章讲到了.NET中的网络编程, ...
 - JAVASE02-Unit010: 多线程基础 、 TCP通信
		
多线程基础 . TCP通信 * 当一个方法被synchronized修饰后,那么 * 该方法称为同步方法,即:多个线程不能同时 * 进入到方法内部执行. package day10; /** * 当多 ...
 - NetworkComms V3 使用TCP通信传递IList<T>类型的数据
		
客户端从服务器获取一组IList<T>类型的数据非常常见(通常从数据库中获取) 我们用NeworkComms V3来演示一下(NetworkcommsV2.x版本也同样支持) [ 使用pr ...
 
随机推荐
- mysql自动生成时间
			
字段类型: DATETIME 默认值: CURRENT_TIMESTAMP
 - 【pytest】@pytest.fixture与@pytest.mark.parametrize结合实现参数化
			
背景:测试数据既要在fixture方法中使用,同时也在测试用例中使用 使用方法:在使用parametrize的时候添加"indirect=True"参数.pytest可以实现将参数 ...
 - 蓝桥2021 B组
			
2. 卡片(结果填空) 小蓝有很多数字卡片,每张卡片上都是数字 0 到 9. 小蓝准备用这些卡片来拼一些数,他想从 1 开始拼出正整数,每拼一个, 就保存起来,卡片就不能用来拼其它数了. 小蓝想知道自 ...
 - 安装pytorch时install的packages
 - 【UE4】GameplayTag的妙用(ActorTag)
			
我不会抛下这个残破的世界 在现代游戏引擎中,有一个"Tag"的概念,无论是在Unreal还是Unity中,他们都有大同小异的tag实现. 此篇随笔以Actor Tag举例,简单讲解 ...
 - 尝试改善科研V2
			
参考链接: https://fulequn.github.io/2022/09/26/Article202209261/ https://www.xljsci.com/ https://apps.an ...
 - Matlab|fastica遇到的问题
			
fastica 1 安装 FastICA 在matlab代码实现以及运行结果by阳光idol 安装步骤博主阳光idol已经写的很清楚了 FastICA 在matlab代码实现.运行结果及错误调试方法 ...
 - 如何卸载powermill?怎么把powermill彻底卸载删除干净重新安装的方法【转载】
			
如何卸载powermill?怎么把powermill彻底卸载删除干净重新安装的方法.powermill显示已安装或者报错出现提示安装未完成某些产品无法安装的问题,怎么完全彻底删除清理干净powermi ...
 - web之jquery
			
jquery 插件 下载解压插件 加载jQuery 加载插件 插件样式 按照使用例子给元素添加类名,id,函数.
 - Honeywell安卓版手持机设置广播方式
			
设置>Honeywell设置>扫描设置>Internal Scanner>Default profile>Data Processing Settings>Data ...