TCP/IP
套接字关联和数据结构
底层FIFO缓冲区
Local IP
Local Port
Remote IP
Remote Prot
Closed
底层缓冲区可能带来的死锁风险
解决1:在独立线程中实现读写分离
解决2:分阻塞式I/O
应用的缓冲区
write(byte[] buf) -java的buf实际受限和底层的Send-Q
read(byte[] buf) -java的buf实际受限和底层的Recv-Q
性能相关
生命周期
客户端发起链接
服务端等待响应
关闭链接
TCP Socket
TCP的通信原理
TCP使用accept为每一个不同的客户端建立新的通信的Socket
Socket
API
close方法关闭Socket的输入输出流
shutDownOutput关闭Socket输出流
shutDownInput关闭Socket输入流
Socket Option
Server Socket
Socket Option
I/O
InputStream
API
read(byte[] b, int off, int len)
函数解析
方法会阻塞的读取数据
由输出端write输出数据,read并不表示会以一个整体接受数据
read需要调用多次来读取数据
参数解析
b -- 目标字节数组
off -- 在数组b在其中写入数据的起始位置的偏移<br>
len -- 要读取的字节数
返回值解析
该方法返回一个字符为整数。如果流已到达末尾,那么该方法返回-1。<br>
read(byte[] b)
等同与read(b,0,b.length)
available()
返回次输入流下一个方法调用可以不受阻塞地从输入流读取(或跳过)的估计字节数。下一个调可能是同一个线程,也可能是另一个线程。一次读取或跳过此估计数个字节不会受阻塞,但读取或跳过的字节数可能小于该数
readFully(byte[] b)
只有读取len长度个字节的时候才返回。否则阻塞等待,如果超时,则会抛出异常
OutputStream
API
write(byte[] b, int off, int len)
方法解析
将指定byte数组中从偏移量off开始的len个字节写入此输出流
OutputStream的write方法对每个要写出的字节调用一个参数的wrtie方法
子类重写此方法并提供更有效的实现
参数解析
b -- 数据
off -- 在数据偏移的开始
len -- 写入的字节数
write(byte[] b)
等同于write(b, 0, b.length)的效果完全相同
flush()
刷新此输出流并强制写出所有缓冲的输出字节
close()
关闭此输出流并释放与此流有关的所有系统资源
消息边界
TCP传输的数据不一定是以一个整体发送,又以一个整体的方式接收
UDP Socket
UDP的通信原理
UDP服务器端需要显示的设置端口,客户端无需设置
UDP服务器端可以使用同一个套接字与多个客户端通信
DatagramPacket就可以绑定目标地址和端口。DatagramSocket不必要connect目标地址和端口
DatagramPacket
作用:DatagramPacket是发送和接收对象
说明
DatagramPacket.getLength()会在发送或接收数据报文后更新为实际收发数
DatagramPacket在发送和接收数据后不会影响缓冲区的大小和偏移量的位置
DatagramPacket再次接收数据时会根据当前便宜位置覆盖已有的数据
DatagramPacket需要一个足够大的字节缓存数组来容纳接收到的数据
复制getData中的数据,需要注意缓冲数组的偏移位置、大小、实际长度
消息边界
以一个整体的send和receive方法间传递
DatagramPackage最大65507字节
DatagramSocket
DatagramSocket的连接
DatagramSocket的connect()方法是可选
建立连接就只能与该地址通信发送和接收
如果试图发送数据导其他地址会抛出异常
忽略接收来自其他地址和端口发来的信息
常用API
disconnect
断开套接字的连接,如果套接字没有连接,则此方法不执行任何操作
setTimeout
启用/禁用带有指定超时值的SO_TIMEOUT.以毫秒为单位。将此选项设为非零的超时值时,对此DatagramSocket调用receive()将只阻塞此时间长度
receive
此方法在接收到数据报前一直阻塞,数据报包对象的length字段包含所接收信息的长度,如果信息比包的长度长,该信息将被截短
阻塞和超时
accept、read、receive
ServerSocket-accept()
TCP-read
UDP-receive
write
write在没有足够的写缓冲区时,写操作也会阻塞
直到最后一个字节成功写入到TCP实现的本地缓存
如果可用的缓存控件比要写入的小,在write方法调用返回前,必须把一些数据成功传输到连接的另一端
write的阻塞时间最终取决于接收端
超时和打断write()方法没有提供超时和打断的机制
问题:尝试发送大良数据协议可能会长时间的组成
connect
避免连接阻塞
使用无参数的构造函数创建一个Socket
调用connect指定进程终端和连接时间
解决策略
setSoTimeout会设置一下阻塞方法的最长等待时间
ServerSocket.setSoTimeout()-->accept()
Socker.setSoTimeout()-->read()
Datagram.setSoTimeout()--receive()
Socket.available()->方法会监测Socket是否有可读数据
outTime策略
关闭连接
Http协议与回显协议的处理<br>Http的关闭发起者是服务端<br>回显的关闭发起者是客户端
Close方法关闭Socket的输入输出流
shutDownOutput关闭Socket输出流(在这之前发送的数据会继续发送到远程接收端,直到读取到-1)
shutDownOutput关闭Socket输入流在这之后不能从输入流读取到数据
Option
Socket:<br>keepAlive-检查通信的另一端是否活跃
Socket/DatagramSocket reveiceBufferSize/sendBUfferSize<br>建议尺寸,实际情况不一定如此
ServerSocket reveiceBufferSize
实际为accept的Socket创建缓冲区
ServerSocket不支持设置sendBufferSize
accept的Socket可以自行设置sendBufferSize
Socket/ServerSocket/DatagramSocketSoTimeout<br>setSoTimeout会设置一下阻塞方法的最长等待时间
ServerSocket.setSoTimeout()->accept();
Socket.setSoTimeout()->read()
Datagram.setSoTimeout()->receive()
Socket/ServerSocket/DatagramSocket ReuserAddress
Socket:TcpNodeply
是否禁止数据缓存延迟功能
不在等待缓冲区满后再发送
Socket:OOBinline-紧急数据
Java的实际情况是不能区分紧急数据
接收方需要开启setOOinline
发送方需要用sendurgentData
Socket:solinger
开启关闭停留功能
Socket:close将等待套接字缓冲区的数据发送完
DatagramSocket:broadcast-广播许可
设置系统是否开启广播
java默认是允许广播开启
Socket/DatagramSocket:TrafficClass-通信等级
实际情况会取决于网络通信商
Socket:perfermancePreFerence-性能服务
连接时间/延时/宽带
参数设置要在建立连接前设置
java会根据参数自动选择适合的协议