转一篇很全的关于Java Socket…

来源:互联网 发布:淘宝店铺排名怎么看 编辑:程序博客网 时间:2024/06/04 19:52
源地址:http://www.cnblogs.com/jerrychoi/archive/2010/04/15/1712931.html

Java学习总结之第十六章 Socket用法详解

一、构造Socket

Socket的构造方法有以下几种重载形式:

(1)Socket()

(2)Socket(InetAddress address, int port)throwsUnknownHostException,IOException

(3)Socket(InetAddress address, int port, InetAddress localAddr, intlocalPort)throws IOException

(4)Socket(String host, int port) throwsUnknownHostException,IOException

(5)Socket(String host, int port, InetAddress localAddr, intlocalPort) throws IOException

各构造方法的用法如下:

1. 设定等待建立连接的超时时间:

Socket socket=new Socket();

SocketAddress remoteAddr=newInetSocketAddress("localhost",8000);

//等待建立连接的超时时间为1分钟

socket.connect(remoteAddr, 60000);

2. 设定服务器的地址:

Socket(InetAddress address, int port)

Socket(String host, int port)

InetAddress类表示IP地址,其用法如下:

//返回本地主机的IP地址

InetAddress addr1=InetAddress.getLocalHost();

//返回代表"222.34.5.7"的IP地址

InetAddress addr2=InetAddress.getByName("222.34.5.7");

//返回域名为"www.javathinker.org"的IP地址

InetAddress addr3=InetAddress.getByName("www.javathinker.org");

3. 设定客户端的地址:

在一个Socket对象中,既包含远程服务器的IP地址和端口信息,也包含本地客户端的IP地址和端口信息。默认情况下,客户端的IP地址来自于客户程序所在的主机,客户端的端口则由操作系统随机分配。Socket类还有两个构造方法允许显式的设置客户端的IP地址和端口:

Socket(InetAddress address, int port, InetAddresslocalAddr, int localPort)throws IOException

Socket(String host, int port, InetAddresslocalAddr, int localPort) throws IOException

4. 客户连接服务器时可能抛出的异常:

当Socket的构造方法请求连接服务器时,可能会抛出以下异常:

l UnknownHostException:如果无法识别主机的名字或IP地址,就会抛出这种异常。

l ConnectException:如果没有服务器进程监听指定的端口,或者服务器进程拒绝连接,就会抛出这种异常。

l SocketTimeoutException:如果等待连接超时,就会抛出这种异常。

l BindException:如果无法把Socket对象与指定的本地IP地址或端口绑定,就会抛出这种异常。

二、获取Socket的信息

以下方法用于获取Socket的有关信息:

l getInetAddress():获得远程服务器的IP地址。

l getPort():获得远程服务器的端口。

l getLocalAddress():获得客户本地的IP地址。

l getLocalPort():获得客户本地的端口。

lgetInputStream():获得输入流。如果Socket还没有连接,或者已经关闭,或者已经通过shutdownInput()方法关闭输入流,那么此方法会抛出IOException。

lgetOutputStream():获得输出流。如果Socket还没有连接,或者已经关闭,或者已经通过shutdownOutput()方法关闭输出流,那么此方法会抛出IOException。

三、关闭Socket

1.当客户与服务器的通信结束,应该及时关闭Socket,以释放Socket占用的包括端口在内的各种资源。Socket的close()方法负责关闭Socket。推荐代码如下:

Socket socket=null;

try{

socket=new Socket("www.javathinker.org",80);

//执行接收和发送数据的操作

}catch(IOExceptione){

e.printStackTrace();

}finally{

try{

if(socket!=null)socket.close();

}catch(IOExceptione){e.printStackTrace();}

}

2. Socket类提供了三个状态测试方法:

l isClosed()

l isConnected()

l isBound()

3. 如果要判断一个Socket对象当前是否处于连接状态,可采用以下方式:

boolean isConnected=socket.isConnected() &&!socket.isClosed();

四、半关闭Socket

1. 有的时候,可能仅仅希望关闭输出流或输入流之一。此时可以采用Socket类提供的半关闭方法:

l shutdownInput():关闭输入流。

l shutdownOutput(): 关闭输出流。

2.先后调用Socket的shutdownInput()和shutdownOutput()方法,仅仅关闭了输入流和输出流,并不等价于调用Socket的close()方法。在通信结束后,仍然要调用Socket的close()方法,因为只有该方法才会释放Socket占用的资源,比如占用的本地端口等。

3. Socket类还提供了两个状态测试方法,用来判断输入流和输出流是否关闭:

l public boolean isInputShutdown()

l public boolean isOutputShutdown()

五、设置Socket的选项

Socket有以下几个选项:

n TCP_NODELAY:表示立即发送数据。

n SO_RESUSEADDR:表示是否允许重用Socket所绑定的本地地址。

n SO_TIMEOUT:表示接收数据时的等待超时时间。

n SO_LINGER:表示当执行Socket的close()方法时,是否立即关闭底层的Socket。

n SO_SNFBUF:表示发送数据的缓冲区的大小。

n SO_RCVBUF:表示接收数据的缓冲区的大小。

n SO_KEEPALIVE:表示对于长时间处于空闲状态的Socket,是否要自动把它关闭。

n OOBINLINE:表示是否支持发送一个字节的TCP紧急数据。

1. TCP_NODELAY选项

1) 设置该选项:public void setTcpNoDelay(boolean on) throwsSocketException

2) 读取该选项:public boolean getTcpNoDelay() throws SocketException

3)TCP_NODEALY的默认值为false,表示采用Negale算法。如果调用setTcpNoDelay(true)方法,就会关闭Socket的缓冲,确保数据及时发送:

if(!socket.getTcpNoDelay()) socket.setTcpNoDelay(true);

4)如果Socket的底层实现不支持TCP_NODELAY选项,那么getTcpNoDelay()和setTcpNoDelay()方法会抛出SocketException。

2. SO_RESUSEADDR选项

1) 设置该选项:public void setResuseAddress(boolean on) throwsSocketException

2) 读取该选项:public boolean getResuseAddress() throwsSocketException

3)为了确保一个进程关闭了Socket后,即使它还没释放端口,同一个主机上的其他进程还可以立刻重用该端口,可以调用Socket的setResuseAddress(true)方法:

if(!socket.getResuseAddress())socket.setResuseAddress(true);

4)值得注意的是socket.setResuseAddress(true)方法必须在Socket还没有绑定到一个本地端口之前调用,否则执行socket.setResuseAddress(true)方法无效。因此必须按照以下方式创建Socket对象,然后再连接远程服务器:

Socket socket = new Socket();//此时Socket对象未绑定到本地端口,并且未连接远程服务器

socket.setResuseAddress(true);

SocketAddress remoteAddr = new InetSocketAddress("remotehost",8000);

socket.connect(remoteAddr); //连接远程服务器,并且绑定匿名的本地端口

或者:

Socket socket = new Socket();//此时Socket对象未绑定到本地端口,并且未连接远程服务器

socket.setResuseAddress(true);

SocketAddress localAddr = new InetSocketAddress("localhost",9000);

SocketAddress remoteAddr = new InetSocketAddress("remotehost",8000);

socket.bind(localAddr); //与本地端口绑定

socket.connect(remoteAddr); //连接远程服务器,并且绑定匿名的本地端口

3. SO_TIMEOUT选项

1) 设置该选项:public void setSoTimeout(int milliseconds) throwsSocketException

2) 读取该选项:public int getSoTimeOut() throws SocketException

3)当通过Socket的输入流读数据时,如果还没有数据,就会等待。Socket类的SO_TIMEOUT选项用于设定接收数据的等待超时时间,单位为毫秒,它的默认值为0,表示会无限等待,永远不会超时。

4)Socket的setSoTimeout()方法必须在接收数据之前执行才有效。此外,当输入流的read()方法抛出SocketTimeoutException后,Socket仍然是连接的,可以尝试再次读取数据。

4. SO_LINGER选项

1) 设置该选项:public void setSoLinger(boolean on, int seconds) throwsSocketException

2) 读取该选项:public int getSoLinger() throws SocketException

3) SO_LINGER选项用来控制Socket关闭时的行为。

lsocket.setSoLinger(true,0):执行Socket的close()方法时,该方法也会立即返回,但底层的Socket也会立即关闭,所有未发送完的剩余数据被丢弃。

lsocket.setSoLinger(true,3600):执行Socket的close()方法时,该方法不会立即返回,而进入阻塞状态,同时,底层的Socket会尝试发送剩余的数据。只有满足以下两个条件之一,close()方法才返回:

n 底层的Socket已经发送完所有的剩余数据。

n尽管底层的Socket还没有发送完所有的剩余数据,但已经阻塞了3600秒。close()方法的阻塞时间超过3600秒,也会返回,剩余未发送的数据被丢弃。

以上两种情况内,当close()方法返回后,底层的Socket会被关闭,断开连接。

4) setSoLinger(boolean on ,intsecond)方法中的seconds参数以秒为单位,而不是以毫秒为单位。

5. SO_RCVBUF选项

1) 设置该选项:public void setReceiveBufferSize(int size) throwsSocketException

2) 读取该选项:public int getReceiveBufferSize() throwsSocketException

3) SO_RCVBUF表示Socket的用于输入数据的缓冲区的大小。

4)如果底层Socket不支持SO_RCVBUF选项,那么setReceiveBufferSize()方法会抛出SocketException。

6. SO_SNDBUF选项

1) 设置该选项:public void setSendBufferSize(int size) throwsSocketException

2) 读取该选项:public int getSendBufferSize() throws SocketException

3) SO_SNDBUF表示Socket的用于输出数据的缓冲区的大小。

4)如果底层Socket不支持SO_SNDBUF选项,setSendBufferSize()方法会抛出SocketException。

7. SO_KEEPALIVE选项

1) 设置该选项:public void setKeepAlive(boolean on) throwsSocketException

2) 读取该选项:public int getKeepAlive() throws SocketException

3) 当SO_KEEPALIVE选项为true,表示底层的TCP实现会监视该连接是否有效。

4)SO_KEEPALIVE选项的默认值为false,表示TCP不会监视连接是否有效,不活动的客户端可能会永久存在下去,而不会注意到服务器已经崩溃。

8. OOBINLINE选项

1) 设置该选项:public void setOOBInline(int size) throwsSocketException

2) 读取该选项:public int getOOBInline () throws SocketException

3) 当OOBINLINE为true时,表示支持发送一个字节的TCP紧急数据。Socket类的sendUrgentDate(intdata)方法用于发送一个字节的TCP紧急数据。

4)OOBINLINE的默认值为false,在这种情况下,当接收方收到紧急数据时不作任何处理,直接将其丢弃。如果用户希望发送紧急数据,应该把OOBINLINE设为true:socket.setOOBInline(true);此时接收方会把接收到的紧急数据与普通数据放在同样的队列中。值得注意的是,除非使用一些更高层次的协议,否则接收方处理紧急数据的能力非常有限,当紧急数据到来时,接收方不会得到任何通知,因此接收方很难区分普通数据与紧急数据,只好按照同样的方式处理它们。

9. 服务类型选项

1) IP规定了四种服务类型,用来定性的描述服务的质量:

l 低成本:发送成本低。

l 高可靠性:保证把数据可靠的送达目的地。

l 最高吞吐量:一次可以接收或发送大批量的数据。

l 最小延迟:传输数据的速度快,把数据快速送达目的地。

2) 这四种服务类型还可以进行组合,例如,可以同时要求获得高可靠性和最小延迟。Socket类中提供了设置和读取服务类型的方法:

l 设置服务类型:public void setTrafficClass(int trafficClass) throwsSocketException

l 读取服务类型:public int getTrafficClass() throws SocketException

3) Socket类用四个整数表示服务类型:

l 低成本:0x02 (二进制的倒数第二位为1)

l 高可靠性:0x04(二进制的倒数第三位为1)

l 最高吞吐量:0x08(二进制的倒数第四位为1)

l 最小延迟:0x10(二进制的倒数第五位为1)

10. 设定连接时间、延迟和带宽的相对重要性

public void setPerformancePreferences(int connectionTime,intlatency,int bandwidth)

以上方法的三个参数表示网络传输数据的三项指标:

n 参数connectionTime:表示用最少时间建立连接。

n 参数latency:表示最小延迟。

n 参数bandwidth:表示最高带宽。

setPerformancePreferences()方法用来设定这三项指标之间的相对重要性。可以为这些参数赋予任意的整数,这些整数之间的相对大小就决定了相应参数的相对重要性。例如,如果参数connectionTime为2,参数latency为1,而参数bandwidth为3,就表示最高带宽最重要,其次是最少连接时间,最后是最小延迟。

向文章作者 陆止于此海始于斯 致敬!

原创粉丝点击