• 第二章 Socket用法详解


    构造Socket

      Socket构造方法如下:

     1 Socket() 
     2 //Creates an unconnected socket, with the system-default type of SocketImpl.
     3  
     4 Socket(InetAddress address, int port) 
     5 //Creates a stream socket and connects it to the specified port number at the  
     6 //specified IP address.
     7  
     8 Socket(InetAddress host, int port, boolean stream) 
     9 //Deprecated.  
    10 //Use DatagramSocket instead for UDP transport.
    11  
    12 Socket(InetAddress address, int port, InetAddress localAddr, int localPort) 
    13 //Creates a socket and connects it to the specified remote address on the 
    14 //specified remote port.
    15  
    16 Socket(Proxy proxy) 
    17 //Creates an unconnected socket, specifying the type of proxy, if any, that 
    18 //should be used regardless of any other settings.
    19  
    20 Socket(SocketImpl impl) 
    21 //Creates an unconnected Socket with a user-specified SocketImpl.
    22  
    23 Socket(String host, int port) 
    24 //Creates a stream socket and connects it to the specified port number on the  
    25 named host.
    26  
    27 Socket(String host, int port, boolean stream) 
    28 //Deprecated.  
    29 //Use DatagramSocket instead for UDP transport.
    30  
    31 Socket(String host, int port, InetAddress localAddr, int localPort) 
    32 //Creates a socket and connects it to the specified remote host on the specified 
    33 //remote port. 

      除了第一个无参,其余构造方法都试图建立与服务器的连接,如果成功则返回Socket对象,否在抛出异常。

      根据以上构造方法来创建一个类,用于扫描主机上1-1024之间的端口是否被服务器程序监听(如果被监听,就可以返回Socket对象)。代码如下:

    import java.io.IOException;
    import java.net.Socket;
    
    public class PortScanner {
    
        public static void main(String[] args) {
            String host="localhost";
            new PortScanner().scan(host);
    
        }
        public void scan(String host){
            Socket socket=null;
            for(int port=1;port<=1024;port++){
                try{
                    socket=new Socket(host,port);
                    System.out.println("There is a server on port "+port);
                }catch(IOException e){
                    System.out.println("Can't connect to port "+port);
                }finally{
                    if(socket!=null){
                        try {
                            socket.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    
    }

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

        当需要设定连接超时时间时,则需要调用Socket的无参构造函数。   

    Socket socket = new Socket();
    //SocketAddress 提供不可变对象,供套接字用于绑定、连接或用作返回值。
    SocketAddress remoteAddr = new InetSocketAddress("localhost",8000);
    //超时未连接时,会抛出超时异常。
    socket.connect(remoteAddr,60000);//毫秒为单位,0表示用于不超时

      2.1.2 设定服务器地址

        除了第一个无参构造函数,其余都需要提供服务器IP或主机名,以及端口号。    

    1 Socket(InetAddress address,int port)  //第一个参数表示主机IP地址
    2 Socket(String host,int port)  //第一个表示主机名
    View Code

        InetAddress类表示服务器的IP地址,详情查看这里

      2.1.3 设定客户端地址

      一个socket对象应该包含远程服务器的IP和端口信息,也包含本地客户机的IP地址和端口信息。默认情况下,客户机的IP来自于本地主机,端口有操作系统自动分配。也可以显式的设置客户端的IP和端口。  

     Socket(InetAddress address,int port,InetAddress localAddress,int localPort)
     Socket(String host,int port,int port,InetAddress localAddress,int localPort)

      2.1.4 客户机连接服务器可能出现的异常

    UnKnownHostException 无法识别主机的名字或IP地址
    ConnectException 服务器没有对应的端口或服务器拒绝连接
    SocketTimeoutException 等待连接超时
    BindException 无法与指定的本地IP或端口绑定
       
       
       
       

    获取Socket信息

      以下方法可获得Socket相关信息:

     1 InetAddress getInetAddress() 
     2 //Returns the address to which the socket is connected.
     3  
     4 InputStream getInputStream() 
     5 //Returns an input stream for this socket.
     6 
     7 OutputStream getOutputStream() 
     8 //Returns an output stream for this socket. 
     9  
    10 int getPort() 
    11 //Returns the remote port number to which this socket is connected. 
    12  
    13 InetAddress getLocalAddress() 
    14 //Gets the local address to which the socket is bound.
    15  
    16 int getLocalPort() 
    17 //Returns the local port number to which this socket is bound. 

    关闭Socket

      部分代码如下:

    if(socket!=null){
        try {
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
            }
        }
    }

      Socket提供了3个状态测试方法:

    boolean isBound() 
    //Returns the binding state of the socket.
     
    boolean isClosed() 
    //Returns the closed state of the socket.
     
    boolean isConnected()  
    //Returns the connection state of the socket.

    半关闭Socket

      进程A与进程B通信时,A传输数据到B,如何告知B所有数据已经传输完毕呢?以下几个方法:

      (1) 发送一行特殊的字符串,如前一章使用的“bye”,告知输出完毕。

      (2) A先告诉B字符串的长度,在向B传输数据。

      (3) A发送完成后,关闭Socket。此时B读完数据后,在此执行read()时,该方法返回-1,如果执行BufferedReader的readLine()方法,则返回null。以此表示到达输入流末尾。

      (4) 关闭Socket的输入输出流

    shutdownInput():关闭输入流

    shutdownOutput():关闭输出流

    对应两个状态测试方法:

      isInputShutdown()

      isOutputShutdown()

    设置Socket的选项 

      TCP_NODEALY:表示立即 发送数据。

      默认情况下,发送数据会先放在缓冲区,缓存区满了在发出去,并等待接收方的响应,然后再发下一批数据。这种模式适合发送大量数据,并且会得到及时响应的场合。发送小数据时这种模式速度很慢,调用setTcpNoDelay(true)可以关闭缓存区。设置之前先调用socket.getTcpNoDelay()方法查看底层是否支持TCP_NODEALY选项。

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

      当socket执行close()方法后,底层Socket不会立刻释放本地端口,而是等待一会,确保接收到网络发送的延迟数据,然后再释放。这样可以确保这些数据不会被其他绑定到该端口的新进程接收到。为了确保Socket关闭后即使端口未被释放,其他进程也可以绑定该端口,可以调用setResuseAddress(true).

      SO_TIMEOUT:表示接受数据时的等待时间。

      设定接收数据的等待超时时间,超过后抛出异常。

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

      用来控制Socket关闭后的行为。默认下,关闭Socket后,底层不会立即关闭,延迟一段时间,等待剩余数据发送完成,才会关闭底层。

      执行以下方法:socket.setSoLinger(true,0);则Socket执行close()方法后,会立即关闭底层,未发送完的数据被丢弃。

      执行以下方法:socket.setSoLinger(true,3600);表示执行close()方法后进入阻塞状态。当所有数据发送完成后或者阻塞时间超过3600秒(以秒为单位)才会返回。

      SO_SNDBUF:发送数据的缓冲区大小。

        设置输出数据的缓存区大小。

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

        设置输入数据的缓存区大小。

      SO_KEEPALIVE:表示对于空闲的Socket,是否把它关闭。

      选项为true时,底层TCP会对该连接进行监视。当连接空闲状态超过2小时,本地TCP会发送一个数据包给远程Socket。如果未收到响应,则持续尝试11分钟。在12分钟内没有收到响应的话,TCP会自动关闭本地Socket。

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

      服务类型选项

      设置服务类型:setTrafficClass(int trafficClass)

      低成本:0x02

      高可靠性:0x04

      最高吞吐量:0x08

      最小延迟:0x10

      以下代码设置请求高可靠性和最小延迟:

      socket.setTrafficClass(0x04|0x10);

    送邮件的SMTP客户程序

      略

    联系方式:wuchaodzxx@126.com
  • 相关阅读:
    发邮件
    Django 管理多个APP且在后台显示 自定义APP的名称
    MySQL的sql_mode模式说明及设置
    Go语言 基础 函数
    Go语言 基础 map
    Selenium 3 -how to locate the chromedriver and geckodriver place?
    Selenium3笔记-WebDriver源码初探
    MySQL 学习用employee数据库表参考使用
    hibernate spring annotation setup
    Maven full settings.xml
  • 原文地址:https://www.cnblogs.com/wuchaodzxx/p/java_network_program_02.html
Copyright © 2020-2023  润新知