主题:Socket
一 使用Socket
1 Socket是两台主机之间的一个连接,它可以完成7个基本操作:
(1) 连接远程机器
(2) 发送数据
(3) 接收数据
(4) 关闭连接
(5) 绑定端口
(6) 监听入站数据
(7) 在绑定的端口上接收来自远程机器的连接
2 Java中的Socket连接基于C-S模式,客户端Socket使用Java提供的Socket类,完成前4个操作;服务端Socket使用Java提供的ServerSocket类,完成后3个操作。
3 使用客户端socket的一般方式
Socket socket = null;
try{
socket = new Socket("hostname", 13);
}catch(IOException e){
e.printTrace();
}finnaly{
if(socket!= null){
try{
socket.close()
}catch(Exception e){}
}
}
或
try(Socket socket = new Socket("hostname", 13)){
//do something
}catch(Exception e){
}
二 构造Socket
1 基本构造函数(目标端口范围1-65535,本地端口范围会随机选择1024-65535)
public Socket(String host, int port) throws UnknowHostException, IOException
public Socket(InetAddress host, int port) throws IOException
2 选择从哪个本地接口连接
public Socket(String host, int port, InetAddress interface, int localPort) throws UnknowHostException, IOException
public Socket(InetAddress host, int port, InetAddress interface, int localPort) throws UnknowHostException, IOException
3 构造但不连接
public Socket()
public void connect(SocketAddress endpoint) throws IOException
public void connect(SocketAddress endpoint, int timeout) throws IOException(超过等待时间则抛出异常,默认值0表示永远等待)
三 Socket地址
Java中表示Socket地址的抽象类是SocketAddress,目前JDK中只有一个子类,即InetSocketAddress。InetSocketAddress构造方法:
public InetSocketAddress(InetAddress address , int port)
public InetSocketAddress(String host , int port)
public InetSocketAddress(int port)(该方法只指定了端口,用在服务端)
InetSocketAddress只是存储一个连接地址,并没有尝试建立连接,所以,也可以在其他的Socket中复用。
四 判断一个Socket的连接状态
1 isClosed()方法
Socket未建立连接时:false
Socket成功建立连接时:false
Socket关闭时:true
2 isConnected()方法
Socket未建立连接时:false
Socket成功建立连接时:true
Socket关闭时:true
3 判断一个Socket当前是否打开
boolean connected = socket.isConnected() && ! socket.isClosed() ;
五 Socket的选项
1 TCP_NODELAY
正常情况下,小的数据包在发送前会组合为更大的数据包,在发送另一个包前,本地主机要等待远程系统对前一个包的确认。(Nagle算法)
所以对于依赖小数据量稳定传输的程序(比如实时跟踪鼠标移动),延迟会很严重。TCP_NODELAY会打破这种缓冲模式,数据包一旦就绪,就会发送。
2 SO_LINGER
默认情况下,当socket关闭时,如果有未发送完的数据,close方法会立即返回,但系统会接管发送队列并尝试发送剩余的数据。设置SO_LINGER之后,close方法会被阻塞指定时间(setSoLinger),等待发送数据和接收确认。如果过去相应时间后数据未发送完,则丢弃数据。
3 SO_TIMEOUT
设置socket读取数据的超时时间。如果超时则会抛出InterruptedIOException异常,但是Socket仍然是连接的,程序可以捕获这个异常并再次尝试读取socket内容。
4 SO_RCVBUF 和 SO_SNDBUF
设置发送和接收缓冲区的大小。需要注意的是,即使两个缓冲区设置为不同的大小,实际上两个缓冲区的真实大小会取两个设定值中较小的一个。
5 SO_KEEPALIVE
一般在长连接中使用,开始SO_KEEPALIVE之后,客户端通过一个空闲连接发送一个数据包,以确保服务器未崩溃。
六 服务器Socket(ServerSocket)的构造
ServerSocket一共有四个构造函数,前三个构造并绑定端口,最后一个构造但不绑定端口。
如果构造函数抛出BindException,说明无法创建Socket并绑定到端口;如果抛出IOException,那么可能有两种情况:一是目标端口正在被其他Socket使用;二是尝试绑定1-1024范围内的端口但没有root权限(Unix)。
1 public ServerSocket(int port) throws BindException, IOException
将Socket绑定到本地所以网络接口的某个端口上。
2 public ServerSocket(int port, int queueLength) throws BindException, IOException
将Socket绑定到本地所以网络接口的某个端口上,并且设置Socket的队列长度。
3 public ServerSocket(int port, int queueLength, InetAddress address) throws IOException
将Socket绑定到本地某个网络接口的某个端口上,设置Socket的队列长度。
4 public ServerSocket() throws IOException
public void bind(SocketAddress endpoint) throws IOException
public void bind(SocketAddress endpoint, int queueLength) throws IOException
先无参构造一个ServerSocket,之后使用bind()函数,绑定一个端口。
七 ServerSocket选项
1 SO_TIMEOUT
ServerSocket设置这个选项的目的是设置accept()方法阻塞的超时时间,默认只为0,表示永不超时;ServerSocket很少设置这个选项,因为一般都会让accept()函数一直运行,从而保证ServerSocket一直对端口进行监听。
2 SO_RCVBUF
设置服务器接收端的缓冲区大小。
3 SO_REUSEADDR
是否允许一个新的Socket绑定到之前使用过的一个端口上,而此时可能还有一些发送到原Socket的数据正在网络上传输。