专注收集记录技术开发学习笔记、技术难点、解决方案
网站信息搜索 >> 请输入关键词:
您当前的位置: 首页 > Go

golang socket 实现分析(1)

发布时间:2011-06-29 17:52:57 文章来源:www.iduyao.cn 采编人员:星星草
golang socket 实现分析(一)

socket:tcp/udp、ip构成了网络通信的基石,tcp/ip是面向连接的通信协议

            要求建立连接时进行3次握手确保连接已被建立,关闭连接时需要4次通信来保证客户端和,服务端都已经关闭

            在通信过程中还有保证数据不丢失,在连接不畅通时还需要进行超时重试等等

            所以socket就是封装了这一套基于tcp/udp/ip协议细节,提供了一系列套接字接口进行通信

  

client端通过以下方式与Server端进行通信

先看看再golang中如何进行socket编程

// 创建socket文件描述符,绑定ip:port,改变socket状态为监听状态
ln, err := net.Listen("tcp", addr)
// 返回时关闭tcp连接
defer l.Close()
if err != nil {
    return err
}
for {
    // 从socket recive队列里获取一个建立好的连接
    conn,err := ln.Accept()
    if err != nil {
        return err
    }
    // 新起一个goroutine处理连接
    go handler(conn)
}

func handler(conn net.Con) {
    // 关闭连接
    conn.Close()
}

 

介绍几个跟socket相关的底层函数

socketFunc func(int, int, int) (int, error) = syscall.Socket //创建一个socket文件描述符
func Bind(fd int, sa Sockaddr) (err error) //绑定一个本机IP:port到socket文件描述符上
listenFunc func(int, int) error = syscall.Listen //监听是否有tcp连接请求
acceptFunc func(int) (int, syscall.Sockaddr, error) = syscall.Accept //获取一个建立好的tcp连接
connectFunc func(int, syscall.Sockaddr) error = syscall.Connect //发起tcp连接请求
closeFunc func(int) error = syscall.Close //关闭连接

下面介绍下在golang中socket接口是如何通过这几个底层函数完成socket封装的。

 socket:创建的socket默认是阻塞的,通过syscall.SetNonblock()可以将socket设置为非阻塞模式

func sysSocket(family, sotype, proto int) (int, error) {
syscall.ForkLock.RLock()
//创建socket文件描述符 s, err :
= socketFunc(family, sotype, proto) if err == nil {
     // 关闭从父线程拷贝过来的文件描述符后,再执行子线程程序 syscall.CloseOnExec(s) } syscall.ForkLock.RUnlock()
if err != nil { return -1, os.NewSyscallError("socket", err) }

//设置socket位非阻塞
if err = syscall.SetNonblock(s, true); err != nil { closeFunc(s) return -1, os.NewSyscallError("setnonblock", err) } return s, nil } 

listen:设置socket文件描述符为监听状态,把监听到的请求放入未完成的请求队列中,完成3次握手后,会把连接放入已完成的请求队列中等待accept获取处理

func (fd *netFD) listenStream(laddr sockaddr, backlog int) error {
    if err := setDefaultListenerSockopts(fd.sysfd); err != nil {
        return err
    }
    if lsa, err := laddr.sockaddr(fd.family); err != nil {
        return err
    } else if lsa != nil {
       //绑定ip:port
        if err := syscall.Bind(fd.sysfd, lsa); err != nil {
            return os.NewSyscallError("bind", err)
        }
    }
    //监听socket文件描述符
    if err := listenFunc(fd.sysfd, backlog); err != nil {
        return os.NewSyscallError("listen", err)
    }
    if err := fd.init(); err != nil {
        return err
    }
    lsa, _ := syscall.Getsockname(fd.sysfd)
    fd.setAddr(fd.addrFunc()(lsa), nil)
    return nil
}

accept:从已完成的队列里取出一个tcp连接,返回的是由内核根据当前socket信息创建的全新的tcp连接来处理数据的,同时原始创建好的socket还可以继续监听其他连接请求,如果没有获取到则阻塞当前goroutine

func accept(s int) (int, syscall.Sockaddr, error) {
//获取连接 ns, sa, err := acceptFunc(s) if err == nil { syscall.CloseOnExec(ns) } if err != nil { return -1, nil, os.NewSyscallError("accept", err) }
//设置为非阻塞 if err = syscall.SetNonblock(ns, true); err != nil { closeFunc(ns) return -1, nil, os.NewSyscallError("setnonblock", err) } return ns, sa, nil }

connect:client端发起连接请求

//发起连接请求
func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time, cancel <-chan struct{}) error {
switch err := connectFunc(fd.sysfd, ra); err {
  //异常处理
    ....
}
}

close:

//关闭连接请求
func (fd *netFD) destroy() {
//关闭连接 fd.pd.Close()
//释放系统资源 closeFunc(fd.sysfd) fd.sysfd
= -1 runtime.SetFinalizer(fd, nil) }

 

友情提示:
信息收集于互联网,如果您发现错误或造成侵权,请及时通知本站更正或删除,具体联系方式见页面底部联系我们,谢谢。

其他相似内容:

  • ModernUI课程:定义一个Logo

    ModernUI教程:定义一个Logo ModernWindow的标题栏包含了一块区域用来显示自定义的窗体Logo: 这个窗体logo通过ModernWindow.LogoD...

  • Django忘记管理员账号和密码的解决方法

    Django忘记管理员账号和密码的解决办法 看着Django的教程学习搭建网站,结果忘记第一次创建的账号和密码了。结果搭建成功以后,一直...

  • GO语言小结(1)——基本知识

    GO语言总结(1)——基本知识 1、注释(与C++一样)   行注释://  块注释:/*   ...  */ 2、标识符   可以这么说,除了数字开头...

  • golang 惯用的文件读取方式

    golang 常用的文件读取方式 Golang 的文件读取方法很多,刚上手时不知道怎么选择,所以贴在此处便后速查。 一次性读取 小文件推荐一...

  • 查询深圳市通相关信息

    查询深圳通相关信息 用 HTTP.GET 从开放 API 中查询深圳通信息,然后将 JSON 数据存入结构体中,再格式化输出。 注意:获取的并不是实...

  • Go语言设计模式实践:结合(Composite)

    Go语言设计模式实践:组合(Composite) 关于本系列 这个系列首先是关于Go语言实践的。在项目中实际使用Go语言也有段时间了,一个体会就...

  • 列出索引和遍历目录

    列出目录和遍历目录 获取目录列表用 ioutil.ReadDir(),遍历目录用 filepath.Walk(),使用方法请参考文章示例。 示例代码: package ma...

  • io 包的惯用接口速记

    io 包的常用接口速记 我没有 C/C++ 基础,没有接口的概念,且从 Python 投奔而来,Python 的极简主义(一个结果往往只提供一个方法),让我在...

  • 代理服务扩充

    代理服务扩展 之前自己实现了一个代理服务,当时考虑的是只要支持SOCKS5就好了,因为我经常用CHROME,配合着SwitchySharp,体验还是很棒...

  • 文件的创造与打开

    文件的创建与打开 文件操作是个很重要的话题,使用也非常频繁,熟悉如何操作文件是必不可少的。Golang 对文件的支持是在 os package ...

热门推荐: