当前位置: 首页 > news >正文

菜鸟之路Day21一一网络编程

菜鸟之路Day21一一网络编程(一)

作者:blue

时间:2025.3.2

文章目录

  • 菜鸟之路Day21一一网络编程(一)
    • 0.概述
    • 1.初识网络编程
    • 2.网络编程三要素
    • 3.InetAddress类的使用
    • 4.UDP通信程序
      • 4.1发送数据
      • 4.2接受数据
      • 4.3UDP通信程序练习(聊天室)
      • 4.4单播,组播,广播
    • 5.TCP通信程序
    • 6.综合练习
      • 6.1综合练习1(多发多收)
      • 6.2综合练习2(接收并反馈)
      • 6.3综合练习3(上传文件)
      • 6.4综合练习4(解决上一题文件名重复的问题)
      • 6.5综合练习5(上传文件一一多线程版)
      • 6.6综合练习6(线程池优化)

0.概述

内容学习自黑马程序员BV1yW4y1Y7Ms

1.初识网络编程

①什么是网络编程:计算机与计算机之间通过网络进行数据传输

②常见软件架构有哪些:CS/BS

③通信的软件架构CS/BS各有什么区别和优缺点

​ CS:客户端服务端模式需要开发客户端

​ BS:浏览器服务端模式不需要开发客户端

​ CS:适合定制专业化的办公软件如:IDEA,网游

​ BS:适合移动互联网应用,可以在任何地方随时访问的系统

2.网络编程三要素

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

端口号:应用程序在设备中唯一的标识

协议:数据在网络中传输的规则,常见的协议有UDP,TCP,http,https,ftp

3.InetAddress类的使用

InetAddress类表示互联网协议(IP)地址

public class myInetAddressDemo1 {
    public static void main(String[] args) throws UnknownHostException {
        /*
        * static InetAddress getByName(String host) 确定主机名称的IP地址。主机名称可以是机器名称,也可以是IP地址
        * String getHostName() 获取此IP地址的主机名
        * String getHostAddress() 返回文本显示中IP地址字符串
        * */

        //获取InetAddress对象
        //IP的对象或者说是主机的对象
        InetAddress address = InetAddress.getByName("LAPTOP-CFHO6DM4");
        //InetAddress address = InetAddress.getByName("192.168.213.203");
        System.out.println(address);

        //获取主机名
        String hostName = address.getHostName();
        System.out.println(hostName);

        //获取对应的ip
        String ip = address.getHostAddress();
        System.out.println(ip);
    }
}

4.UDP通信程序

4.1发送数据

①创建发送端的DatagramSocket对象;②数据打包(DatagramPacket)

③发送数据;④释放资源

