JAVA网络编程基础

JAVA网络编程

网络编程概述

网络编程

  • 在网络通信协议下,实现网络互连的不同计算机上运行的程序间可以进行数据交换

网络编程三要素

第一要素:ip地址

  • 想要让网络中的计算机能够互相通信,必须为每台计算机指定一个标识号,通过这个标识号来接收指定要接收数据的计算机和识别发送的计算机,而ip地址就是这个标识号,也就是设备的标识

第二要素:端口

  • 网络的通信,本质上是两个应用程序的通信,每台计算机都有很多的应用程序,那么在网络通信时,如何区分这些应用程序呢,如果ip地址可以 唯一标识网络中的设备,那么端口号就可以唯一标识设备中的应用程序了,也就是应用程序的标识

第三要素:协议

  • 通过计算机网络可以使多台计算机实现链接,位于一个网路中的计算机在进行通信的时候需要遵守一定的规则,相当于汽车遵守交通规则,在计算机网络中,连接和通信的规则 被称为网络通信协议,它对数据传输格式,传输速率,传输步骤等做了统一规定,通信双方必须同时遵守才能完成数据交换,常见的协议有UDP协议TCP协议

ip地址

  • 上面图片错误点,IPv6是16位一组

常用命令

  • ipconfig:查看本机IP地址
  • ping IP地址:检查网络是否连通

特殊ip地址

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

IntelAddress的使用

public static void main(String[] args) throws UnknownHostException {
    InetAddress address = InetAddress.getByName("DESKTOP-HES35FH");

    String name = address.getHostName();
    String ip = address.getHostAddress();

    System.out.println("主机名是:"+name);
    System.out.println("ip是:"+ip);
}

端口

协议

UDP协议

UDP通信原理
  • UDP协议是一种不可靠的网络协议,它在通信的两端各建立一个Socket对象,但是这两个Socket只是发送,接受数据的对象因此对于基于UDP协议的通信双方而言,没有所谓的客户端和服务器的概念
  • Java提供了DatagramSocket类作为基于UDP协议的Socket
UDP发送数据

发送数据的步骤

  • 创建发送端的Socket对象(DatagramSocket)
  • 创建数据,并把数据打包:DatagramPacket(byte[] buf, int length, InetAddress address, int port)
  • 调用DatagramSocket对象的方法发送数据:void send(DatagramPacket p)
  • 关闭发送端:ds.close();
public static void main(String[] args) throws IOException {
        //创建发送端的Socket对象(DatagramSocket)
        DatagramSocket ds = new DatagramSocket();

        //创建数据,并把数据打包
        //DatagramPacket(byte[] buf, int length, InetAddress address, int port)
        //指定主机上的指定端口发送数据包的长度 length数据报包结构。
        byte[] by = "你好,收到请回应".getBytes();
//        int length = by.length;
//        InetAddress address = InetAddress.getByName("127.0.0.1");
//        int port = 10086;
//        DatagramPacket dp = new DatagramPacket(by, length, address, port);
        //简化后
        DatagramPacket dp = new DatagramPacket(by,by.length,InetAddress.getByName("192.168.3.4"),10086);

        //调用DatagramSocket对象的方法发送数据
        //void send(DatagramPacket p)从这个套接字发送数据报包。
        ds.send(dp);

        //关闭发送端
        ds.close();
    }
UDP接收数据

接收数据的步骤

  • 创建接收端Socket对象(DatagramSocket)
  • 创建一个数据包,用于接收数据
  • 调用DatagramSocket对象的方法接收数据
  • 解析数据包,并把数据在控制台显示
  • 关闭接收端
  public static void main(String[] args) throws IOException {
        //创建接收端Socket对象(DatagramSocket)
        //DatagramSocket(int port)构建一个数据报套接字绑定到本地主机的指定端口。
        DatagramSocket ds = new DatagramSocket(10086);

        //创建一个数据包,用于接收数据
        //DatagramPacket(byte[] buf, int length)接收数据包长度 length DatagramPacket构建。
        byte[] by = new byte[1024];
        DatagramPacket dp = new DatagramPacket(by, by.length);

        //解析数据包,并把数据在控制台显示
        //void receive(DatagramPacket p)
        ds.receive(dp);

        //解析数据包,并把数据在控制台显示
        //byte[] getData()返回数据缓冲区。
//        byte[] data = dp.getData();
//        int len = dp.getLength();//获取实际接收的数据的长度
//        String dataString = new String(data,0,len);//只显示接收数据的长度,不然会有多余没用到的空字符
//        System.out.println("数据是:"+dataString);
        //简化后
        System.out.println("数据是:"+new String(dp.getData(),0,dp.getLength()));


        //关闭接收端
        ds.close();
    }
