我们将使用 TCP 协议和协程范式编写一个简单的客户端-服务器应用,一个(web)服务器应用需要响应众多客户端的并发请求:Go 会为每一个客户端产生一个协程用来处理请求。我们需要使用 net 包中网络通信的功能。它包含了处理 TCP/IP 以及 UDP 协议、域名解析等方法。

服务器端代码是一个单独的文件:

示例 1 server.go

package main

import (
"fmt"
"net"
) func main() {
fmt.Println("Starting the server ...")
// 创建 listener
listener, err := net.Listen("tcp", "localhost:50000")
if err != nil {
fmt.Println("Error listening", err.Error())
return //终止程序
}
// 监听并接受来自客户端的连接
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println("Error accepting", err.Error())
return // 终止程序
}
go doServerStuff(conn)
}
} func doServerStuff(conn net.Conn) {
for {
buf := make([]byte, 512)
len, err := conn.Read(buf)
if err != nil {
fmt.Println("Error reading", err.Error())
return //终止程序
}
fmt.Printf("Received data: %v\n", string(buf[:len]))
}
}

在 main() 中创建了一个 net.Listener 类型的变量 listener,他实现了服务器的基本功能:用来监听和接收来自客户端的请求(在 localhost 即 IP 地址为 127.0.0.1 端口为 50000 基于TCP协议)。Listen() 函数可以返回一个 error 类型的错误变量。用一个无限 for 循环的 listener.Accept() 来等待客户端的请求。客户端的请求将产生一个 net.Conn 类型的连接变量。然后一个独立的协程使用这个连接执行 doServerStuff(),开始使用一个 512 字节的缓冲 data 来读取客户端发送来的数据,并且把它们打印到服务器的终端,len 获取客户端发送的数据字节数;当客户端发送的所有数据都被读取完成时,协程就结束了。这段程序会为每一个客户端连接创建一个独立的协程。必须先运行服务器代码,再运行客户端代码。

客户端代码写在另一个文件 client.go 中:

示例 2 client.go

package main

import (
"bufio"
"fmt"
"net"
"os"
"strings"
) func main() {
//打开连接:
conn, err := net.Dial("tcp", "localhost:50000")
if err != nil {
//由于目标计算机积极拒绝而无法创建连接
fmt.Println("Error dialing", err.Error())
return // 终止程序
} inputReader := bufio.NewReader(os.Stdin)
fmt.Println("First, what is your name?")
clientName, _ := inputReader.ReadString('\n')
// fmt.Printf("CLIENTNAME %s", clientName)
trimmedClient := strings.Trim(clientName, "\r\n") // Windows 平台下用 "\r\n",Linux平台下使用 "\n"
// 给服务器发送信息直到程序退出:
for {
fmt.Println("What to send to the server? Type Q to quit.")
input, _ := inputReader.ReadString('\n')
trimmedInput := strings.Trim(input, "\r\n")
// fmt.Printf("input:--%s--", input)
// fmt.Printf("trimmedInput:--%s--", trimmedInput)
if trimmedInput == "Q" {
return
}
_, err = conn.Write([]byte(trimmedClient + " says: " + trimmedInput))
}
}

客户端通过 net.Dial 创建了一个和服务器之间的连接。

它通过无限循环从 os.Stdin 接收来自键盘的输入,直到输入了“Q”。注意裁剪 \r 和 \n 字符(仅 Windows 平台需要)。裁剪后的输入被 connection 的 Write 方法发送到服务器。

当然,服务器必须先启动好,如果服务器并未开始监听,客户端是无法成功连接的。

如果在服务器没有开始监听的情况下运行客户端程序,客户端会停止并打印出以下错误信息:对tcp 127.0.0.1:50000发起连接时产生错误:由于目标计算机的积极拒绝而无法创建连接

可以同时启动多个客户端程序。

一下是服务器的输出:

PS C:\Users\20928\go\src\go_code> go run server.g   erveo
Starting the server ...
Received data: 张三 says: 你好,我叫张三
Received data: 李四 says: 你好,我叫李四,很高兴认识你
Received data: 张三 says: 你来自哪里?
Received data: 李四 says: 我来自中国
Received data: 李四 says: 北京

在网络编程中 net.Dial 函数是非常重要的,一旦你连接到远程系统,函数就会返回一个 Conn 类型的接口,我们可以用它发送和接收数据。Dial 函数简洁地抽象了网络层和传输层。所以不管是 IPv4 还是 IPv6,TCP 或者 UDP 都可以使用这个公用接口。

参考链接:https://github.com/unknwon/the-way-to-go_ZH_CN/blob/master/eBook/15.1.md

