• Java Socket


    一、网络基础

      TCP/IP协议:是以TCP和IP为接触的不同层次上多个协议的集合。

      TCP:传输控制协议  IP:网际协议

      IP地址:为实现网络中不通过计算机之间的通信,每台计算机必须有一个唯一的标识。

      端口:用于区分不同的应用程序,端口号范围为0~65535,其中0~1023位系统所保留。

      IP地址和端口号组成了所谓的Socket,Socket是网络上个运行的程序之间双向通信链路的终结点,是TCP UDP的基础。

    二、Java中网络相关API应用

      1)InetAddress

      InetAddress类终于标识网络上的硬件资源,表示IP地址,该类没有构造方法(private),可通过getByAddress(),getByName(),getLocalHost()等静态方法得到InetAddress实例。InetAddress实例可得到当前InetAddress的ip地址 主机名等信息。

    public static void main(String[] args) throws UnknownHostException {
    //获取本机的InetAddress实例
    InetAddress address=InetAddress.getLocalHost();
    
    System.out.println("计算机名:"+address.getHostName());
    System.out.println("IP地址:"+address.getHostAddress());
    
    //获取字节数组形式的IP地址
    byte[] bytes=address.getAddress();
    System.out.println("字节数组形式的IP:"+Arrays.toString(bytes));
    
    //直接输出InetAddress对象
    System.out.println(address);
    
    //根据机器名获取InetAddress实例
    InetAddress address2=InetAddress.getByName("zhao");
    System.out.println(address2);
    
    //根据IP地址获取InetAddress实例
    InetAddress address3=InetAddress.getByAddress(bytes);
    System.out.println(address3);
    }
    
      2)URL
    
      URL:统一资源定位符,标识Internet上某一资源的地址,由两部分组成:协议名和资源名称,可以通过String创建URL实例,也可以根据父URL创建子URL实例。
    
    public static void main(String[] args) throws IOException {
    //创建一个URL实例
    URL imooc=new URL("http://www.imooc.com");
    //?后面表示参数 #后面表示锚点
    //    URL url=new URL(imooc, "/index.html?username=tom#test");
    
    System.out.println("协议 "+imooc.getProtocol());
    System.out.println("主机 "+imooc.getHost());
    //如果为指定端口号,则使用默认的端口号,此时getPort方法返回值为-1
    System.out.println("端口号 "+imooc.getPort());
    //    System.out.println("文件路径 "+url.getPath());
    //    System.out.println("文件名 "+url.getFile());
    //    System.out.println("相对路径 "+url.getRef());
    //    
    //通过URL的openStream方法获取URL对象所表示的资源的字节输入流
    InputStream inputStream=imooc.openStream();
    //将字节输入流转换成字符输入流
    InputStreamReader inputStreamReader=new InputStreamReader(inputStream,"utf-8");
    //为字符输入流添加缓冲
    BufferedReader reader=new BufferedReader(inputStreamReader);
    //读取数据
    String data=reader.readLine();
    while(data!=null){
    System.out.println(data);
    data=reader.readLine();
    }
    reader.close();
    inputStreamReader.close();
    inputStream.close();
    }

    三、Socket

      1)TCP协议是面向连接的,可靠的 有序的 以字节流方式发送数据

      基于TCP协议实现网络通信的类,客户端的Socket类,服务端的Server Socket类

    //客户端

    package com.zhao.TCPSocket;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.io.OutputStreamWriter;
    import java.io.PrintWriter;
    import java.net.InetAddress;
    import java.net.Socket;
    import java.net.UnknownHostException;
    
    public class Client {
    public static void main(String[] args) throws IOException {
    //1:创建客户端Socket,指定服务器地址和端口
    InetAddress address=InetAddress.getLocalHost();
    try {
    Socket socket=new Socket(address,8888);
    //2:获取输出流,向服务器端发送登录的信息
    OutputStream outputStream=socket.getOutputStream();
    PrintWriter printWriter=new PrintWriter(outputStream);
    printWriter.write("dfasfas");
    printWriter.flush();
    socket.shutdownOutput(); //关闭输入流
    
    //3:获取输入流,并读取服务器端响应的信息
    InputStream inputStream=socket.getInputStream();
    InputStreamReader inputStreamReader=new InputStreamReader(inputStream);
    BufferedReader bufferedReader=new BufferedReader(inputStreamReader);
    String info=null;
    while((info=bufferedReader.readLine())!=null)
    {
    System.out.println("服务器端回复:"+info);
    }
    //4:关闭资源
    bufferedReader.close();
    inputStreamReader.close();
    inputStream.close();
    printWriter.close();
    outputStream.close();
    socket.close();
    } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }
    }

    //服务端

    package com.zhao.TCPSocket;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.io.PrintWriter;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    /**
    * 基于tcp协议的Socket通信,实现用户登录 服务器端
    * 
    * @author admin
    *
    */
    public class Server {
    public static void main(String[] args) throws IOException {
    // 1:创建一个服务器端Socket,即ServerSocket,绑定指定的端口,并监听此端口
    ServerSocket serverSocket = new ServerSocket(8888);
    
    System.out.println("***服务器即将启动,等待客户端的连接***");
    //记录客户端的数量
    int count=0;
    
    Socket socket=null;
    //循环监听,等待客户端的连接
    while(true){
    // 2:调用accept()方法开始监听,等待客户端的连接
    
    //注:在调用accept()方式时,将进入阻塞状态,等待客户端的请求。当请求到来时,这个Socket实例并没有完成创建,要等到与客户端3次握手完成后,这个Socket才会返回。
    socket=serverSocket.accept();
    //创建一个新的线程
    ServerThread serverThread=new ServerThread(socket);
    //启动线程
    serverThread.start();
    
    //统计客户端的数量
    count++;
    System.out.println("客户端的数量: "+count);
    }
    
    }
    }  
    package com.zhao.TCPSocket;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.io.PrintWriter;
    import java.net.Socket;
    
    /**
    * 服务器线程处理类
    * 
    * @author admin
    *
    */
    public class ServerThread extends Thread {
    // 和本线程相关的socket
    Socket socket = null;
    
    public ServerThread(Socket socket) {
    this.socket = socket;
    }
    
    // 执行线程的操作,响应客户端的请求
    @Override
    public void run() {
    // 3:获取输入流,读取客户端所发送的信息
    InputStream inputStream = null;
    InputStreamReader inputStreamReader = null;
    BufferedReader bufferedReader = null;
    OutputStream outputStream = null;
    PrintWriter printWriter = null;
    try {
    inputStream = socket.getInputStream();// 字节输入流
    inputStreamReader = new InputStreamReader(inputStream);// 将字节流转成字符流
    bufferedReader = new BufferedReader(inputStreamReader);// 为字符流添加缓冲
    String info = null;
    while ((info = bufferedReader.readLine()) != null) {// 循环读取客户端的信息
    System.out.println("我是服务器,客户端说 : " + info);
    }
    
    socket.shutdownInput();// 关闭输入流
    
    // 4:获取输出流,响应客户端的请求
    outputStream = socket.getOutputStream();
    printWriter = new PrintWriter(outputStream);
    printWriter.write("欢迎您");
    printWriter.flush();
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } finally {
    // 5:关闭资源
    try {
    if (printWriter != null) {
    printWriter.close();
    }
    if (outputStream != null) {
    outputStream.close();
    }
    if (bufferedReader != null) {
    bufferedReader.close();
    }
    if (inputStreamReader != null) {
    inputStreamReader.close();
    }
    if (inputStream != null) {
    inputStream.close();
    }
    if (socket != null) {
    socket.close();
    }
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    
    }
    
    }
    
    }

    分析:

      对服务器Server:

      1 创建一个服务器Socket,即ServerSocket,绑定指定的端口,并监听此端口;

      2调用accept()方法监听,等待客户端的连接;

      3获取输入流,读取客户端所发送的信息;

      4获取输出流,响应客户端请求;

      5关闭资源。

      在多线程情况下,ServerSocket不关闭,每一个ServerThead类继承Thread类,在run方法中实现上述3 4 5输入流输出流的相关操作以及资源的关闭,在Server中 有while(true)循环监听,等待客户端的连接。

      对客户端Client,和对Server操作大同小异。自定义Socket指定其IP和端口号,在这里用的本机IP,通过InetAddress类获取。

    Socket就是IP和端口号,而言指定具体的计算机上具体的线程,网络通信的基础是Socket,服务器监听具体的端口,一旦有客户端访问此端口,服务器也是创建Socket,在服务器 客户机上,两个Socket进行i/o流操作,便完成了网络通信。

      2)UDP以数据报作为数据传输的载体

      进行数据传输时首先要将传输的数据定义成数据报(Datagram),在数据报中指明数据所要达到的Socket(主机地址和端口),然后将数据报发送出去。

    //客户端

    package com.zhao.UDPSocket;
    
    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetAddress;
    import java.net.SocketException;
    import java.net.UnknownHostException;
    
    public class Client {
    public static void main(String[] args) throws IOException {
    /*
    * 向服务器端发送数据
    */
    
    //1:定义服务器的地址,端口号和数据
    InetAddress address=InetAddress.getLocalHost();
    int port=8800;
    byte[] bytes="用户名:admin".getBytes();
    //2:创建数据报,包含发送的信息
    DatagramPacket datagramPacket=new DatagramPacket(bytes, bytes.length, address, port);
    //3:创建DatagramSocket对象
    DatagramSocket datagramSocket=new DatagramSocket();
    //4:向服务器端发送数据报
    datagramSocket.send(datagramPacket);
    
    /*
    * 接收服务器端响应数据
    */
    //1:创建数据报,用于接收服务器端响应的数据
    byte[] data=new byte[1024];
    DatagramPacket datagramPacket2=new DatagramPacket(data, data.length);
    //2:接收服务器端响应的数据
    datagramSocket.receive(datagramPacket2);
    //3:读物数据
    String str=new String(data,0,datagramPacket2.getLength());
    System.out.println("我是客户端,服务器说: "+str);
    //4:关闭资源
    datagramSocket.close();
    }
    }

    //服务端

    package com.zhao.UDPSocket;
    
    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetAddress;
    import java.net.SocketException;
    
    /*
    * 服务器端,实现基于UDP的用户登录
    */
    public class Server {
    public static void main(String[] args) throws IOException {
    /*
    * 接收客户端发送的数据
    */
    //1:创建服务器端DatagramSocket,指定端口
    DatagramSocket datagramSocket=new DatagramSocket(8800);
    //2:穿件数据报,用于接收客户端发送的数据
    byte[] bytes=new byte[1024];//创建字节数组,指定接收的数据报的大小
    DatagramPacket datagramPacket=new DatagramPacket(bytes, bytes.length);
    //3:接收客户端发送的数据
    datagramSocket.receive(datagramPacket);//此方法在接收到数据报之前会一直阻塞
    //4:读取数据
    String info=new String(bytes,0,datagramPacket.getLength());
    System.out.println("我是服务器,客户端说 :"+info);
    
    /*
    * 向客户端作出响应
    */
    //1:定义客户端的地址,端口号和数据
    InetAddress address=datagramPacket.getAddress();
    int port=datagramPacket.getPort();
    byte[] data="欢迎您".getBytes();
    //2:创建数据报,
    DatagramPacket datagramPacket2=new DatagramPacket(data, data.length, address, port);
    //3:响应客户端
    datagramSocket.send(datagramPacket2);
    //4:关闭资源
    datagramSocket.close();
    
    }
    }

    分析:

      1创建服务器端DatagramSocket,指定监听端口

      2创建数据报,用于接收客户端发送的数据

      3接收客户端发送的数据

      4读取数据

      在客户端,DatagranPacket的创建需要指明服务器地址和端口号。

      对于UDP来说,存信息的是数据报DatagramPacket,发信息和接收信息的是DatagramSocket。

    TCP的socket有一个ServerSocket来负责监听宽口,Socket用来连接通信链路,信息是通过Socket和Socket建立I/O流来传递的。

    UDP的socket有点像单向连接,没有通道,服务端和客户端是平等的,信息存在DatagramPacket数据报中,在其中指定IP和Port,直接send便可以了,目标DatagramSocket接收receive之后,把信息存入DatagramPacket,或者说 就是接收到一个DatagramSocket。

  • 相关阅读:
    在IE地址栏输入JS的有趣效果
    min-height for IE6
    针对主流浏览器的CSS-HACK写法及IE常用条件注释
    spring mvc从前台往后台传递参数的三种方式
    SQL语句优化
    SpringCloud分布式开发理解
    Spring的三大核心思想
    单例模式中的懒汉模式及饿汉模式
    SpringMVC工作原理
    堆和栈的区别及堆区和栈区的区别
  • 原文地址:https://www.cnblogs.com/zhao307/p/5364103.html
Copyright © 2020-2023  润新知