UDP通讯程序练习

发送端

public static void main(String[] args) throws IOException {
    DatagramSocket ds = new DatagramSocket();

    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    String line;
    while ((line = br.readLine()) != null) {
        if ("886".equals(line)) {
            break;
        }
        byte[] by = line.getBytes();
        DatagramPacket dp = new DatagramPacket(by, by.length, InetAddress.getByName("192.168.3.4"), 10086);

        ds.send(dp);
    }
    ds.close();
}

接收端

public static void main(String[] args) throws IOException {
    DatagramSocket ds = new DatagramSocket(10086);

    while (true) {
        byte[] by = new byte[1024];
        DatagramPacket dp = new DatagramPacket(by, by.length);

        ds.receive(dp);
        System.out.println(new String(dp.getData(), 0, dp.getLength()));
    }
}

TCP协议

  • 完成三次握手后,连接建立后,客户端和服务器就可以开始进行数据传输了,由于这种面向连接的特性,TCP协议可以保证传输数据的暗拳,所以应用十分广泛,例如上传文件,下载文件,浏览网页等
TCP发送数据

发送数据的步骤

  • 创建客户端的Socket对象(Socket):Socket(String host, int port) 创建一个流套接字,并将其与指定的主机上的指定端口号连接起来。
  • 获取输出流,写数据:OutputStream getOutputStream() 返回此套接字的输出流。
  • 释放资源:void close()
    public static void main(String[] args) throws IOException {
//        Socket st = new Socket(InetAddress.getByName("192.168.3.4"),10000);
        Socket st = new Socket("192.168.3.4",10000);

        OutputStream os = st.getOutputStream();
        os.write("你好,收到请回复".getBytes());

        st.close();
        //直接运行是会报错的,需要写好服务端的接收代码三次握手
    }
TCP接收数据

接收数据的步骤

  • 创建服务器端的Socket对象(ServerSocket):ServerSocket(int port) 创建一个服务器套接字,绑定到指定的端口。
  • 监听连接到此的Socket返回对象,然后获取输入流,读数据,并把数据显示在控制台
    • Socket accept() 监听要对这个套接字作出的连接并接受它。
    • Socket getInputstream()获取输入流
  • 释放资源:void close()
public static void main(String[] args) throws IOException {
    ServerSocket ss = new ServerSocket(10000);

    Socket s = ss.accept();

    InputStream is = s.getInputStream();
    byte[] by = new byte[1024];
    int len;
    while ((len = is.read(by)) != -1) {
        String s1 = new String(by, 0, len);
        System.out.println("数据是:" + s1);
    }
    ss.close();
}
TCP通讯练习1(服务器给出反馈)
  • 客户端:发送数据,接收服务器反馈
public static void main(String[] args) throws IOException {
    //创建客户端的socket对象
    Socket st = new Socket("192.168.3.4", 10000);
    //获取输出流,写数据
    OutputStream os = st.getOutputStream();
    os.write("你好,收到请回复".getBytes());
    //接收服务器反馈
    InputStream is = st.getInputStream();
    byte[] by = new byte[1024];
    int len = is.read(by);
    String s = new String(by, 0, len);
    System.out.println("服务器信息:" + s);
    //释放资源
    st.close();
}
  • 服务端:接收数据,给出反馈
