zoukankan      html  css  js  c++  java
  • 实现简单服务器与客户端

    有些理论知识还是必须要知道的,不然只是参考别人的代码,终究是别人玩剩下来的东西。

    首先是服务端的制作
    因为要制作的是简单的服务端,所以服务端只需要有2个函数,一个函数作为程序的入口,也即main函数,一个函数对连接进行处理。这个对连接进行处理的函数很重要,之后再细讲。

    先贴上服务端代码
    package main

    import (
    “bufio”
    “fmt”
    “net”
    “os”
    “strings”
    )

    func process(conn net.Conn){
    defer conn.Close()
    reader:=bufio.NewReader(os.Stdin) //读取命令框里的数据
    for{
    var buf [1024]byte
    n,err:=conn.Read(buf[:]) //n为数据的大小
    if err!=nil{
    fmt.Println(“从客户端读取数据失败”,err)
    break
    }
    fmt.Println(“收到客户端数据”,string(buf[:n]))
    fmt.Println(“请回复”)
    msg,_:=reader.ReadString(‘\n’) //读取到换行符
    msg=strings.TrimSpace(msg) //把msg前后的空白都去掉
    if msg==”q”{
    break //退出阻塞状态
    }
    conn.Write([]byte(msg)) //向连接中写入数据.
    }
    }

    func main(){
    listen,err:=net.Listen(“tcp”,”127.0.0.1:8888”)
    if err!=nil{
    fmt.Println(“listen faild”,err)
    return
    }
    for{
    conn,err:=listen.Accept()
    if err!=nil{
    fmt.Println(“accept failed,err:”,err)
    continue
    }
    go process(conn)
    }
    }

    对服务端代码进行分析

    Conn接口代表通用的面向流的网络连接。多个线程可能会同时调用同一个Conn的方法。

    func process(conn net.Conn){

    }
    process函数传参 net.Conn 其实就是调用 net包里的Conn接口
    Conn接口 通过查询 golang中文库 可以知道它的方法有
    // Read从连接中读取数据
    // Read方法可能会在超过某个固定时间限制后超时返回错误,该错误的Timeout()方法返回真
    Read(b []byte) (n int, err error)
    // Write从连接中写入数据
    // Write方法可能会在超过某个固定时间限制后超时返回错误,该错误的Timeout()方法返回真
    Write(b []byte) (n int, err error)
    // Close方法关闭该连接
    // 并会导致任何阻塞中的Read或Write方法不再阻塞并返回错误
    Close() error
    // 返回本地网络地址
    LocalAddr() Addr
    // 返回远端网络地址
    RemoteAddr() Addr
    // 设定该连接的读写deadline,等价于同时调用SetReadDeadline和SetWriteDeadline
    // deadline是一个绝对时间,超过该时间后I/O操作就会直接因超时失败返回而不会阻塞
    // deadline对之后的所有I/O操作都起效,而不仅仅是下一次的读或写操作
    // 参数t为零值表示不设置期限
    SetDeadline(t time.Time) error
    // 设定该连接的读操作deadline,参数t为零值表示不设置期限
    SetReadDeadline(t time.Time) error
    // 设定该连接的写操作deadline,参数t为零值表示不设置期限
    // 即使写入超时,返回值n也可能>0,说明成功写入了部分数据
    SetWriteDeadline(t time.Time) error

    因为是最简单的服务端与客户端,所以我们不设置读写超时时间,不设置读取本地和远程地址,也就是说我们只需要用到 read 和 write即可

    reader:=bufio.NewReader(os.Stdin) //这里用到bufio包里的NewReader方法去读取os.Stdin的数据 os.Stdin其实就是键盘输入的数据
    这里可以理解为创建一个读取器 读取键盘数据

    var buf [1024]byte
    n,err:=conn.Read(buf[:])
    这里是声明了一个1024字节的数组 通过 conn接口的Read方法去读取缓冲区里的数据 n为返回数据大小,err为报错信息,这里缓冲区的数据其实就是客户端发送过来的数据。

    msg,:=reader.ReadString(‘\n’) //读取到换行符
    msg=strings.TrimSpace(msg) //把msg前后的空白都去掉
    if msg==”q”{
    break //退出阻塞状态
    }
    conn.Write([]byte(msg))
    用if判断报错就不分析了,没必要reader读取器的ReadString方法实现的是读取字符串的作用,msg,:=reader.ReadString(‘\n’) 指的是 读取到换行符的数据 保存在msg里,而且还是以字符串形式保存,
    strings.TrimSpace(msg) 是调用strings包里的TrimSpace方法去除字符串两边的空格,个人觉得可有可无。。

    conn.Write([]byte(msg)) 是将我们输入的数据写入到连接中

    服务端main方法研究

    listen,err:=net.Listen(“tcp”,”127.0.0.1:8888”)
    if err!=nil{
    fmt.Println(“listen faild”,err)
    return
    }
    通过调用net的Listen方法 设置tcp连接 和 通信的ip地址与端口

    for{
    conn,err:=listen.Accept()
    if err!=nil{
    fmt.Println(“accept failed,err:”,err)
    continue
    }
    go process(conn)
    }
    注意这里用到了一个阻塞状态,而且里面调用 listen.Accept() 意味着,可以不断收到信息,而不是收到了一条信息就停止了。 通过listen.Accept()获取连接的对象,go process(conn)是实现并发处理请求,这里客户端发起的请求如果没失败 就可以认为是一个conn。

    客户端主要功能就是向服务器发起请求建立连接,然后输入数据,等待服务器响应
    贴上代码,所以一个main函数即可。

    package main

    import (
    “bufio”
    “fmt”
    “net”
    “os”
    )

    func main(){
    conn,err:=net.Dial(“tcp”,”127.0.0.1:8888”) //向127.0.0.1:8888发起tcp连接
    if err!=nil{
    fmt.Println(“err: “,err)
    return
    }
    defer conn.Close()
    reader:=bufio.NewReader(os.Stdin) //阅读器 读取输入的数据
    for {
    fmt.Println(“请发送:”)
    msga,_:=reader.ReadString(‘\n’)
    if msga==”q”{
    break
    }
    conn.Write([]byte(msga))
    var buf [1024]byte
    n,err:=conn.Read(buf[:])
    if err!=nil{
    fmt.Println(“read from server faild”,err)
    break
    }
    fmt.Println(“收到服务器数据”,string(buf[:n]))
    }

    }

    conn,err:=net.Dial(“tcp”,”127.0.0.1:8888”) //向127.0.0.1:8888发起tcp连接
    if err!=nil{
    fmt.Println(“err: “,err)
    return
    }

    通过net包的Dial方法 设置 请求方式,请求地址,conn是通过请求建立的连接对象。

    defer conn.Close()
    主函数执行完毕后关闭连接

    reader:=bufio.NewReader(os.Stdin)
    设置阅读器,用来读取客户端传过来的数据

    for {
    fmt.Println(“请发送:”)
    msga,:=reader.ReadString(‘\n’)
    if msga==”q”{
    break
    }
    conn.Write([]byte(msga))
    var buf [1024]byte
    n,err:=conn.Read(buf[:])
    if err!=nil{
    fmt.Println(“read from server faild”,err)
    break
    }
    fmt.Println(“收到服务器数据”,string(buf[:n]))
    }
    客户端开启阻塞状态是为了能够持续发送数据, msga,:=reader.ReadString(‘\n’) 通过这种方式可简单的将输入的数据保存在msga里面 conn.Write写入msga保存的数据. 设置缓冲字节数组,通过这个数组 可以读取 服务端回复的数据,然后打印到界面上。

    欢迎关注我的私人博客: https://arg1nt.gitee.io/2021/03/01/go/#more
  • 相关阅读:
    centos7.3 安装 mysql5.7.13
    linux下MySQL的启动与访问
    使用jquery修改display属性
    浏览器在线预览pdf、txt、office文件
    查看java的jar包源码
    邮件群发器
    公司招聘asp.net程序员(已过期)
    javascript面向对象,实现namespace,class,继承,重载
    javascript window.close() 去掉那讨厌的确认对话框
    如果注定要分别
  • 原文地址:https://www.cnblogs.com/Arg1nt/p/14490531.html
Copyright © 2011-2022 走看看