public class SendMessageDemo {
    public static void main(String[] args) throws IOException {
        //1.创建发送端的DatagramSocket对象
        //细节:
        //绑定端口,以后我们就是通过这个端口往外发送
        //空参:所有可用的都拗口中随机一个进行使用
        //有参:指定端口号进行绑定
        DatagramSocket ds = new DatagramSocket();

        //2.打包要发送的数据
        String str = "好好学习,天天向上";
        byte[] bytes = str.getBytes();//转为字节数组
        InetAddress ip = InetAddress.getByName("127.0.0.1");
        int port = 10086;
        DatagramPacket dp = new DatagramPacket(bytes,bytes.length,ip,port);

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

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

4.2接受数据

①创建接收端的DatagramSocket对象;②接收打包好的数据

③解析数据包;④释放资源

public class ReceiveMessageDemo {
    public static void main(String[] args) throws IOException {
        //1.创建DatagramSocket对象
        //注意:此时接收端所指定的端口号,必须与发送方的目的端口号相一致才能接收到数据
        DatagramSocket ds = new DatagramSocket(10086);

        //2.接收打包好的数据
        byte[] bytes = new byte[1024];//创建一个字节数组来存放接收到的数据
        DatagramPacket dp = new DatagramPacket(bytes,bytes.length);

        ds.receive(dp);//接收数据,注意,这个方法是阻塞的,收不到数据程序就会停在这里

        //3.解析数据包
        byte[] data = dp.getData(); //获取接收到的字节数组
        int length = dp.getLength();//获取数据报文的长度
        int port = dp.getPort(); //获取发送方的端口号
        InetAddress ip = dp.getAddress();//获取发送方的ip
        System.out.println("收到数据:"+new String(data,0,length));
        System.out.println("数据长度:"+length);
        System.out.println("数据从发送方的"+port+"端口发出");
        System.out.println("发送方的IP地址为:"+ip);
        
        //4.释放资源
        ds.close();
    }
}

4.3UDP通信程序练习(聊天室)

按照下面的要求实现程序

UDP发送数据:数据来自于键盘录入,直到输入的数据是886,发送数据结束

UDP接收数据:因为接收端不知道发送端什么时候停止发送,故采用死循环接收

发送端

public class SendMessage {
    public static void main(String[] args) throws IOException {
        //发送端
        DatagramSocket ds = new DatagramSocket();

        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请输入你想说的话");
            String str = sc.nextLine();
            InetAddress ip = InetAddress.getByName("127.0.0.1");
            int port = 10086;//目的端口和目的地址
            DatagramPacket dp = new DatagramPacket(str.getBytes(),str.getBytes().length,ip,port);
            ds.send(dp);//发送数据
            if("886".equals(str)) break;
        }

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

    }
}

接收端

public class ReceiveMessage {
    public static void main(String[] args) throws IOException {
        //接收端
        DatagramSocket ds = new DatagramSocket(10086);

        byte[] bytes = new byte[1024];
        DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
        while (true) {
            ds.receive(dp);
            byte[] data = dp.getData();
            int length = dp.getLength();
            String ip = dp.getAddress().getHostAddress();
            String name = dp.getAddress().getHostName();
            System.out.println("收到来自ip为:"+ip+"主机名为:"+name+"所发送的信息:"+new String(data,0,length));
        }
    }
}

4.4单播,组播,广播

单播:上述代码都是单播

组播:组播地址:224.0.0.0 - 239.255.255.255,其中224.0.0.0 - 224.0.0.255为预留的组播地址

同一分组的ip都可以接收到信息

组播发送端

public class SendMessage {
    public static void main(String[] args) throws IOException {
        //组播发送端
        //创建MulticastSocket对象
        MulticastSocket ms = new MulticastSocket();

        //创建DatagramPacket对象
        String str = "你好,你好";
        byte[] bytes = str.getBytes();
        InetAddress ip = InetAddress.getByName("224.0.0.1");
        int port = 10086;
        DatagramPacket dp = new DatagramPacket(bytes,bytes.length,ip,port);

        //发送数据
        ms.send(dp);

        //释放资源
        ms.close();
    }
}

组播接收端

有多个组播接收端,只要接收端的ip为发送端目的的组播ip,就都能收到信息

public class ReceiveMessageOne {
    public static void main(String[] args) throws IOException {
        //组播接收端
        //创建MulticastSocket对象
        MulticastSocket ms = new MulticastSocket(10086);

        //将当前本机,添加到224.0.0.1这一组中
        InetAddress ip = InetAddress.getByName("224.0.0.1");
        ms.joinGroup(ip);

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

        //接收数据
        ms.receive(dp);

        //解析数据
        byte[] data = dp.getData();
        int length = dp.getLength();
        String HostAddress = dp.getAddress().getHostAddress();
        String name = dp.getAddress().getHostName();
        System.out.println("收到来自ip为:"+HostAddress+"主机名为:"+name+"所发送的信息:"+new String(data,0,length));

        //释放资源
        ms.close();
    }
}

广播:广播地址:255.255.255.255

局域网内任意ip都可以接收到信息

只需要将目的ip改为:255.255.255.255

public class SendMessageDemo {
    public static void main(String[] args) throws IOException {
        //1.创建发送端的DatagramSocket对象
        //细节:
        //绑定端口,以后我们就是通过这个端口往外发送
        //空参:所有可用的端口中随机一个进行使用
        //有参:指定端口号进行绑定
        DatagramSocket ds = new DatagramSocket();

        //2.打包要发送的数据
        String str = "好好学习,天天向上";
        byte[] bytes = str.getBytes();//转为字节数组
        InetAddress ip = InetAddress.getByName("255.255.255.255");
        int port = 10086;
        DatagramPacket dp = new DatagramPacket(bytes,bytes.length,ip,port);

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

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

5.TCP通信程序

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

通信之前要保证连接已经建立

通过Socket产生IO流来进行网络通信

客户端流程:

①创建客户端Socket对象(Socket)与指定服务端连接

Socket(String host,int port)

②获取输出流,写数据

OutputStream getOutputStream()

③释放资源

void close()
public class Client {
    public static void main(String[] args) throws IOException {
        //创建客户端Socket对象(Socket)与指定服务端连接
        Socket socket = new Socket("127.0.0.1",10000);

        //获取输出流,写数据
        OutputStream os = socket.getOutputStream();
        os.write("aaaa".getBytes());

        //释放资源
        os.close();
        socket.close();
    }
}

服务端流程:

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

ServerSocket(int port)

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

Socket accpet()

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

InputStream getInputStream()

④释放资源

void close()
public class Server {
    public static void main(String[] args) throws IOException {
        //创建服务器端的Socket对象(ServerSocket)
        ServerSocket ss = new ServerSocket(10000);

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

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

        //释放资源
        is.close();
        ss.close();
    }
}

6.综合练习

6.1综合练习1(多发多收)

客户端:多次发送数据

服务器:接收多次接收数据,并打印

客户端

public class Client {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1",10000);
        Scanner sc = new Scanner(System.in);
        OutputStream os = socket.getOutputStream();

        while (true) {
            System.out.println("请输入你要发送的信息");
            String str = sc.nextLine();
            os.write(str.getBytes());
            if("886".equals(str)) break;
        }
        socket.close();
    }
}

服务端

public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(10000);
        //监听
        Socket accept = ss.accept();

