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

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

开发者学堂课程【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 返回的还是一段字符串

相关文章
|
29天前
|
Python
Socket学习笔记(二):python通过socket实现客户端到服务器端的图片传输
使用Python的socket库实现客户端到服务器端的图片传输,包括客户端和服务器端的代码实现,以及传输结果的展示。
115 3
Socket学习笔记(二):python通过socket实现客户端到服务器端的图片传输
|
29天前
|
JSON 数据格式 Python
Socket学习笔记(一):python通过socket实现客户端到服务器端的文件传输
本文介绍了如何使用Python的socket模块实现客户端到服务器端的文件传输,包括客户端发送文件信息和内容,服务器端接收并保存文件的完整过程。
115 1
Socket学习笔记(一):python通过socket实现客户端到服务器端的文件传输
|
24天前
|
网络协议 Ubuntu Linux
gpg从公钥服务器接收失败(gpg: keyserver receive failed: Server indicated a failure)
通过上述步骤,大多数情况下应该能够解决GPG从公钥服务器接收失败的问题。如果问题依旧存在,可能需要进一步调查与公钥服务器相关的更深层次的技术问题,或者考虑在相关社区论坛寻求帮助。
113 1
|
27天前
|
网络协议 Unix Linux
一个.NET开源、快速、低延迟的异步套接字服务器和客户端库
一个.NET开源、快速、低延迟的异步套接字服务器和客户端库
|
28天前
|
Python
Flask学习笔记(二):基于Flask框架上传图片到服务器端并原名保存
关于如何使用Flask框架上传图片到服务器端并以其原名保存的教程。
69 1
|
28天前
|
Python
Flask学习笔记(三):基于Flask框架上传特征值(相关数据)到服务器端并保存为txt文件
这篇博客文章是关于如何使用Flask框架上传特征值数据到服务器端,并将其保存为txt文件的教程。
29 0
Flask学习笔记(三):基于Flask框架上传特征值(相关数据)到服务器端并保存为txt文件
|
23天前
|
安全 区块链 数据库
|
6天前
|
弹性计算
阿里云2核16G服务器多少钱一年?亲测价格查询1个月和1小时收费标准
阿里云2核16G服务器提供多种ECS实例规格,内存型r8i实例1年6折优惠价为1901元,按月收费334.19元,按小时收费0.696221元。更多规格及详细报价请访问阿里云ECS页面。
39 9
|
3天前
|
监控 Ubuntu Linux
使用VSCode通过SSH远程登录阿里云Linux服务器异常崩溃
通过 VSCode 的 Remote - SSH 插件远程连接阿里云 Ubuntu 22 服务器时,会因高 CPU 使用率导致连接断开。经排查发现,VSCode 连接根目录 ".." 时会频繁调用"rg"(ripgrep)进行文件搜索,导致 CPU 负载过高。解决方法是将连接目录改为"root"(或其他具体的路径),避免不必要的文件检索,从而恢复正常连接。
|
6天前
|
弹性计算 异构计算
2024年阿里云GPU服务器多少钱1小时?亲测价格查询方法
2024年阿里云GPU服务器每小时收费因实例规格不同而异。可通过阿里云GPU服务器页面选择“按量付费”查看具体价格。例如,NVIDIA A100的gn7e实例为34.742元/小时,NVIDIA A10的gn7i实例为12.710156元/小时。更多详情请访问阿里云官网。
40 2
下一篇
无影云桌面