内容参考net包,net包提供了可移植的网络I/O接口,包括TCP/IP、UDP、域名解析和Unix域socket。

虽然本包提供了对网络原语的访问,大部分使用者只需要Dial、Listen和Accept函数提供的基本接口;以及相关的Conn和Listener接口。crypto/tls包提供了相同的接口和类似的Dial和Listen函数。

服务端

在服务器端我们需要绑定服务到指定的非激活端口, 并监听此端口;当有客户端请求到达的时候可以接收到来自客户端连接的请求。

package mainimport ("fmt""net""os""strings""time"
)func main() {// 监听的服务器端口service := "127.0.0.1:1200"tcpAddr, err := net.ResolveTCPAddr("tcp4", service)if err != nil {fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())os.Exit(1)}// 在服务器端我们需要绑定服务到指定的非激活端口, 并监听此端口,// 当有客户端请求到达的时候可以接收到来自客户端连接的请求//// func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error)// ListenTCP在本地TCP地址laddr上声明并返回一个*TCPListener, net参数必须是"tcp", "tcp4", "tcp6",// 如果laddr的端口字段为0, 函数将选择一个当前可用的端口, 可以用Listener的Addr方法获得该端口listener, err := net.ListenTCP("tcp", tcpAddr)if err != nil {fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())os.Exit(1)}for {// 接受每一种请求// func (l *TCPListener) Accept() (Conn, error)// Accept用于实现Listener接口的Accept方法// 他会等待下一个呼叫, 并返回一个该呼叫的Conn接口conn, err := listener.Accept()// 当有错误发生的情况下最好是由服务端记录错误, 然后当前连接的客户端直接报错而退出, 从而不会// 影响到当前服务端运行的整个服务if err != nil {continue}// 处理客户端的连接go handleClient(conn)}
}func handleClient(conn net.Conn) {// 超时时间, 当一定时间内客户端无请求发送, conn便会自动关闭, 下面的for循环即会因为连接已关闭而跳出conn.SetReadDeadline(time.Now().Add(1 * time.Minute))// request在创建时需要指定一个最大长度以防止flood attack; 每次读取到请求处理完毕后,// 需要清理request, 因为conn.Read()会将新读取到的内容append到原内容之后// request 为提供的读取的最长缓冲区, 缓冲区满后会自动回写到客户端接收, 因此客户端需要注意接收到数据的完整性后在处理// 但是也并非都是写满后才返回给客户端, 有可能提前返回数据, 需要一个协议// 如果该缓冲区给的不够, 可能造成客户端传递过来的信息被截断, 无法得到预期的结果request := make([]byte, 9)defer conn.Close()for {// 不断读取客户端发来的请求, 由于我们需要保持与客户端的长连接, 所以不能在读取完一次请求后就关闭连接// 将读取到的数据追加保存到request中readLen, err := conn.Read(request)if err != nil {fmt.Println(err)break}// 如果没有读取到客户端任何信息, 则默认客户端已经关闭if readLen == 0 {break} else if strings.TrimSpace(string(request[:readLen])) == "timestamp" {date := time.Now().Format("2006-01-02 15:04:05")conn.Write([]byte(date))} else {conn.Write([]byte(request[:readLen]))}// 每次发送写完毕后都清除缓存空间, 防止追加request = make([]byte, 8)}
}

客户端

首先程序将用户的输入作为参数service传入net.ResolveTCPAddr获取一个tcpAddr,然后把tcpAddr传入DialTCP后创建了一个TCP连接conn,通过conn来发送请求信息,最后通过ioutil.ReadAll从conn中读取全部的文本,也就是服务端响应反馈的信息。

package mainimport ("fmt""net""os""io/ioutil"
)func main() {// 获取提供服务的服务器ip地址service := os.Args[1]// func ResolveTCPAddr(net, addr string) (*TCPAddr, error)// ResolveTCPAddr获取一个TCPAddr, 一个TCPAddr类型, 他表示一个TCP的地址信息// ResolveTCPAddr将addr作为TCP地址解析并返回// 参数addr格式为"host:port"或"[ipv6-host%zone]:port", 解析得到网络名和端口名// net必须是"tcp", "tcp4"或"tcp6"tcpAddr, err := net.ResolveTCPAddr("tcp4", service)if err != nil {fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())os.Exit(1)}// 通过net包中的DialTCP函数来建立一个TCP连接, 并返回一个TCPConn类型的对象// 当连接建立时服务器端也创建一个同类型的对象, 此时客户端和服务器端通过各自拥// 有的TCPConn对象来进行数据交换//// 一般而言, 客户端通过TCPConn对象将请求信息, 发送到服务器端, 读取服务器端响应的信息// 服务器端读取并解析来自客户端的请求并返回应答信息, 这个连接只有当任一端关闭了连接之后才失效,// 不然这连接可以一直在使用//// func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error)// DialTCP在网络协议net上连接本地地址laddr和远端地址raddr// net必须是"tcp", "tcp4", "tcp6"// 如果laddr不是nil, 将使用它作为本地地址, 否则自动选择一个本地地址conn, err := net.DialTCP("tcp", nil, tcpAddr)if err != nil {fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())os.Exit(1)}// 向连接的服务器端写入信息// net包中有一个类型TCPConn, 这个类型可以用来作为客户端和服务器端交互的通道, 他有两个主要的函数:// func (c *TCPConn) Write(b []byte) (n int, err os.Error)// func (c *TCPConn) Read(b []byte) (n int, err os.Error)// TCPConn可以用在客户端和服务器端来读写数据//_, err = conn.Write([]byte("HEAD / HTTP/1.0\r\n\r\n"))_, err = conn.Write([]byte("timestamp"))if err != nil {fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())os.Exit(1)}_, err = conn.Write([]byte("a~~~"))if err != nil {fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())os.Exit(1)}_, err = conn.Write([]byte("b~~~~~"))if err != nil {fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())os.Exit(1)}_, err = conn.Write([]byte("c~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"))if err != nil {fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())os.Exit(1)}// 当客户端停止写入时, 需要告诉服务端, 信息发送终止, 服务端就返回全部的数据if err = conn.CloseWrite(); err != nil {fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())os.Exit(1)}// 读取服务器端响应的全部内容// ReadAll从r读取数据直到EOF或遇到error, 返回读取的数据和遇到的错误// 成功的调用返回的err为nil而非EOF, 因为本函数定义为读取r直到EOF, 它不会将读取返回的EOF视为应报告的错误result, err := ioutil.ReadAll(conn)if err != nil {fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())os.Exit(1)}// 输出获取到的内容fmt.Println(string(result))os.Exit(0)
}

服务端启动

服务端每次请求结束后都会以文件结束符标志输出。

zhgxun-pro:go zhgxun$ go run server.go
EOF
EOF
EOF
EOF
EOF
EOF

客户端输出

当客户端停止写入时,服务端将全部数据返回。

zhgxun-pro:go zhgxun$
zhgxun-pro:go zhgxun$ go run client.go 127.0.0.1:1200
2017-09-17 21:07:44a~~~b~~~~~c~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
zhgxun-pro:go zhgxun$ go run client.go 127.0.0.1:1200
2017-09-17 21:07:46a~~~b~~~~~c~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
zhgxun-pro:go zhgxun$ go run client.go 127.0.0.1:1200
2017-09-17 21:07:47a~~~b~~~~~c~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
zhgxun-pro:go zhgxun$ go run client.go 127.0.0.1:1200
2017-09-17 21:07:48a~~~b~~~~~c~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
zhgxun-pro:go zhgxun$ go run client.go 127.0.0.1:1200
2017-09-17 21:07:49a~~~b~~~~~c~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
zhgxun-pro:go zhgxun$ go run client.go 127.0.0.1:1200
2017-09-17 21:07:50a~~~b~~~~~c~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
zhgxun-pro:go zhgxun$

