一、客户端Socket

定义:Socket是两台主机之间的一个连接,一单建立了连接,本地和远程主机就从这个socket得到输入流和输出流,使用这个流可以同时发送和接收数据。Socket对程序员掩盖了网络的底层细节,如错误检测、包大小、包分解、包重传、网络地址等。

1.构造和连接 Socket

javanetSocket 类是java完成客户端 TCP 操作的基础类,这个类使用原生代码与主机操作系统的本地 TCP 栈进行通信。

构造函数:


     

pubic Socket(String host,int port) throws UnknownHostException,IOException 
public Socket(InetAddress host,int port)  throws IOException
/**
下面两个构造函数可以指定本地网络接口和端口来连接,网络接口可以是物理接口也可以是虚拟接口,如果localPort传入 0,java则会随机选择 1024 到 65535 之间的一个可用端口
*/
public Socket(String host,int port,InetAddress interface,int localPort) throws IOException,UnknownHostException
public Socket(InetAddress host,int port,InetAddress interface,int localPort) throws IOException
//看源码其实可以发现传入的参数其实是两个 SocketAddress(Address + port),一个是连接的主机,一个是本地网络接口。
/**

以上的所有的构造方法中都会调用另外一个构造函数:

public Socket (SocketAddress address,SocketAddress localAddr,boolean stream):在这个构造函数中会调用 bind(localAddress);connect(address);所以建立连接时是要先创建一个 Socket,然后调用 bind 方法开始绑定,最后调用 connect 方法进行连接。
所以以下3个构造函数是没有进行连接的
*/
public Socket()
public Socket(Proxy proxy)
protected Socket(SocketImpl impl)


当建立起了连接,这时候就可以开始相互发送数据了。


       

public InputStream getInputStream() throws IOException;//获得输入流,可以从中获取服务端发来的数据
public OutputStream getOutputStream() throws IOException;//获得输出流,可以用其向服务端发送数据
半关闭 Socket

        
        
public void close();//同时关闭 Socket的输入和输出流
public void shutdownInput() throws  IOException ;//关闭输入流,shutdown方法并不关闭socket
public void shutdownOutput() throws IOException ;//关闭输出流,

获取 Socket的信息


       

public InetAddress getInetAddress();//返回远程主机的地址
public int getPort();//返回远程主机的端口
public InetAddress getLocalAddress();//返回本地主机的地址
public int getLocalPort();//返回本地主机的端口
public boolean isClosed();//是否已经关闭
public boolean isConnected();//表示的是:是否从未连接过一个远程主机,只要连接过,就返回true
Socket选项:都有对应的getter 与 setter 方法

       

TCP_NODELAY:是否关闭 Socket 的缓冲,如果关闭了,则一旦就绪就会发送,而不会等到缓冲区满

SO_LINGER:表示当socket关闭时如何处理尚未发送的数据报,可以设置延迟的秒数,一旦时间到,无论还有没有数据都关闭连接。最大延迟时间为65535秒

SO_TIMEOUT:表示从socket获取数据时,read方法会阻塞的时长。0为无限,也是默认值

SO_REVBUF:设置接收缓冲区的大小,头层皮利用缓冲区提升网络的性能

SO_SNDBUF:设置发送缓冲区的大小,但是实际上会设置为发送 和 接收缓冲区大小较小的一个

SO_KEEPALIVE:客户端会偶尔通过一个空闲连接发送一个数据包,以确保服务器未崩溃

OOBINLINE:Out Of Band ,紧急数据,会立即发送

SO_REUSEADDR:重用端口,可能会出现前一个Socket 未接收的数据

2.Socket地址

定义:SocketAddress类表示一个连接端点,这是个空的抽象类,其主要用途是为暂时的 Socket连接信息(如 ip地址 和 端口)提供一个方便的存储

方法:


     

public SocketAddress getRemoteSocketAddress();//返回的是所连接系统的地址
public SocketAddress getLocalSocketAddress();//返回的是发起连接的地址

子类 InetSocketAddress


创建:

       

       

public InetSocketAddress(InetAddress address,int port)
public InetSocketAddress(String,int port)
public InetSocketAddress(int port)
//静态构造方法
public static InetSocketAddress  createUnresolved(String host,int port)//不会在DNS 中查找主机
//获取方法
public final InetAddress getAddress()
public final int getPort()
public final String getHostName()


