04-netty-socketaddress
最后更新于
最后更新于
Socket是一种建立客户端和服务器端连接的方式,这种方式在netty中尤其常见,在socket中客户端和服务器端需要一种机制来确定如何连接到对方,这种机制就是SocketAddress。
今天我们来详细讲解一下SocketAddress在netty中的实现。
SocketAddress听名字就知道它是一个地址,事实上它是在JDK中定义的,我们来看下它的具体定义:
SocketAddress在java.net包中,表示的是一个网络地址。
但是我们检查代码可以看到,SocketAddress中并没有任何内容,它的所有实现都在它的子类中,那么SocketAddress到底有那些实现类呢?
我们以一个图来观察一下,SocketAddress和它的子类实现:
可以看到,SocketAddress继承自Serializable,为什么要继承自Serializable呢?很明显SocketAddress要在网络中进行传输,所以必须要进行序列化。
SocketAddress有4个直接实现的子类分别是LocalAddress,EmbeddedSocketAddress,DomainSocketAddress,InetSocketAddress,还有两个间接实现的子类,分别是DatagramSocketAddress和DomainDatagramSocketAddress。
我们一起来看一下他们到底是什么用的。
首先是LocalAddress,LocalAddress表示的是本地的数据传输地址。localAddress中有两个属性:
这两个属性是从netty的channel中得到的,我们看下他们的实现逻辑:
可以看出,LocalAddress的id是依赖于channel的hashCode来生成,然后进行拼接而成的,拼接后的StringBuilder中的前6个字符就是id,整个StringBuilder的值就是strVal。
而这个ID的作用就是用判断不同的LocalAddress是否相同:
可以看到因为LocalAddress并没有涉及到IP地址,所以它只能在本地使用。
先来看下这个类的定义:
可以看到它自定义了一个toString方法,所以这个类的用处不对,主要使用在EmbeddedChannel中,表示嵌套的channel中的地址。
因为channel是嵌套的,所以它的LOCAL_ADDRESS和REMOTE_ADDRESS实际上是不存在的。
这个类应该是我们最常用到的socketAddress,因为它代表的是一个IP Socket Address,也就是IP address + port number, 这个IP地址也可以用hostname来替代。
InetSocketAddress中只有一个InetSocketAddressHolder类型的属性holder,而这个holder事实上是一个内部类,它定义了三个属性,分别是:
这三个属性正好对于了我们之前降到的IP socket address的几个特征。
其中InetAddress表示的是一个ip地址。
对于域名来说,有个解析的过程,所以InetSocketAddress提供了一个isUnresolved的方法判断。
DatagramSocketAddress是InetSocketAddress的子类,表示的是使用UDP协议的地址。
UDP Socket在JDK中有个专门的类叫做DatagramSocket,DatagramSocketAddress就是对应DatagramSocket的地址。
还记得UDP有什么特征吗?UDP和TCP相比的最大特点就是UDP非常简单,它自管发送消息就行了,不需要知道消息是否被收到。所以对于UDP来说,知道要接受的地址就够了,这个地址就是DatagramSocketAddress。
可以看到DatagramSocketAddress中有一个receivedAmount属性:
receivedAmount表示的是这个地址接收到的bytes数目。
注意这个类只在netty内部使用,主要用在Socket类中的两个方法,从ByteBuffer和memoryAddress中创建DatagramSocketAddress:
一般来说Socket Address需要一个IP地址,用来寻找到目标地址,但是对于UNIX来说,一切都是文件,为了提升UNIX平台中的数据传输效率,UNIX平台引入了一个新的数据在不同进程中交换的方法,这个方法就叫做Unix domain socket或者IPC socket。
DomainSocketAddress不是用IP进行传输的,而是用UNIX文件进行数据交换。
从类的实现来说,DomainSocketAddress中定义了一个socketPath的字符串,表示数据沟通的文件路径,也就是socketPath:
那么如何表明两个DomainSocketAddress是同一个address呢?
可以看到,只要是socketPath相同,那么这两个DomainSocketAddress就是相同的。
最后一个要讲的类是DomainDatagramSocketAddress,从名字可以看出,它是使用IPC来进行沟通的DatagramSocketAddress。
同样的,这个类中也有一个receivedAmount,表示这个地址接收到的字节数:
和DatagramSocketAddress一样,DomainDatagramSocketAddress也是一个内部使用的类。它也是用在Socket类中,用来从buf和memoryAddress中返回一个DomainDatagramSocketAddress:
这里的Socket是一个JNI的bridge类,上面所提到的方法实际上都调用的是native方法。
以上就是SocketAddress和它的各种address实现,当然我们最常用到的还是InetSocketAddress这个以IP为基础的Socket Address.