一、InetAddress类

1.1 作用

可以表示互联网协议地址

1.2 常用方法

  • public static InetAddress getByName(String host)
    获得一个InetAddress对象实例;
    host可以是主机名或者主机IP地址
  • public String getHostAddress()
    获取当前计算机所在网络中的IP地址
  • public String getHostName()
    获取主机名
  • getLocalHost()
    获取主机名和IP地址

1.3 案例

public class Thread {
    public static void main(String[] args) throws UnknownHostException {
        InetAddress address = InetAddress.getByName("DESKTOP-TSM707T");
        System.out.println(address.getHostName());
        System.out.println(address.getHostAddress());
        System.out.println(address.getLocalHost());
    }
}

结果:
DESKTOP-TSM707T
192.168.16.104
DESKTOP-TSM707T/192.168.16.104

注意:计算机名称可以:
此电脑—>属性—>高级系统设置—>计算机名

二、UDP协议

2.1 特点

  • 客户端与服务端不需要建立链接
  • 发送数据速度较TCP快
  • 发送数据有大小限制

2.2 UDP发送数据步骤

  • 创建客户端Socket对象
  • 将数据打包,包里的数据包括要发送的数据,数据的长度,发送端的IP,端口号,注意数据是以字节流的形式打包的。
  • 发送数据

2.3 UDP发送数据示例

public class Thread {
    public static void main(String[] args) throws IOException {
        DatagramSocket socket =  new DatagramSocket();
        byte[] bytes = "UDP发送端".getBytes();
        InetAddress address = InetAddress.getByName("DESKTOP-TSM707T");
        DatagramPacket packet = new DatagramPacket(bytes, bytes.length, address,8823);
        socket.send(packet);
    }
}

2.4 UDP接收数据步骤

  • 创建带有端口号的服务端Socket对象
  • 创建数据包对象
  • Socket对象接收发送端发过来的数据包
  • 从包中获取数据
  • 可以不关闭服务端对象

2.5 UDP接受数据示例

public class receive {
    public static void main(String[] args) throws IOException {
        DatagramSocket socket = new DatagramSocket(8823);
        byte[] bytes = new byte[1024];
        DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
        System.out.println("UDP发送端信息已经过来");
        socket.receive(packet);
        byte[] data = packet.getData();
        System.out.println(packet.getAddress().getHostName() + "发送过来的消息是:" + new String(data));
        socket.close();
    }
}

2.6 UDP输出指定路径文件内容

难点是:

  • 怎么将文件中读出的数据打包
    用的是BufferedReader类中的readLine()方法获取数据,然后发送
  • 怎么将包中的数据读出
    可以在死循环里一直新建包队象,一直等待接受包然后读数据

注意:
UDP接受数据时,新建一个包对象只能接受该包对象大小的数据,只能输出一行!!!!

发送端:

