• (四十六)golang--网络编程(简易的聊天系统)


    Go主要的目标之一就是面向大规模后端服务程序,网络通信这块是服务端程序必不可少也是至关键的一部分。

    网络编程有两种:

    (1)TCP Socket编程:是网络编程的主流,之所以叫TCP Socket编程,是因为底层是基于TCP/IP协议的;

    (2)B/S结构的http编程,使用浏览器去访问服务器时,使用的就是http协议,而http底层就是tcp socket实现的;

    计算机间需要通讯,必须要有网线、网卡或者是无线网卡;

    TCP/IP模型:应用层、传输层、网络层、数据链路层、物理层;

    IP地址:每个internet上的主机和路由器都有一个ip地址,它包括网络号和主机号,ip地址有ipv4(32位)或ipv6(128位),可以通过Ipconfig查看。

    端口:逻辑意义上 的端口,特指tcp/ip协议中的端口。共256×256-1=65535个端口;

    端口分类:

    • 0是保留端口;
    • 1-1024是固定端口(22:ssh远程登录协议,23:telnet使用,21:ftp使用,25:smtp服务使用,80:lis使用,7:echo服务)
    • 1025-65535:是动态端口,供程序员使用;

    服务端和客户端之间通信框图:

    可以看出,它们之间的通信是通过端口 (由于是简易的通讯,目前客户端并不能直接交流,只能通过客户端)

    server.go

    package main
    
    import (
        "fmt"
        "net"
    )
    
    func process(conn net.Conn) {
        //这里接受客户端的数据
        defer conn.Close()
        for {
            //创建一个新的切片
            buf := make([]byte, 1024)
            //等待客户端发送信息,如果客户端没发送,协程就阻塞在这
            // fmt.Printf("服务器在等待客户端%v的输入
    ", conn.RemoteAddr().String())
            n, err := conn.Read(buf)
            if err != nil {
                // fmt.Println("服务器read err=", err)
                fmt.Println("客户端退出了")
                return
            }
            //显示客户端发送内容到服务器的终端
            fmt.Print(string(buf[:n]) + "
    ")
    
        }
    }
    
    func main() {
        fmt.Println("服务器开始监听...")
        //协议、端口
        listen, err := net.Listen("tcp", "0.0.0.0:8888")
        if err != nil {
            fmt.Println("监听失败,err=", err)
            return
        }
        //延时关闭
        defer listen.Close()
        for {
            //循环等待客户端连接
            fmt.Println("等待客户端连接...")
            conn, err := listen.Accept()
            if err != nil {
                fmt.Println("Accept() err=", err)
            } else {
                fmt.Printf("Accept() suc con=%v,客户端Ip=%v
    ", conn, conn.RemoteAddr().String())
            }
            //这里准备起个协程为客户端服务
            go process(conn)
        }
        //fmt.Printf("监听成功,suv=%v
    ", listen)
    }

    client.go

    package main
    
    import (
        "bufio"
        "fmt"
        "net"
        "os"
        "strings"
    )
    
    func main() {
        //同样是tcp协议,192.168.1.145服务端的ip地址,这里是我自己本机的地址,可在终端用ipconfig查看,后面是服务端开启的端口号
        conn, err := net.Dial("tcp", "192.168.1.145:8888")
        if err != nil {
            fmt.Println("client dial err=", err)
            return
        }
        //哭护短在命令行输入单行数据
        reader := bufio.NewReader(os.Stdin)
        for {
            //从终端读取一行用户的输入,并发给服务器
            line, err := reader.ReadString('
    ')
            if err != nil {
                fmt.Println("readString err=", err)
            }
            //去掉输入后的换行符
            line = strings.Trim(line, "
    ")
            //如果是exit,则退出客户端
            if line == "exit" {
                fmt.Println("客户端退出了")
                break
            }
            //将line发送给服务器
            _, e := conn.Write([]byte(line))
            if e != nil {
                fmt.Println("conn.write err=", e)
            }
            // fmt.Printf("客户端发送了%d字节的数据,并退出", n)
        }
    }

    首先在一个终端打开服务器:

    然后连接两个客户端:

    注意到,每个客户端的端口号是不一致的:

    然后两个客户端分别发送消息给服务端:

    服务端可以接收到信息:

     最后输入exit分别关闭两个客户端:

    两个客户端都退出了,然后服务端继续等待新的客户端的连接。 

  • 相关阅读:
    MEF 根据配置注入Service
    .Net创建windows服务入门
    MySQL中MAX函数与Group By一起使用的注意事项(转)
    .net core 跨平台实践
    python中的迭代器和生成器
    python抓取链家房源信息(二)
    scrapy抓取小说
    python的scrapy框架
    总结
    python抓取链家房源信息
  • 原文地址:https://www.cnblogs.com/xiximayou/p/11966620.html
Copyright © 2020-2023  润新知