DatagramChannel
1. DatagramChannel的初始化
DatagramChannel 的 open 方法创建一个 DatagramChannelImpl 对象的一个实例。
所以创建一个 DatagramChannel 就是创建 DatagramChannelImpl 类的一个对象。
下面,来梳理创建一个 DatagramChannelImpl 对象的时候,创建了什么
1 | class DatagramChannelImpl |
创建的 socket.
1 | // 可见在这里创建了一个 SOCK_DGRAM 数据报 Socket |
由此,可见创建一个 DatagramChannel , 其实就是创建一个 SOCK_DGRAM socket,然后将其文件描述符保存到 fd 对象中。
2. bind 的实现
对于 DatagramChannel 的 server 来说,其需要 bind 到一个本地IP和端口上,所以,需要调用 bind 方法。
bind 方法的作用:
When a socket is created with socket, it exists in a name space (address family) but has no address assigned to it. bind() assigns the address specified by addr to the socket referred to by the file descriptor sockfd.
Traditionally, this operation is called “assigning a name to a socket”.
DatagramChannel 实现的 bind 方法,除了调用上面的 bind 系统调用,还会初始化 DatagramChannelImpl 类的
1 | // Binding |
3. connect 的实现
DatagramChannel 调用 connect 方法之后,可以使用 write 方法,进行 channel 的写入了。否则使用 write 方法,将收到 NotYetConnectedException
1 | public DatagramChannel connect(SocketAddress sa) throws IOException { |
UDP socket 进行 connect 的作用:
If the socket sockfd is of type SOCK_DGRAM then addr is the address to which datagrams are sent by default, and the only address from which datagrams are received.
所以 connect 只是记录地址,这个地址将进行默认的收发操作。而不会像 SOCK_STREAM(TCP)类型的 socket , 会向这个 connect 的地址进行握手连接。
connect 方法可以被多次调用:
Generally, connection-based protocol sockets may successfully connect() only once; connectionless protocol sockets may use connect() multiple times to change their association.
getRemoteAddress
方法就可以获取到通过connect方法调用中提供的远程通信的socket的地址。
4. DatagramChannel 的 IO
send & receive
BSD Socket 提供的接口。
send
如果,当前 socket 已经处于 ST_CONNECTED 状态,则 send 方法调用 write 方法来实现。
如果 socket 没有 connect, 则最终调用系统的
sendto
方法进行数据发送。receive
调用系统的
recvfrom
方法获取数据。
write & read
channel 抽象中提供的接口。调用 write 和 read API 的时候,通道必须处于连接状态,否则,会出现 NotYetConnectedException
异常。
在 windows 平台上, write 和 read 最终使用 WSASend
和 WSARecv
来实现
在 linux 平台上,write 和 read 最终使用 recv
和 send
来实现。
两种IO方式的比较
使用 write 和 read 进行 channel IO 时,chennel 自身必须是已经 connected 过的。否则,会出现 NotYetConnectedException
异常。所以,即使是Server端的 DatagramChannel 也需要进行 connect.
杂项
jdk在不同平台的 native 方法的共享库的位置
在 windows 平台下其,位置是 %JAVA_HOME%/jre/bin,其中有 net.dll , nio.dll
在 linxu 平台下,其位置是 %JAVA_HOME%/jre/lib/amd64,其中有 libnet.so libnio.so 文件。
如何查看 so 文件中导出的符号
1 | nm -D libnet.so |
如果查看一个进程加载了哪些共享库
1 | ## 获得进程IO |