        InputStreamReader isr = new InputStreamReader(accept.getInputStream());
        int b;
        while((b= isr.read())!=-1){
            System.out.print((char)b);
        }

        //释放资源
        accept.close();
        ss.close();
    }
}

6.2综合练习2(接收并反馈)

客户端:发送一条数据,接收服务端反馈的消息并打印

服务器:接收数据并打印,再给客户端反馈消息

客户端

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

        //发送数据
        OutputStream os = socket.getOutputStream();
        String str="见到你很高兴!";
        os.write(str.getBytes());

        //写一个结束标志
        socket.shutdownOutput();

        //接受服务器端返回数据
        InputStreamReader isr = new InputStreamReader(socket.getInputStream());
        int b;
        while((b= isr.read())!=-1){
            System.out.println((char)b);
        }

        //释放资源
        socket.close();
    }
}

服务端

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

        //监听客户端
        Socket socket = ss.accept();

        //接收来自客户端的数据
        InputStreamReader isr = new InputStreamReader(socket.getInputStream());
        int b;
        while((b= isr.read())!=-1){
            System.out.println((char)b);
        }

        //对客户端进行反馈
        OutputStream os = socket.getOutputStream();
        String str="有多开心呢?";
        os.write(str.getBytes());

        socket.close();
        ss.close();
    }
}

6.3综合练习3(上传文件)

客户端:将本地文件上传到服务器。接收服务器的反馈。

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

客户端

public class Client {
    public static void main(String[] args) throws IOException {
        //创建Socket
        Socket socket = new Socket("127.0.0.1",10000);
        //读本地文件的数据,然后发出去
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("src\\ClientDir\\girl1.jpg"));
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
        int len;
        byte[] bytes = new byte[1024*5];
        while((len=bis.read(bytes))!=-1){
            bos.write(bytes,0,len);
        }
        bis.close();

        //结束标志,很关键
        socket.shutdownOutput();

        //接收服务端反馈
        InputStreamReader isr = new InputStreamReader(socket.getInputStream());
        int B;
        while((B=isr.read())!=-1){
            System.out.println((char)B);
        }

        //释放资源
        socket.close();
    }
}

服务器

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

        //监听客户端
        Socket socket = ss.accept();

        //接收客户端发来的数据,写到本地
        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("src\\ServerDIr\\girl1.jpg"));
        int len;
        byte[] bytes = new byte[1024*5];
        while((len=bis.read(bytes))!=-1){
            bos.write(bytes,0,len);
        }
        bos.close();

        //向客户端反馈
        BufferedOutputStream Bos = new BufferedOutputStream(socket.getOutputStream());
        Bos.write("上传成功".getBytes());
        Bos.flush(); // 刷新输出流,确保数据发送到客户端

        //释放资源
        socket.close();
        ss.close();
    }
}

6.4综合练习4(解决上一题文件名重复的问题)

我们可以用UUID这个类,来形成随机的文件名称

public class UUIDdemo {
    public static void main(String[] args) {
        String str = UUID.randomUUID().toString().replace("-","");
        System.out.println(str);
    }
}