public static void main(String[] args) throws IOException {
    //创建服务器端的socket对象
    ServerSocket ss = new ServerSocket(10000);
    //监听客户端连接,返回一个socket对象
    Socket s = ss.accept();
    //获取输入流,读数据,并把数据显示在控制台
    InputStream is = s.getInputStream();
    byte[] by = new byte[1024];
    int len = is.read(by);
    String data = new String(by, 0, len);
    System.out.println("客户端信息:" + data);
    //用while循环读取的在循环里最后加上 socket对象.shutdownInput();即可给出反馈
    //给出反馈
    OutputStream os = s.getOutputStream();
    os.write("数据已收到".getBytes());

    //释放资源
    ss.close();
}
TCP通讯程序练习2(客户端数据来自于键盘输入)
  • 客户端:数据来自于键盘录入,知道输入的数据是886,发送数据结束
public static void main(String[] args) throws IOException {
    //创建客户端的socket对象
    Socket st = new Socket("192.168.3.4", 10000);
    //数据来源于键盘录入,直到输入的数据是886,发送数据结束
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    //封装输出流对象
    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(st.getOutputStream()));
    String line;
    while ((line = br.readLine())!=null){
        if ("886".equals(line)){
            break;
        }
        //使用包装的字符缓冲流输出数据
        bw.write(line);
        bw.newLine();
        bw.flush();
    }
    //释放资源
    st.close();
}
  • 服务端:接受收到的数据再控制台输出
public static void main(String[] args) throws IOException {
    //创建服务器端的socket对象
    ServerSocket ss = new ServerSocket(10000);
    //监听客户端连接,返回一个对应的socket对象
    Socket s = ss.accept();
    //封装输入流对象为字符缓冲流,读数据,并把数据显示在控制台
    BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
    String line;
    while ((line = br.readLine())!= null){
        System.out.println(line);
    }
    //用while循环读取的在循环里最后加上 socket对象.shutdownInput();即可给出反馈
    //释放资源
    ss.close();
}
TCP通讯程序练习3(服务器数据写入文本文件)
  • 客户端:数据来自于键盘录入,知道输入的数据是886,发送数据结束

    • 同练习2一样
  • 服务端:接受收到的数据,写入文本文件

public static void main(String[] args) throws IOException {
    //创建服务器端的socket对象
    ServerSocket ss = new ServerSocket(10000);
    //监听客户端连接,返回一个对应的socket对象
    Socket s = ss.accept();
    //封装字符输入输出流,读数据,写入文本文件
    BufferedWriter bw = new BufferedWriter(new FileWriter("ooo.txt"));
    BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
    String line;
    while ((line = br.readLine())!= null){
        bw.write(line);
        bw.newLine();
        bw.flush();
    }
    //用while循环读取的在循环里最后加上 socket对象.shutdownInput();即可给出反馈
    //释放资源
    ss.close();
}
TCP通讯程序练习4(客户端数据来自于文本文件)
  • 客户端解码自GBK的中文文本文件
public static void main(String[] args) throws IOException {
    //创建客户端的socket对象
    Socket st = new Socket("192.168.3.4", 10000);
    //数据来源于GBK编码的中文文本文件
    BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("安装必读.txt"),"GBK"));
    //封装输出流对象
    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(st.getOutputStream()));
    String line;
    while ((line = br.readLine())!=null){
        //使用包装的字符缓冲流输出数据
        bw.write(line);
        bw.newLine();
        bw.flush();
    }
    //释放资源
    st.close();
}
  • 服务端以GBK编码写入文本文件
public static void main(String[] args) throws IOException {
    //创建服务器端的socket对象
    ServerSocket ss = new ServerSocket(10000);
    //监听客户端连接,返回一个对应的socket对象
    Socket s = ss.accept();
    //获取输入流,读数据,以GBK编码写入文本文件
    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("ooo.txt"),"GBK"));
    BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
    String line;
    while ((line = br.readLine())!= null){
        bw.write(line);
        bw.newLine();
        bw.flush();
    }
    //用while循环读取的在循环里最后加上 socket对象.shutdownInput();即可给出反馈
    //释放资源
    ss.close();
}
TCP通讯程序练习5(上传文件服务器给出反馈)
  • 客户端:数据来自于GBK编码的文本文件,接收服务器反馈
    public static void main(String[] args) throws IOException {
        //创建客户端的socket对象
        Socket st = new Socket("192.168.3.4", 10000);
        //数据来源于GBK编码的中文文本文件
        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("安装必读.txt"), "GBK"));
        //封装输出流对象
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(st.getOutputStream()));
        String line;
        while ((line = br.readLine()) != null) {
            //使用包装的字符缓冲流输出数据
            bw.write(line);
            bw.newLine();
            bw.flush();
        }
        //自定义结束标记让服务端能停止接收数据
