第二章 Scoket用法详解

构造Socket

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

1,Socket();

2,Socket(InetAddress address, int port) throws UnknownHostException, IOException

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

4,Socket(String host, int port) throws UnknownHostException, IOException

5,Sockett(String host, int port, InetAddress localAddr, int localPort) throws IOException

除了第一个不带参数的构造方法之外,其他的构造方法都会试图建立与服务器的连接,如果连接成功,就返回Scoket对象;如果因为某些原因是不,就会抛出Exception。

 

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

默认情况下,Scoket构造方法会一直等待下去,直到连接成功,或者出现异常。设置超时后,可能就会抛出SocketTimeoutException。

简单的例子,

Socket socket = new Socket();

SocketAddress remoteAddress = new InetSocketAddress("localhost", 8000);

socket.connect(remoteAddress, 6000);//超时时长为1分钟

 

设定客户端地址

设定服务端地址没什么可说的,要连接什么地方要说清楚的。默认情况下,客户端的IP地址来自于客户端程序所在的主机,客户端的端口则由系统随机分配,但是socket中有两个构造方法是显示的设置客户端的IP地址和端口,这样是有些主机同时属于两个以上的网络,可能拥有两个以上的IP地址,这样就就可以区分出来了。

 

 

客户端连接服务器可能抛出的异常

1,UnknowHostException,如果无法识别主机的名称或IP地址,就会抛出这种异常。

2,ConnectException,如果没有服务器进程监听指定的端口,或者服务器进程拒绝连接(已到达连接上限数),就会抛出这种异常。

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

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

以上都是IOException的子类。

 

获取Socket的信息
在一个Socket对象中同时包含了远程服务器的IP地址和端口信息,以及客户端本地的IP地址和端口信息。想要通信,必然还要有输入输出流,getInputStream()和getOutputStream(),这两个方法在Socket还没要连接,或者已经关闭,或者已经通过shutdownInput()或者shutdownOutput(),就会抛出IOException.

 

一个用Socket发HTTP请求的例子

 

 

关闭Socket

当客户端和服务器的通信结束,应该立即关闭Socket,以释放Socket占用的包括端口在内的各种资源。一个放在finally{}代码块中执行

另外,判断一个Socket是否处于连接状态

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

因为isConnected()的意思是Socket曾经连接到远程服务器

 

半关闭Socket

A与B通信结束的标示

1,发一个标示字符串,比如说“bye”;

2,A发给B内容之前,发送下整个内容的长度值

3,A发送完内容后,关闭Socket。这时B如果继续读取内容,就会是readLine为null,read()返回-1;

4,调用shutdownInput()或者shutdownOutput(),注意的是,即使两个都关了也不等同于close,因为端口之类的资源未释放,如果Sender调用了shutdownOutput, Reader继续读取内容时,就会是readLine为null,read()返回-1;

ps,如果Sender突然被杀死,比如System.exit(0),那么Reader继续read的时候就会有异常,

Exception in thread "main" java.net.SocketException: Connection reset

 

 

设置Socket的选项

1,TCP_NODELAY:表示立即发送数据

默认情况下,发送数据是采用的Negale算法,是指发送方发送的数据不会立刻发出,而是先放在缓冲区内,等缓冲区满了在发出,这个不适合需要实时响应的方式。

socket.setTcpNoDelay(true);

2,SO_RESUSEADDR:表示是否允许重阳Socket所绑定的本地地址。

当接收方通过Socket的close方法关闭Socket时,如果网络上还有发送到这个Socket的数据,那么底层的Socket不会立即是否本地端口,而是会等待一段时间,确保收到了网络上的延迟的数据,然后再释放端口。Socket接收到延迟的数据后,不会对这些数据做任何处理。Socket接收延迟数据的目的,确保这些数据不会被其他碰巧绑定到同样接口的新进程接收到。

socket.setResuseAddress(true);

要注意的是,这个方法必须在socket还没要绑定到一个本地端口之前调用,否则执行后是无效的,另外,两个共用一个端口的进程必须都调用socket.setResuseAddress(true);这样采用使得一个进程关闭socket后,另外一个进程的socket能够立刻重用相同的端口。

3,SO_TIMEOUT:表示接收数据时的等待超时时间,这是要注意的两个超时之一,连接超时,读取超时

如果输入流中没有数据,in.read(buf)就会等待发送方发送数据,知道满足以下情况才结束等待(buf为new byte[1024]):

1),输入流中有1024个字节,read方法把这些字节读入到buff中,再返回读取的字节数。

2),当已经快接近输入流的末尾,距离末尾还有小于1024个字节时,read()方法会把这些字节读入到buff中,再返回读取的字节数

3),已经读到输入流的末尾了,返回-1

4),连接已经断开,抛出IOEXception

5),如果设置了超时时长,抛出SocketTimeoutException

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

 

4,表示当执行Socket的close方法,是否立即关闭底层的socket。

默认情况下,执行Socket的close()方法,该方法会立即返回,但底层的socket实际上并不立即关闭,他会延迟一段时间知道发送所有的剩余的数据,才会真正的关闭socket。如果执行了setSoLinger(boolean on, int seconds),注意,这里的是秒,那么执行socket的close不会立即返回,而是进入阻塞,只有在底层socket发送完所有的剩余数据或者时间超过所设定的时长,这时剩余未发送完成的数据会被丢弃,当然,如果设置为setSoLinger(true, 0),就会立即返回,同时丢弃所有未发送完成的数据

 

当程序通过输出流写数据时,仅仅表示程序向网络提交了一批数据,由网络负载输送到接收方。当程序关闭Socket,有可能这批数据还在网络上传输,还未到达接收方,这里所说的“未发送完的数据”,就是指这种还在网络上传输,为被接收方接收的数据。

 

 

5,SO_SNFBUF, 表示发送数据的缓冲区的大小

6,SO_RCVBUF, 表示接收数据的缓冲区的大小

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

当空闲超过2个小时,会进行重联,重联若干次失败后,会关闭此socket

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


 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值