1 / 36

Java 网络编程精解

Java 网络编程精解. 第 2 章 Socket 用法详解. 2.1 构造 Socket 2.2 获取 Socket 的信息 2.3 关闭 Socket 2.4 半关闭 Socket 2.5 设置 Socket 的选项 2.6 发送邮件的 SMTP 客户程序 . 参考 《Java 网络编程精解 》 的第 2 章. 2.1 构造 Socket. Socket 的构造方法有以下几种重载形式: ( 1 ) Socket()

ulric-wells
Download Presentation

Java 网络编程精解

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Java网络编程精解

  2. 第2章 Socket用法详解 • 2.1 构造Socket • 2.2 获取Socket的信息 • 2.3 关闭Socket • 2.4 半关闭Socket • 2.5 设置Socket的选项 • 2.6 发送邮件的SMTP客户程序 参考《Java网络编程精解》的第2章

  3. 2.1 构造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)Socket(String host, int port, InetAddress localAddr, int localPort) throws IOException

  4. 2.1.1 设定等待建立连接的超时时间 • 设定等待建立连接的超时时间 Socket socket=new Socket(); SocketAddress remoteAddr=new InetSocketAddress("localhost",8000); //等待建立连接的超时时间为1分钟 socket.connect(remoteAddr, 60000);

  5. 2.1.2 设定服务器的地址 • Socket(InetAddress address, int port) Socket(String host, int port) • InetAddress的用法如下: //返回本地主机的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");

  6. 2.1.3 设定客户端的地址 • 在一个Socket对象中,既包含远程服务器的IP地址和端口信息,也包含本地客户端的IP地址和端口信息。默认情况下,客户端的IP地址来自于客户程序所在的主机,客户端的端口则由操作系统随机分配。Socket类还有两个构造方法允许显式的设置客户端的IP地址和端口: • Socket(InetAddress address, int port, InetAddress localAddr, int localPort)throws IOException • Socket(String host, int port, InetAddress localAddr, int localPort) throws IOException

  7. 2.1.4 客户连接服务器时可能抛出的异常 • 当Socket的构造方法请求连接服务器时,可能会抛出以下异常: • UnknownHostException:如果无法识别主机的名字或IP地址,就会抛出这种异常。 • ConnectException:如果没有服务器进程监听指定的端口,或者服务器进程拒绝连接,就会抛出这种异常。 • SocketTimeoutException:如果等待连接超时,就会抛出这种异常。 • BindException:如果无法把Socket对象与指定的本地IP地址或端口绑定,就会抛出这种异常。

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

  9. 2.1.4 客户连接服务器时可能抛出的异常 • 抛出UnknownHostException的情况:如果无法识别主机的名字或IP地址,就会抛出这种异常。 • 抛出ConnectException的情况: • 没有服务器进程监听指定的端口。 • 服务器进程拒绝连接。 • 抛出SocketTimeoutException的情况:如果客户端等待连接超时,就会抛出这种异常。 • 抛出BindException的情况:如果无法把Socket对象与指定的本地IP地址或端口绑定,就会抛出这种异常。

  10. 2.2 获取Socket的信息 • 以下方法用于获取Socket的有关信息: • getInetAddress():获得远程服务器的IP地址。 • getPort():获得远程服务器的端口。 • getLocalAddress():获得客户本地的IP地址。 • getLocalPort():获得客户本地的端口。 • getInputStream():获得输入流。如果Socket还没有连接,或者已经关闭,或者已经通过shutdownInput()方法关闭输入流,那么此方法会抛出IOException。 • getOutputStream():获得输出流。如果Socket还没有连接,或者已经关闭,或者已经通过shutdownOutput()方法关闭输出流,那么此方法会抛出IOException。

  11. 当客户与服务器的通信结束,应该及时关闭Socket,以释放Socket占用的包括端口在内的各种资源。Socket的close()方法负责关闭Socket。当客户与服务器的通信结束,应该及时关闭Socket,以释放Socket占用的包括端口在内的各种资源。Socket的close()方法负责关闭Socket。 Socket socket=null; try{ socket=new Socket("www.javathinker.org",80); //执行接收和发送数据的操作 … }catch(IOException e){ e.printStackTrace(); }finally{ try{ if(socket!=null)socket.close(); }catch(IOException e){e.printStackTrace();} } 2.3 关闭Socket

  12. 2.3 关闭Socket • Socket类提供了三个状态测试方法: • isClosed() • isConnected() • isBound() • 如果要判断一个Socket对象当前是否处于连接状态,可采用以下方式: String isConnected=socket.isConnected() && !socket.isClosed();

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

  14. 2.4 半关闭Socket • 先后调用Socket的shutdownInput()和shutdownOutput()方法,仅仅关闭了输入流和输出流,并不等价于调用Socket的close()方法。在通信结束后,仍然要调用Socket的close()方法,因为只有该方法才会释放Socket占用的资源,比如占用的本地端口等。 • Socket类还提供了两个状态测试方法,用来判断输入流和输出流是否关闭: • public boolean isInputShutdown() • public boolean isOutputShutdown()

  15. 2.5 设置Socket的选项 • TCP_NODELAY:表示立即发送数据。 • SO_RESUSEADDR:表示是否允许重用Socket所绑定的本地地址。 • SO_TIMEOUT:表示接收数据时的等待超时时间。 • SO_LINGER:表示当执行Socket的close()方法时,是否立即关闭底层的Socket。 • SO_SNFBUF:表示发送数据的缓冲区的大小。 • SO_RCVBUF:表示接收数据的缓冲区的大小。 • SO_KEEPALIVE:表示对于长时间处于空闲状态的Socket,是否要自动把它关闭。 • OOBINLINE:表示是否支持发送一个字节的TCP紧急数据。

  16. 2.5.1 TCP_NODELAY选项 • 设置该选项:public void setTcpNoDelay(boolean on) throws SocketException • 读取该选项:public boolean getTcpNoDelay() throws SocketException • TCP_NODEALY的默认值为false,表示采用Negale算法。如果调用setTcpNoDelay(true)方法,就会关闭Socket的缓冲,确保数据及时发送: if(!socket.getTcpNoDelay())socket.setTcpNoDelay(true); • 如果Socket的底层实现不支持TCP_NODELAY选项,那么getTcpNoDelay()和setTcpNoDelay()方法会抛出SocketException。

  17. 2.5.2 SO_RESUSEADDR选项 • 设置该选项:public void setResuseAddress(boolean on) throws SocketException • 读取该选项:public boolean getResuseAddress() throws SocketException • 为了确保一个进程关闭了Socket后,即使它还没释放端口,同一个主机上的其他进程还可以立刻重用该端口,可以调用Socket的setResuseAddress(true)方法: if(!socket.getResuseAddress())socket.setResuseAddress(true); • 值得注意的是socket.setResuseAddress(true)方法必须在Socket还没有绑定到一个本地端口之前调用,否则执行socket.setResuseAddress(true)方法无效。

  18. 2.5.3 SO_TIMEOUT选项 • 设置该选项:public void setSoTimeout(int milliseconds) throws SocketException • 读取该选项:public int getSoTimeOut() throws SocketException • 当通过Socket的输入流读数据时,如果还没有数据,就会等待。例Socket类的SO_TIMEOUT选项用于设定接收数据的等待超时时间,单位为毫秒,它的默认值为0,表示会无限等待,永远不会超时。

  19. 2.5.4 SO_LINGER选项 • 设置该选项:public void setSoLinger(boolean on, int seconds) throws SocketException • 读取该选项:public int getSoLinger() throws SocketException • SO_LINGER选项用来控制Socket关闭时的行为。 • socket.setSoLinger(true,0):执行Socket的close()方法时,该方法也会立即返回,但底层的Socket也会立即关闭,所有未发送完的剩余数据被丢弃。 • socket.setSoLinger(true,3600):执行Socket的close()方法时,该方法不会立即返回,而进入阻塞状态,同时,底层的Socket会尝试发送剩余的数据。只有满足以下两个条件之一,close()方法才返回: • 底层的Socket已经发送完所有的剩余数据。 • 尽管底层的Socket还没有发送完所有的剩余数据,但已经阻塞了3600秒。close()方法的阻塞时间超过3600秒,也会返回,剩余未发送的数据被丢弃。

  20. 2.5.5 SO_RCVBUF选项 • 设置该选项:public void setReceiveBufferSize(int size) throws SocketException • 读取该选项:public int getReceiveBufferSize() throws SocketException • SO_RCVBUF表示Socket的用于输入数据的缓冲区的大小。 • 如果底层Socket不支持SO_RCVBUF选项,那么setReceiveBufferSize()方法会抛出SocketException。

  21. 2.5.6 SO_SNDBUF选项 • 设置该选项:public void setSendBufferSize(int size) throws SocketException • 读取该选项:public int getSendBufferSize() throws SocketException • SO_SNDBUF表示Socket的用于输出数据的缓冲区的大小。 • 如果底层Socket不支持SO_SNDBUF选项,setSendBufferSize()方法会抛出SocketException。

  22. 2.5.7 SO_KEEPALIVE选项 • 设置该选项:public void setKeepAlive(boolean on) throws SocketException • 读取该选项:public int getKeepAlive() throws SocketException • 当SO_KEEPALIVE选项为true,表示底层的TCP实现会监视该连接是否有效。 • SO_KEEPALIVE选项的默认值为false,表示TCP不会监视连接是否有效,不活动的客户端可能会永久存在下去,而不会注意到服务器已经崩溃。

  23. 2.5.9 服务类型选项 • IP规定了四种服务类型,用来定性的描述服务的质量: • 低成本:发送成本低。 • 高可靠性:保证把数据可靠的送达目的地。 • 最高吞吐量:一次可以接收或发送大批量的数据。 • 最小延迟:传输数据的速度快,把数据快速送达目的地。

  24. 2.5.9 服务类型选项 • 这四种服务类型还可以进行组合,例如,可以同时要求获得高可靠性和最小延迟。Socket类中提供了设置和读取服务类型的方法: • 设置服务类型:public void setTrafficClass(int trafficClass) throws SocketException • 读取服务类型:public int getTrafficClass() throws SocketException • Socket类用四个整数表示服务类型: • 低成本:0x02 (二进制的倒数第二位为1) • 高可靠性:0x04(二进制的倒数第三位为1) • 最高吞吐量:0x08(二进制的倒数第四位为1) • 最小延迟:0x10(二进制的倒数第五位为1)

  25. 2.5.10 设定连接时间、延迟和带宽的相对重要性 public void setPerformancePreferences(int connectionTime,int latency,int bandwidth) • 以上方法的三个参数表示网络传输数据的三项指标: • 参数connectionTime:表示用最少时间建立连接。 • 参数latency:表示最小延迟。 • 参数bandwidth:表示最高带宽。 • setPerformancePreferences()方法用来设定这三项指标之间的相对重要性。可以为这些参数赋予任意的整数,这些整数之间的相对大小就决定了相应参数的相对重要性。例如,如果参数connectionTime为2,参数latency为1,而参数bandwidth为3,就表示最高带宽最重要,其次是最少连接时间,最后是最小延迟。

  26. 2.6 发送邮件的SMTP客户程序 • SMTP 协议(Simple Mail Transfer Protocol,简单邮件传输协议)是应用层的协议,建立在TCP/IP协议基础之上。SMTP协议规定了把邮件从发送方传输到接收方的规则。 • SMTP客户程序请求发送邮件,SMTP服务器负责把邮件传输到目的地。默认情况下,SMTP服务器监听25端口。在SMTP客户与SMTP服务器的一次会话过程中,SMTP客户会发送一系列SMTP命令,SMTP服务器则做出响应,返回相应的应答码,以及对应答码的描述。

  27. 2.6 发送邮件的SMTP客户程序

  28. 2.6 发送邮件的SMTP客户程序

  29. 2.6 发送邮件的SMTP客户程序 • MailSender类就是一个SMTP客户程序。它的sendMail()方法请求SMTP服务器发送一封邮件,发送过程如下: • (1)首先创建与SMTP服务器连接的Socket对象。 • (2)当连接成功,SMTP服务器就会返回一个应答码为220的响应,表示服务就绪。 • (3)接着sendMail()方法开始发送“HELO”、“MAIL FROM”、“RCPT TO”等命令,每条命令都按行发送,即以“\r\n”结束。每发送完一条命令后,都会等接收到了SMTP服务器的响应数据,然后再发送下一条命令。

  30. 练习题1 • 问题:对于以下程序代码: Socket socket=new Socket(); //第1行 SocketAddress remoteAddr1=new InetSocketAddress("localhost",8000); //第2行 SocketAddress remoteAddr2=new InetSocketAddress("localhost",8001); //第3行 socket.connect(remoteAddr1, 60000); //第4行 socket.connect(remoteAddr2, 60000); //第5行 下面哪些说法是正确的?(多选) • 选项: • a)以上程序代码可以顺利编译和运行通过。 • b)第1行程序代码创建了一个与本地匿名端口绑定的Socket对象。 • c) 第1行程序代码创建的Socket对象没有与任何服务器建立连接,并且没有绑定任何本地端口。 • d) 第5行程序代码会运行出错,因为一个Socket对象只允许建立一次连接。 • e) 第4行程序代码使Socket对象与一个服务器建立连接,并且绑定一个本地匿名端口。 • 答案: c,d,e

  31. 练习题2 • 问题: 当客户端执行以下程序代码时: Socket socket=new Socket("angel",80); 如果远程服务器angel不存在,会出现什么情况?(单选) • 选项: • a) 构造方法抛出UnknownHostException异常。 • b) 客户端一直等待连接,直到连接超时,从而抛出SocketTimeoutException。 • c) 抛出BindException。 • d) 构造方法返回一个Socket对象,但它不与任何服务器连接。 • 答案: a

  32. 练习题3 • 问题:Socket类的哪个方法返回Socket对象绑定的本地端口?(单选) • 选项: • a) getPort() • b) getLocalPort() • c) getRemotePort() • d) 不存在这样的方法,因为Socket对象绑定的本地端口对程序是透明的。 • 答案: b

  33. 练习题4 • 问题:以下两段程序代码是否等价?(单选) //第一段程序 socket.shutdownInput(); socket.shutdownOutput(); //第二段程序 socket.close(); • 选项: • a)等价 • b)不等价 • 答案: b

  34. 练习题5 • 问题:以下哪个选项设定Socket的接收数据时的等待超时时间?(单选) • 选项: • a) SO_LINGER • b) SO_RCVBUF • c) SO_KEEPALIVE • d) SO_TIMEOUT • 答案: d

  35. 练习题6 • 问题:如何判断一个Socket对象当前是否处于连接状态?(单选) • 选项: • a) boolean isConnected=socket.isConnected() && socket.isBound(); • b) boolean isConnected=socket.isConnected() && !socket.isClosed(); • c) boolean isConnected=socket.isConnected() && !socket.isBound(); • d) boolean isConnected=socket.isConnected(); • 答案: b

  36. 练习题7 • 问题:客户程序希望底层网络的IP层提供高可靠性和最小延迟传输服务,客户程序中应该如何提出这一请求?(单选) • 选项: • a)调用Socket的setPerformancePreferences()方法。 • b)设置Socket的SO_SERVICE选项。 • c)调用Socket的setTrafficClass()方法。 • d)客户程序无法提出这种请求,必须直接配置底层网络。 • 答案: c

More Related