//        bw.write("886");
//        bw.newLine();
//        bw.flush();
        st.shutdownOutput();

        //接收反馈
        BufferedReader j = new BufferedReader(new InputStreamReader(st.getInputStream()));
        String data = j.readLine();
        System.out.println("服务器信息:" + data);
        //释放资源
        st.close();
    }
  • 服务器:接收收到的数据写入文件,给出反馈
   public static void main(String[] args) throws IOException {
        //创建服务器端的socket对象
        ServerSocket ss = new ServerSocket(10000);
        //监听客户端连接,返回一个对应的socket对象
        Socket s = ss.accept();
        //获取输入流,读数据,以GBK编码写入文本文件
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("ooo.txt"), "GBK"));
        BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
        String line;
        while ((line = br.readLine()) != null) {
            //判断接收到自定义结束标记,由于只要文本里有886就会停止,此方法不适用,所以使用shutdowm方法
//            if ("886".equals(line)) {
//                break;
//            }
            bw.write(line);
            bw.newLine();
            bw.flush();
        }
        //由于服务端处于while循环会一直等待接收数据,无法继续发送给服务器反馈,需要客户端进行自定义结束标记
        //发送服务器反馈
        BufferedWriter f = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        f.write("数据已传输完毕");
        f.newLine();
        f.flush();
        //释放资源
        ss.close();
    }
  • 会出现问题为客户端接收不到服务器反馈,服务端一直等待
  • 原因是读数据的方法是阻塞式的
  • 解决方法:自定义结束标记,使用shutdownOutput()方法
TCP通讯程序练习6(多线程实现文件上传)
  • 客户端:数据来自于文本文件,接受服务器反馈
public static void main(String[] args) throws IOException {
    //创建客户端的socket对象
    Socket st = new Socket("192.168.3.4", 10000);
    //数据来源于GBK编码的中文文本文件
    BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("安装必读.txt"), "GBK"));
    //封装输出流对象
    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(st.getOutputStream()));
    String line;
    while ((line = br.readLine()) != null) {
        //使用包装的字符缓冲流输出数据
        bw.write(line);
        bw.newLine();
        bw.flush();
    }
    st.shutdownOutput();

    //接收反馈
    BufferedReader j = new BufferedReader(new InputStreamReader(st.getInputStream()));
    String data = j.readLine();
    System.out.println("服务器信息:" + data);
    //释放资源
    st.close();
}
  • 服务端:接收到的数据写入文本文件,给出反馈,代码用线程进行封装,为每一个客户端开启一个线程
    public static void main(String[] args) throws IOException {
        //创建服务器端的socket对象
        ServerSocket ss = new ServerSocket(10000);
        //监听客户端连接,返回一个对应的socket对象
        while (true) {
            Socket s = ss.accept();
            //为每个客户端开启一个线程
            new Thread(new ServerThread(s)).start();
        }
        //一般服务器不关闭所以不需要用到close
//        ss.close();
    }
  • ServerThread类
    public static void main(String[] args) throws IOException {
        //创建服务器端的socket对象
        ServerSocket ss = new ServerSocket(10000);
        //监听客户端连接,返回一个对应的socket对象
        while (true) {
            Socket s = ss.accept();
            //为每个客户端开启一个线程
            new Thread(new ServerThread(s)).start();
        }
        //一般服务器不关闭所以不需要用到close
//        ss.close();
    }
posted @ 2022-09-15 19:34  Joe_ximu  阅读(49)  评论(0)    收藏  举报