public class send_file {
    public static void main(String[] args) throws IOException {
        DatagramSocket socket = new DatagramSocket();
        FileInputStream inputStream = new FileInputStream("D:a.java");
        int i;
        DatagramPacket packet = null;
        byte[] bytes = new byte[1024];
        InetAddress byName = InetAddress.getByName("MS-20181121ZVTC");
        while ((i = inputStream.read(bytes)) != -1) {
            packet = new DatagramPacket(bytes,1024, byName, 1111);
            socket.send(packet);
            System.out.print(new String(bytes));
        }
        socket.close();
    }

接收端:

public static void main(String[] args) throws IOException {
        FileOutputStream outputStream = new FileOutputStream("D:\\b.java");
        DatagramSocket socket = new DatagramSocket(1111);
        DatagramPacket datagramPacket = null;
        byte[] bytes = new byte[1024];
        while (true){
            datagramPacket = new DatagramPacket(bytes,bytes.length );
            socket.receive(datagramPacket);
            byte[] data = datagramPacket.getData();
            outputStream.write(data);
            System.out.println(new String(data));
        }
    }

2.7 简单UDP聊天

思路:
声明发送端线程和接收端线程,开辟两个聊天室,分别有一个发送端和接收端线程,sleep的作用是确保接收端线程先开启,然后发送端线程再开启。使用InputstreamReader(Syetem.in)从键盘端读取数据。

发送端线程

public class send extends Thread{
    int port;
    send(int port) {
        this.port = port;
    }
    @Override
    public void run() {
        try {
            //创建发送端Socket对象
            DatagramSocket socket = new DatagramSocket();
            //从指定路径读取数据
            InetAddress address = InetAddress.getByName("DESKTOP-TSM707T");
            BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
            byte[] bytes = new byte[1024];
            String str = null;
            DatagramPacket packet;
            while(!(str = in.readLine()).equals("88")) {
                packet = new DatagramPacket(str.getBytes(), str.getBytes().length, address, port);
                socket.send(packet);
            }
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

接收端线程

public class receive extends  Thread{
    int port;
    public receive(int port) {
        this.port = port;
    }
    @Override
    public void run() {
        try {
            DatagramSocket socket = new DatagramSocket(port);
            System.out.println("准备接收数据");
            while (true) {
                byte[] bytes = new byte[1024];
                DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
                socket.receive(packet);
                System.out.println("发送端发来信息:" + new String(packet.getData()));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

聊天窗口1:

public class talkroom {
    public static void main(String[] args) throws InterruptedException {
        receive rec = new receive(4212);
        send se = new send(2424);
        rec.start();
        Thread.sleep(10000);
        se.start();
    }
}

聊天窗口2:

public class talkroom2 {
    public static void main(String[] args) throws InterruptedException {
        receive rec = new receive(2424);
        send se = new send(4212);
        rec.start();
        Thread.sleep(10000);
        se.start();
    }
}

三、TCP协议

3.1 特点

  • 客户端与服务端需要建立链接
  • 不用将数据打包,将数据发送到通道和通过通道获取数据
  • 传输数据速度较UDP慢

3.2 TCP发送数据步骤

  • 创建带有主机IP和端口号的Socket对象
  • 获得输出流
  • 往缓冲区写入数据

3.3 TCP发送数据示例

说明:Socket构造函数第一个参数可以是InetAddress对象,也可以是字符串

public class TCP_text {
    public static void main(String[] args) throws IOException {
        InetAddress address = InetAddress.getByName("DESKTOP-TSM707T");
        Socket socket = new Socket(address, 8984);
        OutputStream out = socket.getOutputStream();
        String str = "TCP发送";
        out.write(str.getBytes());
        socket.close();
    }
}

3.4 TCP接收数据步骤

  • 创建带端口号的ServerSocket对象
  • 创建Socket对象
  • 从通道中获取数据
  • 对数据进行操作

3.5 TCP接收数据示例

public class TCP_receive {
    public static void main(String[] args) throws IOException {
        ServerSocket ser = new ServerSocket(8984);
        System.out.println("准备接收数据");
        Socket socket = ser.accept();
        InputStream in = socket.getInputStream();
        byte[] bytes = new byte[1024];
        int len = 0;
        while((len = in.read(bytes)) != -1) {
            System.out.println(new String(bytes, 0, len));
        }
    }
}

3.5 用TCP发送文件到接收端

思路:利用BuffferedeReader和BufferWriter来封装通过socket对象获得的输入输出流,然后进行操作。

发送端:

public static void main(String[] args) throws IOException {
        InetAddress address = InetAddress.getByName("MS-20181121ZVTC");
        Socket socket = new Socket(address, 1111);
        File file = new File("D:\\a.java");
        BufferedReader re = new BufferedReader(new FileReader(file));
        OutputStream out = socket.getOutputStream();
        BufferedWriter wri = new BufferedWriter(new OutputStreamWriter(out));
        String str = null;
        while((str = re.readLine()) != null) {
            wri.write(str);
            System.out.println(str);
            wri.newLine();
            wri.flush();
        }
        re.close();
        wri.close();
        socket.close();
    }

接收端:

public static void main(String[] args) throws IOException {
            ServerSocket ser = new ServerSocket(1111);
            System.out.println("准备接收数据");
            Socket socket = ser.accept();
            InputStream in = socket.getInputStream();
            BufferedReader re = new BufferedReader(new InputStreamReader(in));
            BufferedWriter wri = new BufferedWriter(new FileWriter("D:\\b.java"));
            String str = null;
            while((str = re.readLine()) != null) {
                System.out.println(str);
                wri.write(str);
                wri.newLine();
                wri.flush();
            }
            re.close();
            wri.close();
        }

注意:

  • void shutdownInput()
    禁用此套接字的输出流。

在客户端使用该方法的作用是告诉服务端不再传输数据

3.6 TCP简单聊天

思路:和上面UDP简单聊天一样

注意:一定要注意参数的名称是否写对,否则会造成传参错误而出不来结果;
客户端线程:

public class Send_Thread extends Thread{
    int port;
    public Send_Thread(int port) {
        this.port = port;
    }
    @Override
    public void run() {
        try {
            InetAddress address = InetAddress.getByName("DESKTOP-TSM707T");
            Socket socket = new Socket(address, port);
            OutputStream out = socket.getOutputStream();
            BufferedWriter buf = new BufferedWriter(new OutputStreamWriter(out));
            BufferedReader re = new BufferedReader(new InputStreamReader(System.in));
            String str = null;
            while(true) {
                str = re.readLine();
                buf.write(str);
                buf.newLine();
                buf.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

服务端线程:

public class Receive_Thread extends Thread {
    int port;

    public Receive_Thread(int port) {
        this.port = port;
    }
    @Override
    public void run() {
        try {
            ServerSocket ser = new ServerSocket(port);
            System.out.println("准备接收数据:");
            Socket socket = ser.accept();
            InputStream in = socket.getInputStream();
            BufferedReader re = new BufferedReader(new InputStreamReader(in));
            while(true) {
                System.out.println(socket.getInetAddress().getHostAddress() + "发来的数据" + re.readLine());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

用户1:

public class room1 {
    public static void main(String[] args) throws InterruptedException {
        Receive_Thread rec = new Receive_Thread(1114);
        Send_Thread se = new Send_Thread(2224);
        rec.start();
        Thread.sleep(10000);
        se.start();
    }
}

用户2:

public class room2 {
    public static void main(String[] args) throws InterruptedException {
        Receive_Thread rec = new Receive_Thread(2224);
        Send_Thread se = new Send_Thread(1114);
        rec.start();
        Thread.sleep(10000);
        se.start();
    }
}