当前位置: 首页 > 科技观察

Golang网络编程Net包解析_0

时间:2023-03-13 16:53:18 科技观察

最近做一个项目,用到了网络编程。下面给大家分享一下Go语言中网络编程的实现。在Go中,网络编程主要是通过net包来实现的。支持包括TCP/IP、UDP、域名解析和Unix域套接字等连接。此外,它还通过net/http、net/rpc等为HTTP、RPC等主流应用层提供连接协议。1.TCP服务TCP是最常用的网络连接方式,以TCP连接为例,一个简单的TCP连接代码示例。客户端:packagemainimport("bufio""fmt""os""strings""net")funcmain(){conn,err:=net.Dial("tcp","tyun.cn:8088")iferr!=nil{//handle}deferconn.Close()inputReader:=bufio.NewReader(os.Stdin)for{//读取输入readString,_:=inputReader.ReadString('\n')trim:=strings.Trim(readString,"\r\n")_,err:=conn.Write([]byte(trim))如果err!=nil{return}buf:=[512]byte{}n,err:=conn.Read(buf[:])iferr!=nil{return}fmt.Println(string(buf[:n]))}}Server:packagemainimport("bufio""fmt""net")funcmain(){listen,err:=net.Listen("tcp",":8088")iferr!=nil{//handle}for{conn,err:=listen.Accept()iferr!=nil{//handlecontinue}deferconn.Close()for{//处理reader:=bufio.NewReader(conn)varbuf[1024]byteread,err:=reader.Read(buf[:])iferr!=nil{//handle}recv:=string(buf[:read])fmt.Println("GETMESSAGE:",recv)conn.Write([]byte(recv))}}}2.TCP连接在系统调用层的实际包中TCP/IP在类Unix操作系统中的各种网络连接都是通过网络系统调用来实现的。使用系统调用创建TCP服务器的核心流程是:首先要能创建socket,即要有create接口;首先要能创建socket,即,你必须有一个创建接口;其次,你要能绑定ip和端口号,也就是bind,不然别人找不到你;要连接,必须要有connect和accept的功能;而且,必须实现读写,即读和写,因为我们需要通过socket进行通信,所以读和写是不可能的;通信完成后,必须关闭socket;创建套接字连接s=socket(AF_INET,SOCK_STREAM,0);绑定地址bind(s,(structsockaddr*)&serv_addr,sizeof(serv_addr));开始听listen(s,5);接收客户端连接ns=accept(s,(structsockaddr*)&cli_addr,&clilen);接收数据n=read(ns,buffer,255);发送数据,n=write(ns,"helloworld",11)。创建TCP客户端的核心过程:创建socket连接s=socket(AF_INET,SOCK_STREAM,0);连接到服务器地址:connect(s,(structsockaddr*)&serv_addr,sizeof(serv_addr));接收数据n=read(ns,buffer,255);发送数据,n=write(ns,"helloworld",11)。socket()等系统调用的实现是在内核层面完成的,net包封装了这些底层进程。3、Go中TCP连接的实现在客户端中,建立连接conn,err:=net.Dial("tcp","tyun.cn:8088")的底层源码实现方法为:func(d*Dialer)DialContext(ctxcontext.Context,network,addressstring)(Conn,error)该方法解析网络和地址后,主要有两种连接方式:iflen(fallbacks)>0{c,err=sd.dialParallel(ctx,primaries,fallbacks)}else{c,err=sd.dialSerial(ctx,primaries)}这两个连接方法是调用:func(sd*sysDialer)dialSingle(ctxcontext.Context,raAddr)(cConn,errerror)sd.dialSingle支持4种类型:sd.dialTCP(ctx,la,ra)sd.dialUDP(ctx,la,ra)sd.dialIP(ctx,la,ra)sd.dialUnix(ctx,la,ra)继续追溯,可以看到实际上是调用了socket函数,实现了系统调用socket()。如果多个goroutine读写conn,就会出现多次读,多次写。socket是全双工的,读写不会互相影响。当多个goroutines读取时,这并不重要。因为如果读取了,就不会重复读取,多次读取不会造成安全问题。用多个goroutine写的时候,有一个问题。多个goroutine不能每次写一半。必须保证每次写入都是原子操作。幸运的是,在Go内部实现写的时候加了一把锁。TCP连接建立后,每当客户端发送请求时,服务器都会建立一个新的连接。conn,err:=listen.Accept()这个方法也往下走,可以看到底层实现其实是系统调用syscall.Accept。在连接通信过程中,如果一方突然关闭,对方会是什么反应?在实践过程中,总结如下:当对端异常关闭时,如果自己的socket中有数据,则自己方继续读取;当socket中没有数据时,己方read函数返回EOF;如果还在socket的buffer中写入,那么这次写入成功,下次会报错;·关闭端时,读写均异常错误。4.结语以上是关于围棋网络编程的一些分享。虽然net包提供了对网络原语的访问,但大多数用户只需要Dial、Listen和Accpet功能的基本接口;以及Conn和Listener接口。net包主要是增加了上下文控制,封装了一些不同的连接类型,DNS查找等,并在需要的地方引入了goroutine来提高处理效率。