go实现tcp 服务器的更多相关文章

  1. Socket Server-基于线程池的TCP服务器

    了解线程池 在http://blog.csdn.net/ns_code/article/details/14105457(读书笔记一:TCP Socket)这篇博文中,服务器端采用的实现方式是:一个客 ...

  2. Python TCP服务器

    TCP服务器的创建也比较简单: 1.建立一个socket对象 2.绑定要监听的IP地址和端口 3.当有客户端请求时,启动多线程处理客户端连接 import socket import threadin ...

  3. [安卓] 9、线程、VIEW、消息实现从TCP服务器获取数据动态加载显示

    一.前言: 一般情况下从TCP服务器读取数据是放在一个线程里读的,但是刷新界面又不得不放在线程外面,所以需要用消息传递把线程里从TCP里获得的数据传送出来,然后根据数据对页面进行相应的刷新. 二.业务 ...

  4. Mina、Netty、Twisted一起学(一):实现简单的TCP服务器

    MINA.Netty.Twisted为什么放在一起学习?首先,不妨先分别看一下它们官方网站对其的介绍: MINA: Apache MINA is a network application frame ...

  5. TCP服务器不回复SYN的问题

    个人问题发生环境: 1.TCP服务器是虚拟机,IP地址是192.168.8.12. 2.TCP客户端是宿主机,IP地址是192.168.8.11. 3.从宿主机(192.168.8.11)上启动Soc ...

  6. 高性能、高并发TCP服务器(多线程调用libevent)

    from:http://blog.csdn.net/i_am_jojo/article/details/7587838 本文讲述的TCP服务器是模仿memcache中的TCP网络处理框架,其中是基于l ...

  7. python socket之tcp服务器与客户端demo

    python socket之tcp服务器与客户端demo 作者:vpoet mails:vpoet_sir@163.com server: # -*- coding: cp936 -*- ''' 建立 ...

  8. <摘录>详谈高性能TCP服务器的开发

    对于开发一款高性能服务器程序,广大服务器开发人员在一直为之奋斗和努力.其中一个影响服务器的重要瓶颈就是服务器的网络处理模块.如果一款服务器程序不能及时的处理用户的数据.则服务器的上层业务逻辑再高效也是 ...

  9. 【卷二】网络二—TCP服务器与客户端

    经过上回简单地介绍,大家对服务器多少应该清楚一些了吧!还记得TCP: (Transmission Control Protocol) 传输控制协议? 还记得IP: (Internet Protocol ...

  10. 使用nodejs的net模块创建TCP服务器

    使用nodejs的net模块创建TCP服务器 laiqun@msn.cn Contents 1. 代码实现 2. 使用telnet连接服务器测试 3. 创建一个TCP的client 1. 代码实现 ; ...

随机推荐

  1. docker-compose之跳板机jumpserver部署

    下载docker-compose curl -L https://get.daocloud.io/docker/compose/releases/download/1.24.1/docker-comp ...

  2. ReentrantReadWriteLock 源码分析

    ReentrantReadWriteLock  源码分析: 1:数据结构: 成员变量: private final ReentrantReadWriteLock.ReadLock readerLock ...

  3. [转帖]从零开始入门 K8s | 手把手带你理解 etcd

    从零开始入门 K8s | 手把手带你理解 etcd https://zhuanlan.zhihu.com/p/96721097 导读:etcd 是用于共享配置和服务发现的分布式.一致性的 KV 存储系 ...

  4. 使用SonarQube和SonarQube Scanner分析项目

    一.概述 SonarQube的安装,请参考链接:https://www.cnblogs.com/xiao987334176/p/12011623.html 配置好sonar的服务端后,接下来就要使用s ...

  5. 【Navicat】使用navicat执行sql 查询速度很慢解决方法

    ========================== Navicat 远程连接Mysql执行普通sql速度慢问题: 场景: navicat可以连接上 远程服务器的mysql.但是在navicat执行最 ...

  6. Linq 将两个查询结果合称为一个

    var handsonitems = from a in db.DltQuestionHandson join c in db.DltBdChapter on new { a.ChapterCode ...

  7. 基于.net core 3 和 Orleans 3 的 开发框架:Phenix Framework 7

    Phenix Framework 7 for .net core 3 + Orleans 3 发布地址:https://github.com/phenixiii/Phenix.NET7 2019052 ...

  8. python 进程和线程-进程和线程的比较以及分布式进程

    进程和线程的比较 参考链接:https://www.liaoxuefeng.com/wiki/1016959663602400/1017631469467456 我们介绍了多进程和多线程,这是实现多任 ...

  9. Python学习笔记之try-except

    Python使用被称为异常的特殊对象来管理程序执行期间发生的错误.每当发生让Python不知所措的错误时,它都会创建一个异常对象.如果你编写了处理该异常的代码,程序将继续运行:如果你未对异常进行处理, ...

  10. Java内存泄漏解析!

    前言: 内存管理是Java最重要的优势之一,你只需创建对象,Java垃圾收集器会自动负责分配和释放内存.但是,情况并不那么简单,因为在Java应用程序中经常发生内存泄漏. 本章会说明什么是内存泄漏,为 ...