Java网络编程

一、网络编程三要素

1、IP地址

  • 设备在网络中的地址,是唯一标识

2、端口

  • 应用程序在设备中的唯一标识

3、协议

  • 数据在网络中传输的规则,常见的协议有UDP协议和TCP协议

二、IP地址

1、含义

  • IP地址,全称为Internet Protocol Address,网络协议地址。是分配给上网设备的数字标签。
  • 常见的IP分类有ipv4和ipv6

2、实践--终端ping网址

  • 在终端输入 ping www.itheima.com的过程解析

3、分类

ipv4:32bit来表示

  • 问题:ipv4能分配的地址数量最多为256的四次方个,约为42亿,数量逐渐不够使用

ipv6:128bit来表示

4、相关命令(Mac)

  • 查看本机的IP地址

    • ifconfig
    • ifconfig | grep net 用管道符号+grep命令来过滤一下,更方便查看
  • 检查网络是否连通(还可以确定域名的IP地址)

    • ping IP地址

5、特殊IP

  • 127.0.0.1:回送地址,本地回环地址。可以代表本机的IP地址,一般用来测试使用

6、Java中的InetAddress类

6.1、含义

  • 表示IP地址

6.2、常用方法

  • static InetAddress getByName("String host"):通过主机名获取InetAdress对象,host可以是主机名,也可以是IP地址
  • String getHostName():获取主机名
  • String getHostAddress():获取IP地址

6.3、关于Mac查看和修改主机名和计算机名

https://www.jianshu.com/p/dbf2fa105f26

三、端口

1、含义

  • 应用程序在设备中的唯一表示

2、端口号

  • 用两个字节表示的整数来标识。范围0~25535
  • 0~1023之间的端口号常用于一些知名的网络服务或应用,我们自己使用1024及以上

3、注意

  • 一个端口号只能被一个应用程序来使用

四、协议

1、UDP协议

  • UDP(User Datagram Protocol)用户数据报协议

  • 面向无连接:只管发送,不必先建立连接,都可以发送成功。如果两者已经连接,就能成功接收;

  • 特点

    • 速度快
    • 大小限制:最大为64K
    • 数据不安全,易丢失
  • 常见场景:音视频、普通数据

2、TCP协议

  • TCP(Transmission Control Protocol)传输控制协议
  • 面向连接:先保证连接已经建立,才传输数据
  • 特点
    • 速度慢
    • 没有大小限制
    • 数据安全
  • 常用场景:聊天

五、UDP通信程序

1、发送端

  • 过程图示

  • 代码实现
public class ClientDemo {
    public static void main(String[] args) throws IOException {
        //1.找码头
        DatagramSocket ds = new DatagramSocket();

        //2.打包数据
        String message = "你好哇,李婷婷!";
        byte[] bytes = message.getBytes();
        InetAddress address = InetAddress.getByName("127.0.0.1");
        int port = 10000;
        DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, port);

        //3.发送数据
        ds.send(dp);

        //4.释放资源
        ds.close();
    }
}

2、接收端

  • 过程图示

  • 代码实现
public class ServerDemo {
    public static void main(String[] args) throws IOException {
        //1.找码头    ---表示从10000端口号接收数据,否则就是从随机端口接收数据
        DatagramSocket ds = new DatagramSocket(10000);

        //2.创建包
        byte[] bytes = new byte[1024];
        DatagramPacket dp = new DatagramPacket(bytes, bytes.length);

        //3.接受包
        ds.receive(dp);

        //4.打开包得到数据
        byte[] data = dp.getData();
        System.out.println(new String(data));

        //5.释放资源
        ds.close();
    }
}

3、实现通信

  • 先运行接收端,保证建立了连接。
  • 再运行发送端,发送数据
  • 检查服务端,确实收到了数据

4、注意

  1. 如果接收端没有收到数据,就会死等(阻塞)。可以在接收前后加上输出语句来验证
  2. 新数组接收到的数据中,如果不能填满,会包含空格,可以使用getLength()来获取数据的长度

其实,数组data是多余的,直接用bytes也可以得到数据

5、UDP三种通信方式

5.1、单播:

  • 一对一发送
  • 之前写的代码就是单播通信

5.2、组播

  • 一对多发送,但是多个接收端要是一组的

  • 代码实现

组播地址:244.0.0.0 ~ 244.255.255.255 。其中244.0.0.0 ~ 244.0.0.255是预留的组播地址


5.3、广播

  • 一对所有发送

  • 代码实现

六、TCP通信程序

1、TCP通信原理

  • TCP通信协议是一种可靠的网络协议,所以在通信两端各建立一个Socket对象

  • 通信之前,要保证建立连接

  • 通过socket产生IO流来进行通信

2、TCP发送数据的步骤

①、创建客户端Socket对象,与指定的服务端连接

②、获取输出流,写出数据

③、释放资源

  • 代码实现如下
public class ClientDemo {
    public static void main(String[] args) throws IOException {

        Socket socket = new Socket("127.0.0.1", 10000);

        OutputStream os = socket.getOutputStream();
        os.write("xian".getBytes());

        os.close();
        socket.close();
    }
}

//注意:此时如果我们运行,是会报异常ConnectException,因为无法和接收端建立连接

3、TCP接受数据

①、创建服务端Socket对象(ServerSocket)

②、监听客户端,返回一个Socket对象

③、获取输入流,读数据,把数据显示在控制台

④、释放资源

  • 代码实现
public class ServerDemo {
    public static void main(String[] args) throws IOException {

        ServerSocket ss = new ServerSocket(10000);

        System.out.println(111);
        Socket accept = ss.accept();//等待客户端来进行连接,一直等待
        System.out.println(222);

        //复习
        InputStream is = accept.getInputStream();
        int b;
        while ((b = is.read() )!= -1){
            System.out.println((char) b);
        }
        
        is.close();
        ss.close();
    }
}

4、原理分析

  • 需要先运行服务端,服务端会执行到 ss.accept()处等待客户端连接
  • 客户端连接,发送数据
  • 服务端接受收据

注意

  • accept()方法是阻塞的,作用:等待客户端连接
  • 客户端连接服务器通过:三次握手

下面的类比就尼玛离谱,公平打在有才上

  • 针对客户端,往外写,用输出流;针对服务端,往里读,用输入流
  • read()方法是阻塞的
  • os.close()会附带一个结束标记,来让read结束
  • socket.close()关闭连接通过:四次挥手

5、练习一

客户端:发送数据,接受服务端反馈

服务端:接收数据,给出反馈

客户端代码

public class ClientDemo {
    public static void main(String[] args) throws IOException {
        //创建socket对象
        Socket socket = new Socket("127.0.0.1", 10086);

        //获取输出流,写出数据
        OutputStream os = socket.getOutputStream();
        os.write("hello".getBytes());
        socket.shutdownOutput();//关闭输出流,写一个结束标记给接收端,不会关闭socket

        //获取输入流,读入数据
        /*
        InputStream is = socket.getInputStream();
        int b;
        while ((b = is.read()) != -1){
            System.out.println((char) b);
        }
        */
        //因为接受的是中文,用字节流会乱码,socket又没有字符流,--->用缓冲流
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String line;
        while ((line = br.readLine()) != null){
            System.out.println(line);
        }

        //关闭资源
        br.close();
        os.close();
        socket.close();

    }
}

服务端代码

public class ServerDemo {
    public static void main(String[] args) throws IOException {
        //创建socket对象
        ServerSocket ss = new ServerSocket(10086);

        //监听客户端,返回一个Socket对象
        Socket accept = ss.accept();

        //获取输入流,读入数据
        InputStream is = accept.getInputStream();
        int b;
        while ((b = is.read()) != -1){
            System.out.println((char) b);
        }

        //获取输出流,写出数据
        /*OutputStream os = accept.getOutputStream();
        os.write("你谁啊".getBytes());*/
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
        bw.write("你谁啊?");

        //关闭资源
        bw.close();
        is.close();
        ss.close();
    }
}

6、练习二

客户端:将文件上传到服务器,接受服务器的反馈

服务器:接受客户端上传的文件,上传完毕后给出反馈

客户端代码

public class ClientDemo {
    public static void main(String[] args) throws IOException {
        //创建socket
        Socket socket = new Socket("127.0.0.1", 10086);

        //本地流,读取本地文件
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("heima/ClientDir/java图标.jpg"));

        //网络中的流,写到服务器
        OutputStream os = socket.getOutputStream();
        BufferedOutputStream bos = new BufferedOutputStream(os);

        int b;
        while ((b = bis.read()) != -1){
            bos.write(b);
        }

        socket.shutdownOutput();//给服务器一个结束标记,表名传输完毕

        //获取服务端数据
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String line;
        while ((line = br.readLine()) != null){
            System.out.println(line);
        }

        //关闭资源
        socket.close();
        bis.close();
    }
}

服务端代码

public class ServerDemo {
    public static void main(String[] args) throws IOException {

        //创建socket
        ServerSocket ss = new ServerSocket(10086);
        //等待连接
        Socket accept = ss.accept();

        //网络中的流,读取客户端数据
        BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());
        //本地的流,持久化
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("heima/ServerDir/copy.jpg"));
        //读取,持久化到本地
        int b;
        while ((b = bis.read()) != -1){
            bos.write(b);
        }

        //发送反馈信息
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
        bw.write("上传成功");
        bw.newLine();
        bw.flush();

        //关闭资源
        ss.close();
        accept.close();//网络中的流,随着socket的关闭也会关闭
        bos.close();
    }
}
posted @ 2021-01-31 18:34  不知老之将至  阅读(215)  评论(0编辑  收藏  举报