服务器接收客户端消息|学习笔记

简介: 快速学习服务器接收客户端消息

开发者学堂课程【Go 语言核心编程 - 面向对象、文件、单元测试、反射、TCP 编程:服务器接收客户端消息】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址:https://developer.aliyun.com/learning/course/626/detail/9780


服务器接收客户端消息

 

内容介绍

一、开发的难度

二、客户端功能

三、客户端代码

四、修改服务端代码

 

一、开发的难度

写代码时可能写了一段服务器代码然后写客户端代码测试,然后在写服务器代码客户端代码测试这样的开发模式,但是如果服务器端和客户端不是同一个类型那就没有办法,只能自己写模拟程序,不能完全不测试,因为服务器代码很多,必须依赖客户端的测试才能成功。所以开发难度比单机版难。

 

二、客户端功能

1.续写一个客户端程序,能链接到服务器端的8888接口

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

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

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

 

三、客户端代码

1.代码

package  main  

import(

"fmt""

"net"

func main(){

conn, err := net.Dial("tcp", "192.168.20.253:8888")

if err !=nil{

fmt. Println("client dial err=",err)

return

fmt.Println(  "conn  成功=",conn)

(1)Dial 函数

Dial 函数和服务端建立连接:

conn, err := net.  Dial  ("tcp","google.com:,80")  

if err !=nil {

// handle error

fmt. Fprintf(conn, "GeT / HTTP/1.0\r\n\r\n")

status, err := bufio NewReader(conn).Readstring('\n')  

//...

(2)代码解释

google.com:,80"为对方服务器的 ip➕端口,因为一个程序一定是 ip➕端口才能区分究竟是与哪一个 ip进行沟通,一个 ip 地址可以跑几万个程序,所以不能只写 IP 不写端口。最后会返回conn连接,使两个连接兑上,就像打电话接通一样。bufioNewReader(conn).Readstring('\n')是想创建一个 reader,reader 可以接收键盘的输入,可以一行一行输,一个字符一个字符输入过慢

(3)查看连接

查看是否连上,服务器不可以关闭,新开一个

D:\go project\src\go_code\chapter18\tcpdemo\client>go run client.go

conn成功=&<<0xc04209a000>>

D:\go project\src\go_code\chapter18\tcpdemo\client>

显示等待客户端连接,表示成功

2.如何在服务器将IP地址显示出来?

在 server 中通过 conn,conn 中有一个方法是 RemoteAddr()Addr,返回的是 addr

type Addr interface {

Network()string//网络名

String()string  //字符串格式的地址  

addr 是一个接口,调 string 就可以得到字符串的地址

Server 中代码更改为fmt. Printf("Accept()conn. suc con=%V 客户端 ip=%v\n", conn,conn.RemoteAddr()  string()

重新连接看到显示客户端 ip=192.168.20.253:51741,客户端端口为51741,客户端端口是随机分配的。

 

四、修改服务端代码

接下来实现在服务端接收一句话并显示的功能

1.代码

func main() {

conn, err := net.Dial("tcp","192.168.20.253:8888")

if err != nil {

fmt.Println("client dial err=", err) return}

fmt.Println("conn 成功=",conn)

}

//功能一:客户端可以发送单行数据,然后就退出

reader := bufio.NewReader(os.stdin) //os.stdin 代表标准输入[终端]

//从终端读取一行用户输入,并准备发送给服务器

line, err := reader.Readstring("\n') if err != nil {

fmt.Println("readstring err=", err)

}

//再将line 发送给服务器

n,err := conn.write([]byte(line))

if err != nil {

fmt.Println("conn.write err=", err)

}

(1)os.stdin

Stdin、 Stdout 和 Stderr是指向标准输入、标准输出、标准错误输出的文件描述符。

var Args  []string

准确讲 stdin 指向的就是标准输入,标准输入指的就是终端,在底层中在终端中写东西也会落入到文件中去,另外一个是文件读取的,本质网络编程也是这样

(2)代码解释:

conn.write

//Write 方法可能会在超过某个固定时间限制后超时返回错误,该错误的 Timeout()方法返回真  

Write(b []byte)  (n int,err error)

客户端逻辑,先将号连上,再创建 new reader 再从键盘里得到一个输入发给 client,此时服务器未做接收

2.改 server

接收工作不要在主线写,在主线写会造成阻塞(有一个客户在向服务器发送数据时别的客户全部堵在这里)

package main

import(

"fmt'

"net"//做网络 socket 开发时,net 包含有我们需要所有的方法和函数  

"io"

func process(conn net.Conn) {

//这里我们循环的接收客户端发送的数据  

defer conn. close()//关闭 conn

for{

//创建一个新的切片

buf := make([]byte, 1024)

//conn.Read(buf)

//1.等待客户端通过conn发送信息

//2.如果客户端没有wrtie[发送],那么协程就阻塞在这里

fmt.Printf("服务器在等待客户端%s发送信息\n",    conn . RemoteAddr().string())  

n, err := conn.Read(buf)//从conn读取

if  err  s= io.EoF {

fmt.Println("客户端退出")

return //!

//3.显示客户端发送的内容到服务器的终端

fmt.print(string(buf[:n]))

}

}

Func main(){

fmt.Println("服务器开始监听....")

//net.Listen("tcp","0.0.0.0:8888")

//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()//延时关闭 listen

//循环等待客户端来链接我

for {

//等待客户端链接

fmt.Println("等待客户端来链接....") conn, err := listen.Accept()

if err != nil {

fmt.Println("Accept()err=",err)

} else {

fmt.Printf("Accept()suc con=%v 客户端ip=%v\n”,conn,conn.RemoteAddr().string())

}

//这里准备其一个协程,为客户端服务

Go process(conn)

}

//fmt.Printf("listen suc=%v\n",listen)

协程在处理时关键命令是协程一定要拿到连接,defer conn.Close 这里连接用完一定要关闭,如果这个连接不关闭连接会越来越多,服务器会因为连接没有释放而别的连接无法连上

如果服务器正在等待发送连接突然出现一个客户端直接关闭,导致连接无法收到,一旦检测到连接断掉也会报错,协程就会退出

连接的维护:每隔一段时间由 tcp 协议发送包:你还在吗?客户端通过 ycp 发送:我还在,隔一段时间发送一次。此过程我们无法看到

3.跑代码

D:\go project\src\go_code\chapter18\tcpdemo\client>go run client.go

hello,world,sgg回车

不停在循环,意味着一旦发生错误应该在

if err != nil {

fmt.Print1n("服务器的Read err=",err)

return

后加 return,不退出就会一直等

再次运行,没有出现问题

hello,world,ABC

服务器在等待客户端192.168.20.253:52156发送信息

服务器的 Read err=read tcp 192.168.20.253:8888->192.168.20.253:52156:wsarecv:An existing connection was forcibly closed by the remote host.

再去等待时发现对方已经关闭所以出错,这个错误信息可以不打出来,定义一个对方已退出

type Error interface {

error

Timeout()  bool  //错误是否为超时?                      

Temporary () bool // 错误是否是临时的?

}

Error代 表一个网络错误。

Erro 返回的还是一段字符串

相关文章
|
2月前
|
消息中间件 运维 网络协议
客户端和服务器之间的通信
客户端和服务器之间的通信
34 0
|
2月前
|
监控 关系型数据库 Linux
|
20天前
|
网络协议 Python
pythonTCP客户端编程连接服务器
【4月更文挑战第6天】本教程介绍了TCP客户端如何连接服务器,包括指定服务器IP和端口、发送连接请求、处理异常、进行数据传输及关闭连接。在Python中,使用`socket`模块创建Socket对象,然后通过`connect()`方法尝试连接服务器 `(server_ip, server_port)`。成功连接后,利用`send()`和`recv()`进行数据交互,记得在通信完成后调用`close()`关闭连接,确保资源释放和程序稳定性。
|
1月前
|
安全 数据处理 C#
C# Post数据或文件到指定的服务器进行接收
C# Post数据或文件到指定的服务器进行接收
|
2月前
|
网络协议 Java API
【JavaEE初阶】 TCP服务器与客户端的搭建
【JavaEE初阶】 TCP服务器与客户端的搭建
|
2月前
|
自然语言处理 Java 编译器
【JavaEE初阶】 UDP服务器与客户端的搭建
【JavaEE初阶】 UDP服务器与客户端的搭建
|
2月前
|
安全 Shell 网络安全
Git学习---Git快速入门、Git基础使用、Git进阶使用、Git服务器使用(IDEA集成GitHub、Gitee、GitLab)、GitHub Desktop客户端
Git学习---Git快速入门、Git基础使用、Git进阶使用、Git服务器使用(IDEA集成GitHub、Gitee、GitLab)、GitHub Desktop客户端
131 0
|
3月前
|
数据采集 JavaScript 前端开发
服务器端渲染(SSR)和客户端渲染(CSR)
服务器端渲染(SSR)和客户端渲染(CSR)
|
1月前
|
Ubuntu JavaScript 关系型数据库
在阿里云Ubuntu 20.04服务器中搭建一个 Ghost 博客
在阿里云Ubuntu 20.04服务器上部署Ghost博客的步骤包括创建新用户、安装Nginx、MySQL和Node.js 18.x。首先,通过`adduser`命令创建非root用户,然后安装Nginx和MySQL。接着,设置Node.js环境,下载Nodesource GPG密钥并安装Node.js 18.x。之后,使用`npm`安装Ghost-CLI,创建Ghost安装目录并进行安装。配置过程中需提供博客URL、数据库连接信息等。最后,测试访问前台首页和后台管理页面。确保DNS设置正确,并根据提示完成Ghost博客的配置。
在阿里云Ubuntu 20.04服务器中搭建一个 Ghost 博客
|
1月前
|
存储 弹性计算 数据可视化
要将ECS中的文件直接传输到阿里云网盘与相册(
【2月更文挑战第31天】要将ECS中的文件直接传输到阿里云网盘与相册(
420 4