Go tcp客户端、服务端编程相关推荐

  1. python多线程tcp客户端_基于Python多线程的TCP客户端/服务端应用示例

    每个连接都必须创建新线程(或进程)来处理,否则,单线程在处理连接的过程中,无法接受其他客户端的连接. 服务端:server.py # -*- coding:utf-8 -*- import sys i ...

  2. 使用springboot+netty处理tcp/ip服务端编程

    1.添加依赖 略 2.netty服务器启动 springboot的bean代码,另开一个线程启动 @Component public class NettyServer {private static ...

  3. OSI七层模型以及TCP/UDP客户端/服务端程序实例

    OSI七层模型以及TCP/UDP客户端/服务端程序实例 一.前言 二.OSI简介 2.1 OSI概念 2.2 划分原则 2.3 OSI七层模型 2.4 模型举例 三.Linux下TCP/UDP程序开发 ...

  4. TCP/IP网络编程之基于TCP的服务端/客户端(二)

    回声客户端问题 上一章TCP/IP网络编程之基于TCP的服务端/客户端(一)中,我们解释了回声客户端所存在的问题,那么单单是客户端的问题,服务端没有任何问题?是的,服务端没有问题,现在先让我们回顾下服 ...

  5. TCP/IP网络编程之基于TCP的服务端/客户端(一)

    TCP/IP网络编程之基于TCP的服务端/客户端(一) 理解TCP和UDP 根据数据传输方式的不同,基于网络协议的套接字一般分为TCP套接字和UDP套接字.因为TCP套接字是面向连接的,因此又称为基于 ...

  6. 易语言tcp多线程服务端客户端_从TCP协议到TCP通信的各种异常现象和分析

    很多人总觉得学习TCP/IP协议没什么用,觉得日常编程开发只需要知道socket接口怎么用就可以了.如果大家定位过线上问题就会知道,实际上并非如此.如果应用在局域网内,且设备一切正常的情况下可能确实如 ...

  7. Qt中TCP服务端编程

    文章目录 1 Qt中的TCP服务端编程 1.1 TCP服务端编程介绍 1.2 Qt中的TCP服务端编程 1 Qt中的TCP服务端编程 1.1 TCP服务端编程介绍 网络中的服务端: 服务端是为客户端服 ...

  8. 新书预告:《Linux 多线程服务端编程——使用 muduo C++ 网络库》

    看完了 W. Richard Stevens 的传世经典<UNIX 网络编程>, 能照着例子用 Sockets API 编写 echo 服务, 却仍然对稍微复杂一点的网络编程任务感到无从下 ...

  9. 《Linux多线程服务端编程:使用muduo C++网络库》书摘6.6.2节

    6.6.2 常见的并发网络服务程序设计方案 W. Richard Stevens 的<UNIX 网络编程(第2 版)>第27 章"Client-ServerDesign Alte ...

  10. 《Linux多线程服务端编程:使用muduoC++网络库》学习笔记

    文章目录 第1章 线程安全的对象生命期管理 1.1 当析构函数遇到多线程 1.1.1 线程安全的定义 1.1.3 线程安全实例 1.2 对象的创建很简单 1.3 销毁很难 1.4 线程安全的Obser ...

最新文章

  1. BAPI:BAPI_CONTRACT_CREATE(内部合同创建)
  2. 1500度的近视能学计算机吗,1500度近视考驾照,近视多少度不能考驾照
  3. 非经营性网站备案流程
  4. 狮子鱼小程序独立版安装配置教程
  5. Win7---保护眼睛的电脑窗口颜色设置
  6. ANACONDA下载opencv,py-opencv,libopencv的区别
  7. 沟通的艺术:简介及内容导航
  8. 视频画中画的实现(窗口剪裁)
  9. 篱笆回路Fence Loops
  10. python打包成.exe文件时出现“系统找不到指定路径”
  11. SMETA验厂咨询,由于两种模式所需的审核天数不同,总的费用存在差异
  12. 风控基础——通俗介绍逾期次数和逾期期数
  13. 安装OpenCV时遇到的几种错误
  14. 【信号处理】心电信号PQRST峰值检测matlab工具箱
  15. 手机拍照识别 如何识别车牌号并给出数据
  16. 764 · 计算圆周长和面积
  17. 【面经】美团春招三轮面经分享~涵盖众多知识点
  18. 在线培训网校系统,解决了课程的计时消课问题
  19. 《ZigBee开发笔记》第六部分 项目篇 基于ZigBee和Openwrt的智能家居控制系统(五)
  20. 椭圆形中间一个大写的v_一个横着的椭圆中间画了一个竖线这是什么符号 10分...

热门文章

  1. eclipse控制台自动换行不分割单词_这 7 个实用的文档技巧,不掌握就太可惜了...
  2. 嵌入式论文3000字_SCI英文论文一般多少字
  3. java 命令读取参数_如何读取/处理命令行参数?
  4. 被尘封的故事技能点bug_新月纪元稳定版下载-新月纪元bug修复版1.0 修复版
  5. python反转字符串的元音字母_345. 反转字符串中的元音字母-----leetcode刷题(python解题)...
  6. vue iframe 中写script_vue: 单文件组件 render函数
  7. 基金指数温度怎么算_医药冷链物流——运输过程中如何保证温度?
  8. python数组plot_Python Matplotlib:动态更新plot-数组长度未知
  9. java复制文件_java多种文件复制方式以及效率比较
  10. aspen二元体系共沸组分_超详细 | 手把手教你组分结构预测