• Go语言进阶,interface接口,socket套接字


            虽然Go语言没有类的概念,也没有所谓继承,所以谈不上属于真正的面向对象的编程语言,但是拥有非常灵活的接口概念,而且独特之处在于它是满足隐式实现的,不需要类似implements这样的关键字,编译器自动在需要的时候检查两个类型之间的实现关系。

    接口是一种双方的约定,其接口类型是对其他类型行为的抽象和概括,接口的实现者不需要关心接口会被怎样使用,调用者也不需要关心接口的实现细节,接口的定义和结构体类似,所以也是一种自定义类型,是一种抽象结构,不会暴露所含数据的格式、类型和结构。

    接口的实现与错误处理

    接口声明格式如下: 

    1. type 名称 interface{
    2. 方法名称1(参数...) (返回值...)
    3. 方法名称2(参数...) (返回值...)
    4. ...
    5. }

    具体来看一个示例,熟悉接口的声明与调用,然后针对接口的规范,我们故意设计一些出错的情况来了解它:

    1. package main
    2. import (
    3. "fmt"
    4. )
    5. // 声明一个Tester接口
    6. type Tester interface {
    7. PrintData(info interface{}) error
    8. }
    9. // 定义一个结构体实现这个接口
    10. type person struct {
    11. }
    12. // 实现接口里面的方法
    13. // error返回类型,表示可能发生的错误
    14. func (p *person) PrintData(info interface{}) error {
    15. fmt.Println(info)
    16. return nil
    17. }
    18. func main() {
    19. // 实例化person,类型是*person
    20. p := new(person)
    21. // 声明一个接口变量
    22. var tester Tester
    23. //将*person类型的p赋值给接口变量,虽然两个变量类型不一致。但是tester是一个接口,且p已经完全实现了接口的所有方法,因此赋值是成功的
    24. tester = p
    25. // 接口变量实现其定义的方法
    26. tester.PrintData("你好,寅恪光潜")
    27. }
    28. //你好,寅恪光潜

    错误一,方法名称需一致

    如果我们将PrintData方法名称修改为PrintData1,也就是说不去实现接口中的PrintData方法,虽然PrintData1写法都是合乎规范的,但由于修改的名称方法,没有实现,所以会报错:

    ./prog.go:29:11: cannot use p (variable of type *person) as type Tester in assignment:
        *person does not implement Tester (missing PrintData method)

    报错提示没有实现Tester接口里面的PrintData方法。也就是说tester = p这块的赋值就不会成功了。
    因为编译器扫描到这块赋值的时候,发现试着将*person类型赋值给tester时,需要检查*person类型是否完全实现了Tester接口。显然,编译器没有找到这个接口需要的PrintData方法,所以就会报错了。

    错误二,参数类型需一致

    如果我们将PrintData(info interface{})参数的类型修改为PrintData(info string),我们看下报错:

    ./prog.go:29:11: cannot use p (variable of type *person) as type Tester in assignment:
        *person does not implement Tester (wrong type for PrintData method)
            have PrintData(info string) error
            want PrintData(info interface{}) error

    这个就是方法参数类型不一致导致,所以类型也需要一样的才可以

    错误三,方法需全部实现

    由于接口是属于双方的一种约定,那么其定义的方法,就需要全部的实现,这样才可以被正确的编译执行。现在我们在Tester接口中增加一个方法:

    1. type Tester interface {
    2. PrintData(info interface{}) error
    3. //新增一个方法
    4. PrintData2() string
    5. }

    运行之后,将出现报错信息:

    ./prog.go:31:11: cannot use p (variable of type *person) as type Tester in assignment:
        *person does not implement Tester (missing PrintData2 method)

    就会提示这个Tester接口还有一个PrintData2()方法没有被实现。

    socket套接字

    socket是一种套接字,对于新手来说,套接字可能不好理解,你可以将它看做一种特殊的文件,可以连接打开与读写,因为起源于Linux,而Linux是将任何东西或设备都当文件来对待,这样去看待就很容易理解了。

    服务端:server.go

    1. package main
    2. import (
    3. "fmt"
    4. "log"
    5. "net"
    6. "bufio"
    7. )
    8. func handleConnection(conn net.Conn) {
    9. // 一直监听客户端的连接
    10. // 连接成功,如果客户端被强制中断,将报错:
    11. // 2022/11/05 11:37:05 客户端错误信息: read tcp 127.0.0.1:6010->127.0.0.1:3651: wsarecv: An existing connection was forcibly closed by the remote host.
    12. data, err := bufio.NewReader(conn).ReadString('\n')
    13. if err != nil {
    14. log.Fatal("客户端错误信息:", err)
    15. }
    16. fmt.Printf("%v", data)
    17. fmt.Fprintf(conn, "已连接到服务端\n")
    18. conn.Close()
    19. }
    20. func main() {
    21. ln, err := net.Listen("tcp", ":6010")
    22. if err != nil {
    23. panic(err)
    24. }
    25. for {
    26. conn, err := ln.Accept()
    27. if err != nil {
    28. log.Fatal("客户端连接错误:", err)
    29. }
    30. go handleConnection(conn)
    31. }
    32. }

    客户端:client.go

    1. package main
    2. import (
    3. "fmt"
    4. "net"
    5. "bufio"
    6. "log"
    7. )
    8. func main() {
    9. // 客户端连接服务端,服务端的端口是6010
    10. // 如果没有连接上或服务端没有开启,将报错:
    11. // 2022/11/05 12:01:09 服务器拒绝服务:dial tcp :6010: connectex: No connection could be made because the target machine actively refused it.exit status 1
    12. conn, err := net.Dial("tcp", ":6010")
    13. if err != nil {
    14. log.Fatal("服务器拒绝服务:",err)
    15. }
    16. // 如果客户端连接成功,服务端反馈显示:客户端已连接
    17. fmt.Fprintf(conn, "客户端已连接\n")
    18. data, err := bufio.NewReader(conn).ReadString('\n')
    19. if err != nil {
    20. panic(err)
    21. }
    22. fmt.Printf("%v", data)
    23. }

    然后分别各自启动,就可以看到它们的连接状态了。


    以下更多关于套接字的文章,多属于攻防方面,有兴趣的可以看下:

    Python嗅探socket

    Python的DoS拒绝服务之TCP/SYN洪水攻击

    Python使用nmap进行端口扫描

    Python遍历破解FTP密码,并上传webshell

  • 相关阅读:
    sqlserver 日志文件收缩
    The Linux Kernel ktime
    【SpringCloud微服务实战07】Sentinel 服务保护
    vue2.0/vue3.0 添加静态文件
    SpringBoot定时任务 - Spring自带的定时任务是如何实现的?有何注意点?
    Python使用jieba库分词并去除标点符号
    [git] 撤销 git reset –hard
    皕杰报表之小程序代码质量检测
    深度学习:资料整理
    给定两个字符串S和T,返回S子序列等于T的不同子序列个数有多少个? 如果得到子序列A删除的位置与得到子序列B删除的位置不同,那么认为A和B就是不同的。
  • 原文地址:https://blog.csdn.net/weixin_41896770/article/details/127702095