二、服务器 Socket

服务器就像是坐在电话胖等电话的接线员,它不管对方是谁。只管监听入站的TCP连接

1.创建

     

//监听 端口为 port的入站连接
public ServerSocket(int port) throws BindException,IOException
//queue 代表的是在队列中未处理连接的最大容量,当达到最大值是,主机会拒绝这个端口上的额外连接,知道队列腾出新的位置为止,客户端在首次连接被拒绝后还会尝试建立连接
public ServerSocket(int port,int queueLength) throws BindException,IOException
//InetAddress 绑定一个特定的本地 ip地址,服务器就值监听这个指定地上上的入站连接。因为一个主机有多个网络接口或ip地址,服务器在默认情况下会监听所有的接口和ip地址的指定端口上监听
public Serversocket(int port,int queueLength,InetAddress bindAddress) throws IOException
//创建一个ServerSocket对象,旦没有绑定到某个端口。需要调用 bind(socketAddress)来进行绑定
public ServerSocket() throws IOException

2.方法

当获取到的 ServerSocket对象过后,可以通过 accept方法获取一个 Socket对象(accept方法会监听指定端口的入站连接,一直阻塞到有客户端尝试建立连接),然后对socket进行操作,可以对其进行数据传输

关闭serverSocket:close()方法。关闭 serverSocket 会释放本地主机的一个端口,允许另一个服务器绑定到这个端口,还会中断该serversocket已经接受的目前处于打开状态的所有socket。当关闭了一个serversocket之后,就不能在重新连接

isBound():判断一个serverSocket是否曾打开过

public InetAddress getInetAddress():返回服务器(本地主机)使用的地址,如果还没绑定,则返回null

public int getLocalPort():返回端口号,如果没有绑定到某个端口,则返回 -1.如果绑定到所有接口,则

3.服务Socket选项:有对应的getter 与 setter 方法

     

     

SO_TIMEOUT:等待入站连接的时间,如果到时了,就会跑出异常

SO_REUSEADDR:是否允许一个新的Socket绑定到之前使用过的一个端口,肯呢个会存在之前Socket的数据

SO_RCVBUF:设置服务器 Socket接收客户端默认接收缓存区大小

三、测试代码

说明:因为socket中的流是阻塞式的,会一直等待数据。所以要双方定义结束协议:这里的协议为 “#标志着结束”

1.服务端 Server.java

     

     

public class Server {
public static void main(String[] args) {
   ServerSocket server = null;
   Socket socket = null;
   try {
       server = new ServerSocket(1335);
       if (server.isBound()) {
           System.out.println("server is open");
       }
       socket = server.accept();
       InputStream in = socket.getInputStream();
       StringBuffer buffer = new StringBuffer("");
       int b =  0;
       while (true) {
           if ((b = in.read()) == '#') break;
           buffer.append((char)b);
       }
       System.out.println("Server receive data from client:" + buffer.toString());
       System.out.println("server send data to client...");
       OutputStream out = socket.getOutputStream();
       out.write("hello,client#".getBytes());
   } catch (Exception e) {
       e.printStackTrace();
   } finally {
       if (socket != null) {
           try {
               socket.close(); //it close stream as well
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
   }
}
}


2.客户端 Client.java

     

     

public class Client {
public static  void  main(String[] args){
    Socket socket = null;
    try {
        socket = new Socket("172.22.113.134",1335);
        if (socket.isConnected()){
            System.out.println("client is create");
        }
        System.out.println("client send data to server");
        OutputStream out = socket.getOutputStream();
        out.write("hello,server,i'm client#".getBytes());
        InputStream in = socket.getInputStream();
        StringBuffer buffer = new StringBuffer("");
       int c = 0;
        while (true) {
            if ((c = in.read()) == '#') break;
            buffer.append((char)c);
        }
        System.out.println("client receive data form server:" + buffer.toString());
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        if (socket != null){
            try {
                socket.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}
}

3.运行结果

对于Server.java


       

       

server is open

Server receive data from client:hello,server,i'm client

server send data to client...

对于Client.java


       

       

client is create

client send data to server

client receive data fo