- 浏览: 953108 次
文章分类
- 全部博客 (428)
- Hadoop (2)
- HBase (1)
- ELK (1)
- ActiveMQ (13)
- Kafka (5)
- Redis (14)
- Dubbo (1)
- Memcached (5)
- Netty (56)
- Mina (34)
- NIO (51)
- JUC (53)
- Spring (13)
- Mybatis (17)
- MySQL (21)
- JDBC (12)
- C3P0 (5)
- Tomcat (13)
- SLF4J-log4j (9)
- P6Spy (4)
- Quartz (12)
- Zabbix (7)
- JAVA (9)
- Linux (15)
- HTML (9)
- Lucene (0)
- JS (2)
- WebService (1)
- Maven (4)
- Oracle&MSSQL (14)
- iText (11)
- Development Tools (8)
- UTILS (4)
- LIFE (8)
最新评论
-
Donald_Draper:
Donald_Draper 写道刘落落cici 写道能给我发一 ...
DatagramChannelImpl 解析三(多播) -
Donald_Draper:
刘落落cici 写道能给我发一份这个类的源码吗Datagram ...
DatagramChannelImpl 解析三(多播) -
lyfyouyun:
请问楼主,执行消息发送的时候,报错:Transport sch ...
ActiveMQ连接工厂、连接详解 -
ezlhq:
关于 PollArrayWrapper 状态含义猜测:参考 S ...
WindowsSelectorImpl解析一(FdMap,PollArrayWrapper) -
flyfeifei66:
打算使用xmemcache作为memcache的客户端,由于x ...
Memcached分布式客户端(Xmemcached)
SocketChannelImpl 解析一(通道连接,发送数据):http://donald-draper.iteye.com/blog/2372364
SocketChannelImpl 解析二(发送数据后续):http://donald-draper.iteye.com/blog/2372548
引言:
前一篇文章我们看了一下SocketChannelImpl发送多个字节序列的过程,先来回顾一下:
SocketChannelImpl写ByteBuffer数组方法,首先同步写锁,确保通道,输出流打开,连接建立委托给IOUtil,将ByteBuffer数组写到输出流中,这一过程为获取存放i个字节缓冲区的IOVecWrapper,遍历ByteBuffer数组m,将字节缓冲区添加到iovecwrapper的字节缓冲区数组中,如果ByteBuffer非Direct类型,委托Util从当前线程的缓冲区获取容量为j2临时DirectByteBuffer,并将ByteBuffer写到DirectByteBuffer,并将DirectByteBuffer添加到iovecwrapper的字节缓冲区(Shadow-Direct)数组中,将字节缓冲区的起始地址写到iovecwrapper,字节缓冲区的实际容量写到iovecwrapper;遍历iovecwrapper的字节缓冲区(Shadow-Direct)数组,将Shadow数组中的DirectByteBuffer通过Util添加到本地线程的缓存区中,并清除DirectByteBuffer在iovecwrapper的相应数组中的信息;最后通过
SocketDispatcher,将iovecwrapper的缓冲区数据,写到filedescriptor对应的输出流中。
今天我们来看一下接受数据
再来看SocketChannelImpl的读操作
从输入流读取字节序列,写到buffer,有几点要关注
1.
2.
3.
下面我们分别来看这几点:
1.
//确保通道,输入流打开,通道连接建立
2.
3.
这里循环的原因,线程读输入流,有可能因为某种原因被中断,中断位消除,继续读取输入流,写到buffer
//IOUtil
来看readIntoNativeBuffer方法
readIntoNativeBuffer方法中一点我们需要关注:
//从输入流读取k个字节到buffer
//NativeDispatcher
从NativeDispatcher的pread方法可以看出,当前JDK版本,还不支持pread操作,我的JDK版本为1.7.0.17。
//SocketDispatcher
至此读输入流到buffer,已经看完,首先同步读写,确保通道,输入流打开,通道连接建立,
清除原始读线程,获取新的本地读线程,委托IOUtil读输入流到buffer;IOUtil读输入流到buffer,首先确保buffer是可写的,否则抛出IllegalArgumentException,然后判断buffer是否为Direct类型,是则委托给readIntoNativeBuffer,否则通过Util从当前线程缓冲区获取一个临时的DirectByteBuffer,然后通过readIntoNativeBuffer读输入流数据到临时的DirectByteBuffer,这一个过程是通过SocketDispatcher的read方法实现,读写数据到DirectByteBuffer中后,将DirectByteBuffer中数据,写到原始buffer中,并将
DirectByteBuffer添加到添加临时DirectByteBuffer到当前线程的缓冲区,以便重用,
因为重新DirectByteBuffer为直接操作物理内存,频繁分配物理内存,将耗费过多的资源。
在来看从输入流读取数据,写到多个buffer:
从输入流读取数据,写到多个buffer,我们只需要关注下面这点
这里循环的原因,线程读输入流,有可能因为某种原因被中断,中断位消除,继续读取输入流,写到buffer;
//IOUtil
再来看IOUtil写buffer数组的关键点
//SocketDispatcher
至此我们把SocketChannelImpl从输入流读取数据,写到ByteBuffer数组的read方法看完,首先同步写锁,确保通道,连接建立,输入流打开,委托给IOUtil,从输入流读取数据写到ByteBuffer数组中;IOUtil首先获取存放i个字节缓冲区的IOVecWrapper,遍历ByteBuffer数组m,将buffer添加到iovecwrapper的字节缓冲区数组中,如果ByteBuffer非Direct类型,委托Util从当前线程的缓冲区获取容量为j2临时DirectByteBuffer,并将ByteBuffer写到DirectByteBuffer,并将DirectByteBuffer添加到iovecwrapper的字节缓冲区(Shadow-Direct)数组中,将字节缓冲区的起始地址写到iovecwrapper,字节缓冲区的实际容量写到iovecwrapper;遍历iovecwrapper的字节缓冲区(Shadow-Direct)数组,将Shadow数组中的DirectByteBuffer通过Util添加到本地线程的缓存区中,并清除DirectByteBuffer在iovecwrapper的相应数组中的信息;最后通过
SocketDispatcher,从filedescriptor对应的输入流读取数据,写到iovecwrapper的缓冲区中。
总结:
读输入流到buffer,首先同步读写,确保通道,输入流打开,通道连接建立,
清除原始读线程,获取新的本地读线程,委托IOUtil读输入流到buffer;IOUtil读输入流到buffer,首先确保buffer是可写的,否则抛出IllegalArgumentException,然后判断buffer是否为Direct类型,是则委托给readIntoNativeBuffer,否则通过Util从当前线程缓冲区获取一个临时的DirectByteBuffer,然后通过readIntoNativeBuffer读输入流数据到临时的DirectByteBuffer,这一个过程是通过SocketDispatcher的read方法实现,读写数据到DirectByteBuffer中后,将DirectByteBuffer中数据,写到原始buffer中,并将
DirectByteBuffer添加到添加临时DirectByteBuffer到当前线程的缓冲区,以便重用,因为重新DirectByteBuffer为直接操作物理内存,频繁分配物理内存,将耗费过多的资源。
从输入流读取数据,写到ByteBuffer数组的read方法,首先同步写锁,确保通道,连接建立,输入流打开,委托给IOUtil,从输入流读取数据写到ByteBuffer数组中;IOUtil首先获取存放i个字节缓冲区的IOVecWrapper,遍历ByteBuffer数组m,将buffer添加到iovecwrapper的字节缓冲区数组中,如果ByteBuffer非Direct类型,委托Util从当前线程的缓冲区获取容量为j2临时DirectByteBuffer,并将ByteBuffer写到DirectByteBuffer,并将DirectByteBuffer添加到iovecwrapper的字节缓冲区(Shadow-Direct)数组中,将字节缓冲区的起始地址写到iovecwrapper,字节缓冲区的实际容量写到iovecwrapper;遍历iovecwrapper的字节缓冲区(Shadow-Direct)数组,将Shadow数组中的DirectByteBuffer通过Util添加到本地线程的缓存区中,并清除DirectByteBuffer在iovecwrapper的相应数组中的信息;最后通过
SocketDispatcher,从filedescriptor对应的输入流读取数据,写到iovecwrapper的缓冲区中。
SocketChannelImpl 解析四(关闭通道等):http://donald-draper.iteye.com/blog/2372717
SocketChannelImpl 解析二(发送数据后续):http://donald-draper.iteye.com/blog/2372548
引言:
前一篇文章我们看了一下SocketChannelImpl发送多个字节序列的过程,先来回顾一下:
SocketChannelImpl写ByteBuffer数组方法,首先同步写锁,确保通道,输出流打开,连接建立委托给IOUtil,将ByteBuffer数组写到输出流中,这一过程为获取存放i个字节缓冲区的IOVecWrapper,遍历ByteBuffer数组m,将字节缓冲区添加到iovecwrapper的字节缓冲区数组中,如果ByteBuffer非Direct类型,委托Util从当前线程的缓冲区获取容量为j2临时DirectByteBuffer,并将ByteBuffer写到DirectByteBuffer,并将DirectByteBuffer添加到iovecwrapper的字节缓冲区(Shadow-Direct)数组中,将字节缓冲区的起始地址写到iovecwrapper,字节缓冲区的实际容量写到iovecwrapper;遍历iovecwrapper的字节缓冲区(Shadow-Direct)数组,将Shadow数组中的DirectByteBuffer通过Util添加到本地线程的缓存区中,并清除DirectByteBuffer在iovecwrapper的相应数组中的信息;最后通过
SocketDispatcher,将iovecwrapper的缓冲区数据,写到filedescriptor对应的输出流中。
今天我们来看一下接受数据
再来看SocketChannelImpl的读操作
public int read(ByteBuffer bytebuffer) throws IOException { if(bytebuffer == null) throw new NullPointerException(); Object obj = readLock;//获取读锁 JVM INSTR monitorenter ;//进入同步,try if(!ensureReadOpen())//确保通道,输入流打开,通道连接建立 return -1; int i = 0; begin(); int k; Object obj3; Exception exception; synchronized(stateLock) { if(isOpen()) break MISSING_BLOCK_LABEL_146; k = 0; } //清除读线程 readerCleanup(); end(i > 0 || i == -2); obj3 = stateLock; JVM INSTR monitorenter ; if(i > 0 || isInputOpen) goto _L2; else goto _L1 _L1: -1; obj; JVM INSTR monitorexit ; return; _L2: obj3; JVM INSTR monitorexit ; goto _L3 exception; obj3; JVM INSTR monitorexit ; throw exception; _L3: if(!$assertionsDisabled && !IOStatus.check(i)) throw new AssertionError(); obj; JVM INSTR monitorexit ; return k; //初始化本地读线程 readerThread = NativeThread.current(); obj1; JVM INSTR monitorexit ; int j; do //委托IOUtil从输入流读取字节序列,写到bytebuffer i = IOUtil.read(fd, bytebuffer, -1L, nd, readLock); while(i == -3 && isOpen()); ... }
从输入流读取字节序列,写到buffer,有几点要关注
1.
if(!ensureReadOpen())//确保通道,输入流打开,通道连接建立 return -1;
2.
//清除读线程 readerCleanup();
3.
do //委托IOUtil从输入流读取字节序列,写到bytebuffer i = IOUtil.read(fd, bytebuffer, -1L, nd, readLock); while(i == -3 && isOpen());
下面我们分别来看这几点:
1.
if(!ensureReadOpen())//确保通道,输入流打开,通道连接建立 return -1;
//确保通道,输入流打开,通道连接建立
private boolean ensureReadOpen() throws ClosedChannelException { Object obj = stateLock; JVM INSTR monitorenter ; if(!isOpen())//通道打开 throw new ClosedChannelException(); if(!isConnected())//连接建立 throw new NotYetConnectedException(); if(!isInputOpen)//输入流打开 return false; true; obj; JVM INSTR monitorexit ; return; Exception exception; exception; throw exception; }
2.
//清除读线程 readerCleanup();
private void readerCleanup() throws IOException { //同步通道状态锁,清除读线程,如果通道关闭则,执行清除工作 synchronized(stateLock) { readerThread = 0L; if(state == 3) kill();//这个后面再讲 } }
3.
do //委托IOUtil从输入流读取字节序列,写到bytebuffer i = IOUtil.read(fd, bytebuffer, -1L, nd, readLock); while(i == -3 && isOpen());
这里循环的原因,线程读输入流,有可能因为某种原因被中断,中断位消除,继续读取输入流,写到buffer
//IOUtil
static int read(FileDescriptor filedescriptor, ByteBuffer bytebuffer, long l, NativeDispatcher nativedispatcher, Object obj) throws IOException { ByteBuffer bytebuffer1; //如果buffer为只读,则抛出IllegalArgumentException if(bytebuffer.isReadOnly()) throw new IllegalArgumentException("Read-only buffer"); //如果buffer为DirectBuffer,则委托给readIntoNativeBuffer if(bytebuffer instanceof DirectBuffer) return readIntoNativeBuffer(filedescriptor, bytebuffer, l, nativedispatcher, obj); //从当前线程缓存区获取临时的DirectByteBuffer bytebuffer1 = Util.getTemporaryDirectBuffer(bytebuffer.remaining()); int j; //委托readIntoNativeBuffer方法,读取输入流数据,到临时DirectByteBuffer int i = readIntoNativeBuffer(filedescriptor, bytebuffer1, l, nativedispatcher, obj); //读写模式切换 bytebuffer1.flip(); if(i > 0) //如果有数据被读取,则放到byteBuffer中 bytebuffer.put(bytebuffer1); j = i;//记录读取的字节数 //添加临时DirectByteBuffer到当前线程的缓冲区,以便重用, //因为重新DirectByteBuffer为直接操作物理内存,频繁分配物理内存,将耗费过多的资源。 Util.offerFirstTemporaryDirectBuffer(bytebuffer1); return j; Exception exception; exception; Util.offerFirstTemporaryDirectBuffer(bytebuffer1); throw exception; }
来看readIntoNativeBuffer方法
private static int readIntoNativeBuffer(FileDescriptor filedescriptor, ByteBuffer bytebuffer, long l, NativeDispatcher nativedispatcher, Object obj) throws IOException { int i = bytebuffer.position(); int j = bytebuffer.limit(); //如果断言开启,buffer的position大于limit,则抛出断言错误 if(!$assertionsDisabled && i > j) throw new AssertionError(); //获取需要读的字节数 int k = i > j ? 0 : j - i; if(k == 0) return 0; int i1 = 0; //从输入流读取k个字节到buffer if(l != -1L) i1 = nativedispatcher.pread(filedescriptor, ((DirectBuffer)bytebuffer).address() + (long)i, k, l, obj); else i1 = nativedispatcher.read(filedescriptor, ((DirectBuffer)bytebuffer).address() + (long)i, k); //重新定位buffer的position if(i1 > 0) bytebuffer.position(i + i1); return i1; }
readIntoNativeBuffer方法中一点我们需要关注:
//从输入流读取k个字节到buffer
if(l != -1L) i1 = nativedispatcher.pread(filedescriptor, ((DirectBuffer)bytebuffer).address() + (long)i, k, l, obj); else i1 = nativedispatcher.read(filedescriptor, ((DirectBuffer)bytebuffer).address() + (long)i, k);
//NativeDispatcher
int pread(FileDescriptor filedescriptor, long l, int i, long l1, Object obj) throws IOException { throw new IOException("Operation Unsupported"); }
从NativeDispatcher的pread方法可以看出,当前JDK版本,还不支持pread操作,我的JDK版本为1.7.0.17。
//SocketDispatcher
int read(FileDescriptor filedescriptor, long l, int i) throws IOException { return read0(filedescriptor, l, i); } static native int read0(FileDescriptor filedescriptor, long l, int i) throws IOException;
至此读输入流到buffer,已经看完,首先同步读写,确保通道,输入流打开,通道连接建立,
清除原始读线程,获取新的本地读线程,委托IOUtil读输入流到buffer;IOUtil读输入流到buffer,首先确保buffer是可写的,否则抛出IllegalArgumentException,然后判断buffer是否为Direct类型,是则委托给readIntoNativeBuffer,否则通过Util从当前线程缓冲区获取一个临时的DirectByteBuffer,然后通过readIntoNativeBuffer读输入流数据到临时的DirectByteBuffer,这一个过程是通过SocketDispatcher的read方法实现,读写数据到DirectByteBuffer中后,将DirectByteBuffer中数据,写到原始buffer中,并将
DirectByteBuffer添加到添加临时DirectByteBuffer到当前线程的缓冲区,以便重用,
因为重新DirectByteBuffer为直接操作物理内存,频繁分配物理内存,将耗费过多的资源。
在来看从输入流读取数据,写到多个buffer:
public long read(ByteBuffer abytebuffer[], int i, int j) throws IOException { //校验参数 if(i < 0 || j < 0 || i > abytebuffer.length - j) throw new IndexOutOfBoundsException(); Object obj = readLock;//获取读锁 JVM INSTR monitorenter ;//进入同步,try if(!ensureReadOpen())//确保通道打开,连接建立,输入流打开 return -1L; long l = 0L; begin();//与end协同,记录中断器,处理读操作过程中的中断问题 long l2; Object obj3; Exception exception; synchronized(stateLock) { if(isOpen()) break MISSING_BLOCK_LABEL_177; l2 = 0L; } //清除原始读线程 readerCleanup(); end(l > 0L || l == -2L); obj3 = stateLock; JVM INSTR monitorenter ; if(l > 0L || isInputOpen) goto _L2; else goto _L1 _L1: -1L; obj; JVM INSTR monitorexit ; return; _L2: obj3; JVM INSTR monitorexit ; goto _L3 exception; obj3; JVM INSTR monitorexit ; throw exception; _L3: if(!$assertionsDisabled && !IOStatus.check(l)) throw new AssertionError(); obj; JVM INSTR monitorexit ; return l2; //获取本地读线程 readerThread = NativeThread.current(); obj1; JVM INSTR monitorexit ; long l1; do //委托给IOUtil,从输入流读取数据,写到多个buffer l = IOUtil.read(fd, abytebuffer, i, j, nd); while(l == -3L && isOpen()); l1 = IOStatus.normalize(l); }
从输入流读取数据,写到多个buffer,我们只需要关注下面这点
do //委托给IOUtil,从输入流读取数据,写到多个buffer l = IOUtil.read(fd, abytebuffer, i, j, nd); while(l == -3L && isOpen());
这里循环的原因,线程读输入流,有可能因为某种原因被中断,中断位消除,继续读取输入流,写到buffer;
//IOUtil
static long read(FileDescriptor filedescriptor, ByteBuffer abytebuffer[], int i, int j, NativeDispatcher nativedispatcher) throws IOException { IOVecWrapper iovecwrapper; boolean flag; int k; //获取存放i个byteBuffer的IOVecWrapper iovecwrapper = IOVecWrapper.get(j); flag = false; k = 0; long l1; int l = i + j; for(int i1 = i; i1 < l && k < IOV_MAX; i1++) { ByteBuffer bytebuffer = abytebuffer[i1]; if(bytebuffer.isReadOnly()) throw new IllegalArgumentException("Read-only buffer"); int j1 = bytebuffer.position(); int k1 = bytebuffer.limit(); if(!$assertionsDisabled && j1 > k1) throw new AssertionError(); int j2 = j1 > k1 ? 0 : k1 - j1; if(j2 <= 0) continue; //将buffer添加到iovecwrapper的字节缓冲区数组中 iovecwrapper.setBuffer(k, bytebuffer, j1, j2); if(!(bytebuffer instanceof DirectBuffer)) { //获取容量为j2临时DirectByteBuffer ByteBuffer bytebuffer2 = Util.getTemporaryDirectBuffer(j2); //添加DirectByteBuffer到iovecwrapper的shadow buffer数组 iovecwrapper.setShadow(k, bytebuffer2); bytebuffer = bytebuffer2; j1 = bytebuffer2.position(); } //将字节缓冲区的起始地址写到iovecwrapper iovecwrapper.putBase(k, ((DirectBuffer)bytebuffer).address() + (long)j1); //将字节缓冲区的实际容量写到iovecwrapper iovecwrapper.putLen(k, j2); k++; } if(k != 0) break MISSING_BLOCK_LABEL_263; l1 = 0L; if(!flag) { for(int i2 = 0; i2 < k; i2++) { //获取iovecwrapper索引i2对应的字节序列副本 ByteBuffer bytebuffer1 = iovecwrapper.getShadow(i2); if(bytebuffer1 != null) //如果字节序列不为空,则添加到当前线程的缓存区中 Util.offerLastTemporaryDirectBuffer(bytebuffer1); //清除索引i2对应的字节序列在iovecwrapper中的字节序列数组,及相应副本数组的信息 iovecwrapper.clearRefs(i2); } } return l1; long l4; //委托给nativedispatcher,从filedescriptor对应的输入流读取数据,写到iovecwrapper的缓冲区中。 long l2 = nativedispatcher.readv(filedescriptor, iovecwrapper.address, k); }
再来看IOUtil写buffer数组的关键点
long l2 = nativedispatcher.readv(filedescriptor, iovecwrapper.address, k);
//SocketDispatcher
long readv(FileDescriptor filedescriptor, long l, int i) throws IOException { return readv0(filedescriptor, l, i); } static native long readv0(FileDescriptor filedescriptor, long l, int i) throws IOException;
至此我们把SocketChannelImpl从输入流读取数据,写到ByteBuffer数组的read方法看完,首先同步写锁,确保通道,连接建立,输入流打开,委托给IOUtil,从输入流读取数据写到ByteBuffer数组中;IOUtil首先获取存放i个字节缓冲区的IOVecWrapper,遍历ByteBuffer数组m,将buffer添加到iovecwrapper的字节缓冲区数组中,如果ByteBuffer非Direct类型,委托Util从当前线程的缓冲区获取容量为j2临时DirectByteBuffer,并将ByteBuffer写到DirectByteBuffer,并将DirectByteBuffer添加到iovecwrapper的字节缓冲区(Shadow-Direct)数组中,将字节缓冲区的起始地址写到iovecwrapper,字节缓冲区的实际容量写到iovecwrapper;遍历iovecwrapper的字节缓冲区(Shadow-Direct)数组,将Shadow数组中的DirectByteBuffer通过Util添加到本地线程的缓存区中,并清除DirectByteBuffer在iovecwrapper的相应数组中的信息;最后通过
SocketDispatcher,从filedescriptor对应的输入流读取数据,写到iovecwrapper的缓冲区中。
总结:
读输入流到buffer,首先同步读写,确保通道,输入流打开,通道连接建立,
清除原始读线程,获取新的本地读线程,委托IOUtil读输入流到buffer;IOUtil读输入流到buffer,首先确保buffer是可写的,否则抛出IllegalArgumentException,然后判断buffer是否为Direct类型,是则委托给readIntoNativeBuffer,否则通过Util从当前线程缓冲区获取一个临时的DirectByteBuffer,然后通过readIntoNativeBuffer读输入流数据到临时的DirectByteBuffer,这一个过程是通过SocketDispatcher的read方法实现,读写数据到DirectByteBuffer中后,将DirectByteBuffer中数据,写到原始buffer中,并将
DirectByteBuffer添加到添加临时DirectByteBuffer到当前线程的缓冲区,以便重用,因为重新DirectByteBuffer为直接操作物理内存,频繁分配物理内存,将耗费过多的资源。
从输入流读取数据,写到ByteBuffer数组的read方法,首先同步写锁,确保通道,连接建立,输入流打开,委托给IOUtil,从输入流读取数据写到ByteBuffer数组中;IOUtil首先获取存放i个字节缓冲区的IOVecWrapper,遍历ByteBuffer数组m,将buffer添加到iovecwrapper的字节缓冲区数组中,如果ByteBuffer非Direct类型,委托Util从当前线程的缓冲区获取容量为j2临时DirectByteBuffer,并将ByteBuffer写到DirectByteBuffer,并将DirectByteBuffer添加到iovecwrapper的字节缓冲区(Shadow-Direct)数组中,将字节缓冲区的起始地址写到iovecwrapper,字节缓冲区的实际容量写到iovecwrapper;遍历iovecwrapper的字节缓冲区(Shadow-Direct)数组,将Shadow数组中的DirectByteBuffer通过Util添加到本地线程的缓存区中,并清除DirectByteBuffer在iovecwrapper的相应数组中的信息;最后通过
SocketDispatcher,从filedescriptor对应的输入流读取数据,写到iovecwrapper的缓冲区中。
SocketChannelImpl 解析四(关闭通道等):http://donald-draper.iteye.com/blog/2372717
发表评论
-
文件通道解析二(文件锁,关闭通道)
2017-05-16 23:17 996文件通道解析一(读写操作,通道数据传输等):http://do ... -
文件通道解析一(读写操作,通道数据传输等)
2017-05-16 10:04 1105Reference定义(PhantomRefere ... -
文件通道创建方式综述
2017-05-15 17:39 939Reference定义(PhantomReference,Cl ... -
文件读写方式简单综述后续(文件,流构造)
2017-05-14 23:04 1406Java Socket通信实例:http://donald-d ... -
文件读写方式简单综述
2017-05-14 11:13 1075Java Socket通信实例:http://donald-d ... -
FileChanne定义
2017-05-12 23:28 875文件读写方式简单综述:http://donald-draper ... -
SeekableByteChannel接口定义
2017-05-11 08:43 1136ByteChannel,分散聚集通道接口的定义(SocketC ... -
FileChannel示例
2017-05-11 08:37 913前面我们看过socket通道,datagram通道,以管道Pi ... -
PipeImpl解析
2017-05-11 08:41 842ServerSocketChannel定义:http://do ... -
Pipe定义
2017-05-10 09:07 850Channel接口定义:http://donald-drape ... -
NIO-Pipe示例
2017-05-10 08:47 853PipeImpl解析:http://donald-draper ... -
DatagramChannelImpl 解析四(地址绑定,关闭通道等)
2017-05-10 08:27 696DatagramChannelImpl 解析一(初始化):ht ... -
DatagramChannelImpl 解析三(多播)
2017-05-10 08:20 1712DatagramChannelImpl 解析一(初始化):ht ... -
NIO-UDP实例
2017-05-09 12:32 1522DatagramChannelImpl 解析一(初始化):ht ... -
DatagramChannelImpl 解析二(报文发送与接收)
2017-05-09 09:03 1347DatagramChannelImpl 解析一(初始化):ht ... -
DatagramChannelImpl 解析一(初始化)
2017-05-08 21:52 1334Channel接口定义:http://donald-drape ... -
MembershipKeyImpl 简介
2017-05-08 09:11 877MembershipKey定义:http://donald-d ... -
DatagramChannel定义
2017-05-07 23:13 1187Channel接口定义:http://donald-drape ... -
MulticastChanne接口定义
2017-05-07 13:45 1073NetworkChannel接口定义:ht ... -
MembershipKey定义
2017-05-06 16:20 839package java.nio.channels; i ...
相关推荐
at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:574) at IceInternal.Network.doFinishConnect(Network.java:393) ... 6 more 这种报错是ICE服务端没有起来,telnet服务端ICE的端口不通...
防雷及短路计算软件
电线穿管选用小软件
小白python数据分析入门4Pandas可视化——板块8案例 2018幸福大数据,辅助8.1读取数据
电气照明照度计算软件
数据库模拟考试试卷试卷
算法是什么 划重点:算法是计算机科学与数学的边界,是一系列解决问题的清晰指令。 1、算法首先是数学的一部分,是子集而非全集只有那些能够被计算机实现的、而且用于解决实际问题的那部分数学内容,才能被纳入“算法”这个范畴,成为计算机科学的一部分,所以对于同一个数学问题,数学更加关心理论上能不能求解,而算法通常更关心是不是可以在有限的时间和空间内使用计算机求解。 2、算法是一系列解决问题的清晰指令就像是总指挥,需要不停地发送指令,一个算法的优劣可以用空间复杂度与时间复杂度来衡量,而算法工程师就是利用算法处理事物的人,因此逻辑完备和思路清晰是最重要的素质,通过这种方式,把想法通过算法的魔法变成“产品”,解决实际工程应用场景中的问题。 算法工程师承担的是整个工程中最核心的思路演绎,如果核心出了纰漏,则整个系统就容易出错,工程问题就得不到解决,1%的差错率都是不能被接受的。
W25Q512数据手册。The W25Q512JV (512M-bit) Serial Flash memory provides a storage solution for systems with limited space, pins and power. The 25Q series offers flexibility and performance well beyond ordinary Serial Flash devices. They are ideal for code shadowing to RAM, executing code directly from Dual/Quad SPI (XIP) and storing voice, text and data. The device operates on a single 2.7V to 3.6V power supply with current consumption as low as 1µA for power-down. All devices are offered in space-
电学计算软件
五子棋游戏想必大家都非常熟悉,游戏规则十分简单。游戏开始后,玩家在游戏设置中选择人机对战,则系统执黑棋,玩家自己执白棋。双方轮流下一棋,先将横、竖或斜线的5个或5个以上同色棋子连成不间断的一排者为胜。 【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、python、web、C#、EDA、proteus、RTOS等项目的源码。 【技术】 Java、Python、Node.js、Spring Boot、Django、Express、MySQL、PostgreSQL、MongoDB、React、Angular、Vue、Bootstrap、Material-UI、Redis、Docker、Kubernetes
单片机C语言Proteus仿真实例数码管显示的频率计提取方式是百度网盘分享地址
计算机设计大赛微课类别国赛一等奖作品时光修复-图像的平滑操作视频提取方式是百度网盘分享地址
Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。
Python源码-数学美之太阳花
五子棋游戏想必大家都非常熟悉,游戏规则十分简单。游戏开始后,玩家在游戏设置中选择人机对战,则系统执黑棋,玩家自己执白棋。双方轮流下一棋,先将横、竖或斜线的5个或5个以上同色棋子连成不间断的一排者为胜。 【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、python、web、C#、EDA、proteus、RTOS等项目的源码。 【技术】 Java、Python、Node.js、Spring Boot、Django、Express、MySQL、PostgreSQL、MongoDB、React、Angular、Vue、Bootstrap、Material-UI、Redis、Docker、Kubernetes
五子棋游戏想必大家都非常熟悉,游戏规则十分简单。游戏开始后,玩家在游戏设置中选择人机对战,则系统执黑棋,玩家自己执白棋。双方轮流下一棋,先将横、竖或斜线的5个或5个以上同色棋子连成不间断的一排者为胜。 【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、python、web、C#、EDA、proteus、RTOS等项目的源码。 【技术】 Java、Python、Node.js、Spring Boot、Django、Express、MySQL、PostgreSQL、MongoDB、React、Angular、Vue、Bootstrap、Material-UI、Redis、Docker、Kubernetes
Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。
Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。
数据库选择题库数据库选择
单片机C语言Proteus仿真实例数码管显示4×4键盘矩阵按键提取方式是百度网盘分享地址