修改上题的服务端代码,将文件名替换为随机的UUID

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

        //监听客户端
        Socket socket = ss.accept();

        //接收客户端发来的数据,写到本地
        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
        String name = UUID.randomUUID().toString().replace("-","");//随机的文件名
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("src\\ServerDIr\\"+name+".jpg"));
        int len;
        byte[] bytes = new byte[1024*5];
        while((len=bis.read(bytes))!=-1){
            bos.write(bytes,0,len);
        }
        bos.close();

        //向客户端反馈
        BufferedOutputStream Bos = new BufferedOutputStream(socket.getOutputStream());
        Bos.write("上传成功".getBytes());
        Bos.flush(); // 刷新输出流,确保数据发送到客户端

        //释放资源
        socket.close();
        ss.close();
    }
}

6.5综合练习5(上传文件一一多线程版)

Runnable类

public class MyRunnable implements Runnable{
    Socket socket;

    public MyRunnable(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            //接收客户端发来的数据,写到本地
            BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
            String name = UUID.randomUUID().toString().replace("-","");//随机的文件名
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("src\\ServerDIr\\"+name+".jpg"));
            int len;
            byte[] bytes = new byte[1024*5];
            while((len=bis.read(bytes))!=-1){
                bos.write(bytes,0,len);
            }
            bos.close();

            //向客户端反馈
            BufferedOutputStream Bos = new BufferedOutputStream(socket.getOutputStream());
            Bos.write("上传成功".getBytes());
            Bos.flush(); // 刷新输出流,确保数据发送到客户端
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (socket!=null) { //做一个非空判断
                try {
                    socket.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

服务端

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

        while (true) {
            //监听客户端
            Socket socket = ss.accept();

            //开启一条线程,一个用户对应服务端一条线程
            new Thread(new MyRunnable(socket)).start();
        }
    }
}

6.6综合练习6(线程池优化)

频繁创建线程并销毁非常浪费系统资源,所以要用线程池优化,需要更改的只有服务端的代码

服务端

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

        //线程池
        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
                3,//核心线程数量,不能小于0
                16,//最大线程数,不能小于0,最大数量 >= 核心线程数量
                60,//空闲线程最大存活时间
                TimeUnit.SECONDS,//时间单位
                new ArrayBlockingQueue<>(3),//任务队列
                Executors.defaultThreadFactory(),//创建线程工厂
                new ThreadPoolExecutor.AbortPolicy()//任务的拒绝策略
        );

        while (true) {
            //监听客户端
            Socket socket = ss.accept();

            //开启一条线程,一个用户对应服务端一条线程
            poolExecutor.submit(new MyRunnable(socket));
        }
    }
}

相关文章:

  • 超详细:数据库的基本架构
  • 基于NI USRP 硬件的下一代O-RAN研究测试台​
  • 服务器租用:静态BGP和动态BGP分别指什么?
  • 大白话css第七章跨领域融合创新、行业标准与规范遵循
  • Vue 3 响应式系统:最佳实践与陷阱解析
  • FlashMLA(DeepSeek开源周,第一个框架):含源码分析
  • Java+iTextPDF,实时生成与预览PDF文件的最佳实践!
  • 智慧农业中光谱相机对土壤成分的无损检测应用‌
  • python学习第三天
  • qt作业day2
  • 五分钟快速学习优秀网站的HTML骨架布局设计
  • 跨部门沟通与团队协作
  • 京东外卖上架菜品流程教学
  • LeetCode 解题思路 8(Hot 100)
  • Java Maven 项目问题:org.dom4j:dom4j:pom:2.1.3 failed to transfer from...
  • 分布式锁—2.Redisson的可重入锁一
  • 机器学习(五)
  • 线程相关八股
  • 【论文分析】语义驱动+迁移强化学习:无人机自主视觉导航的高效解决方案(语义驱动的无人机自主视觉导航)
  • 基于开源库编写MQTT通讯
  • 古稀之年的设计家吴国欣:重拾水彩,触摸老上海文脉
  • 俄需要达成怎样的特别军事行动结果?普京:包含四个方面
  • 特朗普政府涉税改法案遭众议院预算委员会否决
  • 浙江省委金融办原副主任潘广恩被“双开”
  • 中欧互动中的合作与分歧:务实需求将克服泛安全化的“政治钟摆”
  • 广西壮族自治区政府主席蓝天立任上被查