Java Socket
1. 分类
流套接字(stream socket,基于TCP)和数据报套接字(datagram socket,基于UDP)
2. InetAddress
代表网络目标地址(network destination address)
两个子类:Inet4Address,Inet6Address代表IPV4和IPV6地址;
3. NetworkInterface
获取本地网络信息以及InetAddress类实例;
4. Socket和ServerSocket(TCP/IP套接字)
ServerSocket负责监听客户端的Socket,当有Socket请求到来时,服务端创建一个Socket实例与客户端Socket进行通信;
故服务器端要同时维护ServerSocket和Socket,而客户端则只维护Socket;
对于需要多线程处理的连接,通常即每个连接产生一个Socket,然后一个线程池中的一个线程持有这个Socket来处理该请求;
5. BIO/NIO/AIO区别
HTTP的请求模型:
HTTP的请求模型分为几步:建立连接->传输数据发送请求->处理->发送响应返回数据->断开连接
BIO即通常的请求模式(ServerSocket,Socket),当建立连接时,服务器分配一个线程处理该连接的请求;
该线程负责(传输数据发送请求->处理->发送响应返回数据)过程;
而NIO则将请求与连接分开,用SocketChannel来处理所有的连接,使用selector来对SocketChannel的请求进行轮询,如果有请求,则分配一个线程进行处理;
该线程仅负责(处理)这一步,(传输数据发送请求->发送响应返回数据)则通过selector轮询SocketChannel来处理;线程与SocketChannel之间需要有关联机制;
AIO则依赖操作系统来处理请求数据和返回数据,以及实现关联机制,实现真正的异步机制;
故可知,
因为BIO每个连接由对应的线程CPU来处理请求及响应,故会在I/O处浪费CPU资源,有可能会造成CPU瓶颈; 而NIO则由一个线程selector来处理所有的请求及响应,而专门的线程来处理每个请求,即所有连接的I/O由一个线程来处理,
节省了CPU,但如果I/O过多,可能会在selector处造成瓶颈;因为要处理线程处理结果与SocketChannel的对应关系,不适合用多个selector且也增加了模型的复杂度;
而AIO则去除了selector,I/O以及线程处理结果与I/O的对应关系由操作系统来完成,故效率最高,但需操作系统支持;
6. DatagramPacket和DatagramSocket(UDP套接字)
DatagramPacket对象是所存数据报的载体,存储了所传输的数据,端口号,远程地址等;
DatagramSocket的send方法负责发送DatagramPacket对象所包含的报文,而receive方法负责接收DatagramPacket对象所包含的报文;
注意:DatagramPacket对象最好不要复用,因为其会保留原始的长度信息,需要每次手动刷新;
其getData总是返回原始数组的大小,即使DatagramPacket本身包含了长度和偏移量的信息;
7. JAVA中UDP通信方式与TCP/IP通信的区别
UDP没有错误恢复机制,即send的数据并不会有超时重传及补传机制,同样receive也只接收一次send的数据;
UDP无须建立连接;
8. 发送和接收数据
发送方和接收方必须在信息的编码方式上达成一致;
如对于数字来说:发送信息的基本单位,高位在前还是低位在前,有符号无符号等都需考虑;
对于字符串来说,发送信息的基本单位,字符串的编码都需考虑;
9. 多任务处理
对于多个请求,可以产生多个Socket,然后提供给多个实现了Thread接口对象,由这些对象来启动多线程处理;
同时,也可以持有多个实现了Thread接口的对象的List,通过利用这些对象并改变该对象持有的Socket,来完成请求;
10.默认行为
可开启keepAlive(),即如果不段时间连接上不发送数据,则对另一端发送探测消息,确定连接是否正常;
可设置超时时间,即如果I/O操作超过一定时间不响应,则抛异常;
11.HTTP中的keep-alive与JAVA中的Socket
1)为何使用keep-alive
HTTP请求基于TCP/IP,如果多个请求都基于同一TCP/IP的连接,则可以节省每个单独建立TCP/IP连接的开销;
2)如何触发keep-alive
对于HTTP/1.0,需在头信息中加入Connection:keep-alive,而在HTTP/1.1中,则默认keep-alive;
3)服务器及浏览器对keep-alive的处理
一个原理:keep-alive需双方的参与,任何一方关闭都会使keep-alive结束;
HTTP/1.1规定服务器如果关闭keep-alive连接,需发出一个通知;
服务器端的处理通常会设置keep-alive有效时间,以在规定时间结束后可以释放连接占用的内存;如果有效,则会在响应头加入Connection:keep-alive;
而浏览器端则有可能使用keep-alive来利用TCP/IP连接,也可能直接新建TCP/IP连接来请求;
原因在于:随着硬件及操作系统的发展,客户端新建TCP/IP连接的开销实际上并不是很大,
比起等待第一个请求结束再发送第二个请求来说,直接新建多个TCP/IP来同时请求,得到响应的速度更快;
故事实上,keep-alive对于浏览器来讲,并不一定会提升性能,因为在客户端看来,瓶颈在服务器端的处理响应速度,而非浏览器多建几个TCP连接的时间和资源开销;
keep-alive对于服务器来讲,可以连接复用,节省资源,但是如果连接上总是没有请求,则该连接在该时间内则占用了服务器的内存,浪费资源
因此,keep-alive对于浏览器是多TCP/IP连接的CPU内存消耗和更快的得到处理结果的权衡;
对于服务器则是TCP/IP连接复用对CPU内存的节省和TCP/IP连接空置对CPU内存的浪费之间的合理权衡;
12.NIO
1)NIO的使用背景
多个Socket保持长连接,连接上请求很少,但该连接却需要单独一个线程,浪费了系统的线程资源;
需对不同的请求的设置处理优先级;
不同的请求需要修改相同的资源,需进行同步;
2)NIO解决的方法
一个selector线程执有所有Socket,对Socket上的请求进行轮询,如有I/O请求,由selector处理,其它请求则由selector处理I/O部分;
selector负责所有的线程转发,故可在转发层面控制请求的优先级;
selector暴露了buffer,使得通过控制buffer大小以及使用操作系统的缓存来优化系统成为可能;
13. Java Socket与底层TCP实现
TCP的Socket包含了sendQ(发送缓存),recvQ(接收缓存),Delivered(接收者从缓存读取的数据)
通用的发送过程:
1)TCP/IP连接的建立
TCP/IP连接建立需三次握手:客户端连接请求,服务端确认信息,客户端确认信息
对于Socket来说,当接收到服务端确认信息时(第2步),就认为连接建立,即Socket的状态为Established;
对于ServerSocket来说,当accept()方法接收到连接请求时,即产生Socket实例,认为连接建立,而非等到三次握手完成;
2)TCP/IP数据的发送接收
Socket调用write()方法,将数据写入底层sendQ,则wirte()方法完成;
写入前,如果wirte()的buffer比sendQ大,则会将buffer进行分组,待sendQ发送完一部分后,再写入,直至完全写入;
sendQ将数据发送到recvQ
依赖于底层实现,依靠重传机制来保证数据的正确有序到达recvQ
recvQ将数据传入read()
recvQ依据read()方法buffer的大小,分成合适的包传入read()
故write()结束并不代表数据已到达接收端,仅代表数据已写入sendQ,如传输过程中发生异常,则应用程序发送端不会收到任何通知;
3)TCP/IP连接关闭
Socket调用close()或者shutdownOutput()方法,则代表关闭;
而此时,仍有未发送的数据存在于sendQ中,如有异常,应用程序不会知道;
在TCP/IP协议中,则需要另一方也发送close()才算结束;
1. 分类
流套接字(stream socket,基于TCP)和数据报套接字(datagram socket,基于UDP)
2. InetAddress
代表网络目标地址(network destination address)
两个子类:Inet4Address,Inet6Address代表IPV4和IPV6地址;
3. NetworkInterface
获取本地网络信息以及InetAddress类实例;
4. Socket和ServerSocket(TCP/IP套接字)
ServerSocket负责监听客户端的Socket,当有Socket请求到来时,服务端创建一个Socket实例与客户端Socket进行通信;
故服务器端要同时维护ServerSocket和Socket,而客户端则只维护Socket;
对于需要多线程处理的连接,通常即每个连接产生一个Socket,然后一个线程池中的一个线程持有这个Socket来处理该请求;
5. BIO/NIO/AIO区别
HTTP的请求模型:
HTTP的请求模型分为几步:建立连接->传输数据发送请求->处理->发送响应返回数据->断开连接
BIO即通常的请求模式(ServerSocket,Socket),当建立连接时,服务器分配一个线程处理该连接的请求;
该线程负责(传输数据发送请求->处理->发送响应返回数据)过程;
而NIO则将请求与连接分开,用SocketChannel来处理所有的连接,使用selector来对SocketChannel的请求进行轮询,如果有请求,则分配一个线程进行处理;
该线程仅负责(处理)这一步,(传输数据发送请求->发送响应返回数据)则通过selector轮询SocketChannel来处理;线程与SocketChannel之间需要有关联机制;
AIO则依赖操作系统来处理请求数据和返回数据,以及实现关联机制,实现真正的异步机制;
故可知,
因为BIO每个连接由对应的线程CPU来处理请求及响应,故会在I/O处浪费CPU资源,有可能会造成CPU瓶颈; 而NIO则由一个线程selector来处理所有的请求及响应,而专门的线程来处理每个请求,即所有连接的I/O由一个线程来处理,
节省了CPU,但如果I/O过多,可能会在selector处造成瓶颈;因为要处理线程处理结果与SocketChannel的对应关系,不适合用多个selector且也增加了模型的复杂度;
而AIO则去除了selector,I/O以及线程处理结果与I/O的对应关系由操作系统来完成,故效率最高,但需操作系统支持;
6. DatagramPacket和DatagramSocket(UDP套接字)
DatagramPacket对象是所存数据报的载体,存储了所传输的数据,端口号,远程地址等;
DatagramSocket的send方法负责发送DatagramPacket对象所包含的报文,而receive方法负责接收DatagramPacket对象所包含的报文;
注意:DatagramPacket对象最好不要复用,因为其会保留原始的长度信息,需要每次手动刷新;
其getData总是返回原始数组的大小,即使DatagramPacket本身包含了长度和偏移量的信息;
7. JAVA中UDP通信方式与TCP/IP通信的区别
UDP没有错误恢复机制,即send的数据并不会有超时重传及补传机制,同样receive也只接收一次send的数据;
UDP无须建立连接;
8. 发送和接收数据
发送方和接收方必须在信息的编码方式上达成一致;
如对于数字来说:发送信息的基本单位,高位在前还是低位在前,有符号无符号等都需考虑;
对于字符串来说,发送信息的基本单位,字符串的编码都需考虑;
9. 多任务处理
对于多个请求,可以产生多个Socket,然后提供给多个实现了Thread接口对象,由这些对象来启动多线程处理;
同时,也可以持有多个实现了Thread接口的对象的List,通过利用这些对象并改变该对象持有的Socket,来完成请求;
10.默认行为
可开启keepAlive(),即如果不段时间连接上不发送数据,则对另一端发送探测消息,确定连接是否正常;
可设置超时时间,即如果I/O操作超过一定时间不响应,则抛异常;
11.HTTP中的keep-alive与JAVA中的Socket
1)为何使用keep-alive
HTTP请求基于TCP/IP,如果多个请求都基于同一TCP/IP的连接,则可以节省每个单独建立TCP/IP连接的开销;
2)如何触发keep-alive
对于HTTP/1.0,需在头信息中加入Connection:keep-alive,而在HTTP/1.1中,则默认keep-alive;
3)服务器及浏览器对keep-alive的处理
一个原理:keep-alive需双方的参与,任何一方关闭都会使keep-alive结束;
HTTP/1.1规定服务器如果关闭keep-alive连接,需发出一个通知;
服务器端的处理通常会设置keep-alive有效时间,以在规定时间结束后可以释放连接占用的内存;如果有效,则会在响应头加入Connection:keep-alive;
而浏览器端则有可能使用keep-alive来利用TCP/IP连接,也可能直接新建TCP/IP连接来请求;
原因在于:随着硬件及操作系统的发展,客户端新建TCP/IP连接的开销实际上并不是很大,
比起等待第一个请求结束再发送第二个请求来说,直接新建多个TCP/IP来同时请求,得到响应的速度更快;
故事实上,keep-alive对于浏览器来讲,并不一定会提升性能,因为在客户端看来,瓶颈在服务器端的处理响应速度,而非浏览器多建几个TCP连接的时间和资源开销;
keep-alive对于服务器来讲,可以连接复用,节省资源,但是如果连接上总是没有请求,则该连接在该时间内则占用了服务器的内存,浪费资源
因此,keep-alive对于浏览器是多TCP/IP连接的CPU内存消耗和更快的得到处理结果的权衡;
对于服务器则是TCP/IP连接复用对CPU内存的节省和TCP/IP连接空置对CPU内存的浪费之间的合理权衡;
12.NIO
1)NIO的使用背景
多个Socket保持长连接,连接上请求很少,但该连接却需要单独一个线程,浪费了系统的线程资源;
需对不同的请求的设置处理优先级;
不同的请求需要修改相同的资源,需进行同步;
2)NIO解决的方法
一个selector线程执有所有Socket,对Socket上的请求进行轮询,如有I/O请求,由selector处理,其它请求则由selector处理I/O部分;
selector负责所有的线程转发,故可在转发层面控制请求的优先级;
selector暴露了buffer,使得通过控制buffer大小以及使用操作系统的缓存来优化系统成为可能;
13. Java Socket与底层TCP实现
TCP的Socket包含了sendQ(发送缓存),recvQ(接收缓存),Delivered(接收者从缓存读取的数据)
通用的发送过程:
1)TCP/IP连接的建立
TCP/IP连接建立需三次握手:客户端连接请求,服务端确认信息,客户端确认信息
对于Socket来说,当接收到服务端确认信息时(第2步),就认为连接建立,即Socket的状态为Established;
对于ServerSocket来说,当accept()方法接收到连接请求时,即产生Socket实例,认为连接建立,而非等到三次握手完成;
2)TCP/IP数据的发送接收
Socket调用write()方法,将数据写入底层sendQ,则wirte()方法完成;
写入前,如果wirte()的buffer比sendQ大,则会将buffer进行分组,待sendQ发送完一部分后,再写入,直至完全写入;
sendQ将数据发送到recvQ
依赖于底层实现,依靠重传机制来保证数据的正确有序到达recvQ
recvQ将数据传入read()
recvQ依据read()方法buffer的大小,分成合适的包传入read()
故write()结束并不代表数据已到达接收端,仅代表数据已写入sendQ,如传输过程中发生异常,则应用程序发送端不会收到任何通知;
3)TCP/IP连接关闭
Socket调用close()或者shutdownOutput()方法,则代表关闭;
而此时,仍有未发送的数据存在于sendQ中,如有异常,应用程序不会知道;
在TCP/IP协议中,则需要另一方也发送close()才算结束;