java 网络编程之Socket详解
创建Socket:
使用Socket的有参构造方法,其都会试图建立与服务器端的连接,如果连接成功,就会返回Socket对象,如果因为某些原因连接失败,就会抛出IOEcpection
设定等待时间:
客户端的Socket构造方法请求与服务器端连接时,可能要等待一段时间,默认情况下,Socket会一直等下去,直到连接成功,或者出现异常。
设定如下:
Socket socket = new Socket();
SocketAddress address = new InetSocketAddress("localhost", 8888);
socket.connect(address, 5000);
InetSocketAddress : 根据 IP 地址和端口号创建套接字地址。
设定时间后,如果超出时间既没有连接成功,也没有异常,则会抛出SocketTimeOutException ,Socket的Connect()负责连接服务器,第一个参数为指定服务器地址,第二个擦数为设定时间,参数为0 则永不会超时。
客户端与服务器连接时的异常、:
UnKnownException: 如果无法识别主机的名字或IP地址。
ConnectionException: 如果没有服务器进程监听指定的接口,或者服务器进程拒绝连接。
SocketTimOutException: 如果等待连接超时,会抛出该类异常。
BindException:如果无法把Socket对象与指定的本地ip地址或端口号绑定,就会抛出这种异常。
获取Socket的信息:
在一个Socket中包含了远程服务器的ip地址和端口信息,以及客户本地的ip地址和端口信息,此外Socket对象还可以活的输入流,输出流用于用于读取服务器数据以及接收服务器数据
getInetAdress ():获取远程服务器的ip
getport():获取远程服务器的端口号。
getLocalAdress ():获得客户本地的ip
getLocalport ():获得本地的端口号
关闭Socket :
当客户与服务器通信结束后,应该及时关闭Socket,来释放socket占用的资源,当一个Socket对象关闭后,就不能够对其进行IO操作了,否则会导致IOException。(为了确保关闭Socket总是被执行,强烈建议将这个操作放在finally代码块中)
Socket类提供了3个状态测试的方法:
isClosed():如果Socket已经连接到远程主机并且还没有关闭,返回true,否则为false
isConnected():如果曾经连接到主机上返回true否则false
isBound():如果Socket已经与一个本地端口绑定,则返回true,否为false。判断一个Socket对象当前是否处于连接状态如下:
boolean isConnected = socket.isConnected ()&&!socket.isClosed ().
半关闭Socket:
shutdownInput ():半关闭输入流
shutdownOutput()关闭输出流。
假定进程1 先向进程2发送一串字符,然后调用shutdownOutput()关闭输出流。那么接下来1程序不允许在输出数据,但仍可以通过输入流读入数据。
注意:shutdownInput ():,shutdownOutput()仅仅是关闭了输入输出流不等价于调用了Socket的close()方法。因此通信完成后仍然要close()。释放资源。
设置Socket的选项:
TCP_NODELAY:表示立即发送数据。
在默认情况下采用的是Negale 算法,Negale算法是指发送的数据不会立刻发出,而是先放在缓冲区,等缓冲区满了在发送,发送完一批数据后会等待接收方对这批数据的回应,然后在发送一批数据,(Negale适用于需要发送大量数据并且接收方会及时做出回应的场合,这种算法通过减少传输的次数提高传输的效率)。
TCP_NODELAY 的默认值是false,表示采用Negale算法, 如果调用setTCPNoDelay(true)就会关闭socket的缓冲,数据会及时发送。
注意:如果Socket的底层不支持TCP_NODELAY选项调用 调用setTCPNoDelay()会抛出SocketException ()异常。
SO_RESUSEADDR:表示是否允许重用Socket所绑定的本地地址
当接收方通过Socket的close方法关闭时,如果网络上还有发送到这个Socket的数据,那么底层的Socket不会立刻释放本地端口,而是会等待一段时间确保接收到网络上发送的延迟数据,然后在释放端口,Socket接收到延迟数据后不做任何处理,Socket接收延时数据的目的是确保数据不会被碰巧绑定到同样端口的新进程接收到。
许多服务器使用固定的端口,当服务器关闭后,有可能其端口还会被占用一段时间,如果此时立刻在同一个主机上重启服务器程序,由于端口被占用,使得服务器无法绑定到该端口。
为了确保一个进程关闭Socket后,即使还没有释放端口,同一主机上的其它进程还可以立刻重用该端口,可以调用Socket的setResuseAdress (true):当然其必须放在Socket还没用绑定到一个端口之前
So_TIMEOUT :表示接受数据时等待的时间。
当通过Socket的输入读入数据时,如果没有数据会等待 通过setSoTimeout()设置等待时间单位位毫秒。So_TIMEOUT :其默认值是0 表示无限等待。当然setTimeOut()必须在接受数据之前执行才是有效的。
SO_LINGER :表示当执行Socket的close()方法后,是否立即关闭底层的Socket、
SO_LINGER 的默认情况下,执行Socket 的close()方法,该方法会立即返回,但底层的Socket实际上并不立即关闭,它会延迟一段时间,直到发送完所有剩余的数据,才会真正关闭Socket,断开连接。
socket.setSoLinger (true , 0):底层socket会随着close()一起关闭,所有发送玩的数据将被丢弃。
socket.setSoLinger (true , 360): 执行该方法后不会立即返回而是进入阻塞状态,底层的Socket会尝试发送剩余的数据,只有满足下条件之一才会退出:
1:地城Socket发送完所有的数据。
2:超出阻塞时间(有可能剩余数据还未发送完)也会返回,剩余的数据将被丢弃。()
这里所说的未发送完的数据是指 :还在网络上传送未被接收方接收到的数据。
SO_RCVBUF: 表示接收数据的缓冲区大小
设置该选项的方法: setReceiveBufferSize (int size )设置接收数据缓冲区的大小。
使用getReceiveBufferSize ()读取缓冲区的大小。
一般来说穿送大的连续数据块(基于http或Ftp)可以使用较大的缓冲区,减少传输次数,提高效率。对于交互频繁,数据量小的可以使用小缓冲区,确保小批量的数据能及时发送到
如果底层不支持SO_RCVBUF 会抛出SocketException。
SO_SNDBUF :表示发送数据的缓冲区的大小
使用setSendBufferSize()设置缓冲区的大小。getSendBufferSize ():读取缓冲区的大小。
SO_KEEPALIVE :表示处于长时间处于空闲状态的Socket,是否要把它自动关闭。
当SO_KEEPALIVE选项为true时,表示底层的TCP会监视该链接是否有效,当连接空等2小时时,本地的TCP会发送一个数据包给远程的Socket,如果远程的TCp没有响应,TCP实现就会持续尝试11分钟,直到接收到为止。,如果在12分钟时还未收到响应TCP就会自动关闭本地的socket。,不同的平台等待的时间不同。
OOBINLINE: 表示是否支持发送一个字节的TCP紧急报告。
使用setOOBInline ()设置,当其为true时,表示支持。其默认值是false,当接收方
接收到紧急数据时不做任何处理,直接将其丢弃。