• 什么是UDP、TCP,怎么用UDP和TCP实现网络通信和数据传输


    网络编程:就是让两台计算机进行数据交互

    网络编程三要素

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

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

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

    1.IP

    IP:全称"互联网协议地址",也称IP地址。是分配给上网设备的数字标签。常见的ip分类为:IPv4和IPv6

    IPv4:

    IPv6:由于互联网的蓬勃发展,IP地址的需求量愈来愈大,而IPv4的模式下IP的总数是有限的。采用128位地址长度,分成8组

    特殊情况:如果计算出的16进制表示形式中间有多个连续的0

    2.端口

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

    端口号:用两个字节表示的整数,它的取值范围是065535,其中01023之间的端口用于一些知名的网络服务或者应用,我们自己使用1024以上的端口就可以了

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

    3.协议

    计算机网络中,连接和通信的规则被称为网络通信协议

    UDP协议:

    • 用户数据报协议(User Datagram Protocol)
    • UDP是面向无连接通信协议
    • 速度快,有大小限制,一次最多发送64K,数据不安全,易丢失数据

    TCP协议:

    • 传输控制协议(Transmission Control Protocol)
    • TCP协议是面向连接的通信协议
    • 速度慢,没有大小限制,数据安全

    4.UDP发送数据

    步骤:

    ① 创建发送端的DatagramSocket对象

    ② 创建数据,并把数据打包(DatagramPacket)

    ③ 调用DatagramSocket对象的方法发送数据

    ④ 释放资源

    public class ClientDemo {
        public static void main(String[] args) throws IOException {
            //创建发送对象
            DatagramSocket ds = new DatagramSocket();
    
            //创建数据
            String s = "给老村长送礼物";
            byte[] bytes = s.getBytes();
            InetAddress ip = InetAddress.getByName("127.0.0.1");
            int port = 10000;
            DatagramPacket dp = new DatagramPacket(bytes,bytes.length,ip,port);
    
            //发送
            ds.send(dp);
            ds.close();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    5.UDP接收数据

    ① 创建接收端的DatagramSocket对象

    ② 创建一个箱子,用于接收数据

    ③ 调用DatagramSocket的方法接收数据并将数据放入箱子中

    ④ 解析数据包,并把数据在控制台显示

    ⑤ 释放资源

    public class ServerDemo {
        //注意先启动接收端,再启动发送端
        public static void main(String[] args) throws IOException {
            //1.创建datagramSocket对象
            DatagramSocket ds = new DatagramSocket(10000);
    
            //2.创建一个新的箱子
            byte[] bytes = new byte[1024];
            DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
            //3.接收数据
            System.out.println("------------接收前---------");
            ds.receive(dp);
            System.out.println("------------接收后---------");
            //4.从新的箱子获取数据
            //byte[] data = dp.getData();
            int length = dp.getLength();
            System.out.println(new String(bytes,0,length));
            ds.close();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    6.UDP的三种通信方式

    ① 单播

    ② 组播

    ③ 广播

    之前的实现为单播实现

    组播实现:

    组播地址:224.0.0.0239.255.255.255,其中224.0.0.0239.0.0.255为预留地址

    发送端

    public class ClientDemo2 {
        public static void main(String[] args) throws IOException {
            //创建发送对象
            DatagramSocket ds = new DatagramSocket();
    
            //创建数据
            String s = "hello组播";
            byte[] bytes = s.getBytes();
            InetAddress ip = InetAddress.getByName("224.0.1.0");
            int port = 10000;
            DatagramPacket dp = new DatagramPacket(bytes,bytes.length,ip    ,port);
    
            //发送
            ds.send(dp);
            ds.close();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    接收端

    public class ServerDemo2 {
        //注意先启动接收端,再启动发送端
        public static void main(String[] args) throws IOException {
            //1.创建MulticastSocket对象
            MulticastSocket ms = new MulticastSocket(10000);
            //2.创建一个新的箱子
            byte[] bytes = new byte[1024];
            DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
    
            //3.把当前计算机绑定一个组播地址,表示添加到这一组中
            ms.joinGroup(InetAddress.getByName("224.0.1.0"));
            //4.接收数据
            System.out.println("------------接收前---------");
            ms.receive(dp);
            System.out.println("------------接收后---------");
            //5.从新的箱子获取数据
            //byte[] data = dp.getData();
            int length = dp.getLength();
            System.out.println(new String(bytes, 0, length));
            ms.close();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    广播实现:

    广播地址:255.255.255.255

    发送端

    
    public class ClientDemo3 {
        public static void main(String[] args) throws IOException {
            //创建发送对象
            DatagramSocket ds = new DatagramSocket();
    
            //创建数据
            String s = "hello 广播";
            byte[] bytes = s.getBytes();
            InetAddress ip = InetAddress.getByName("255.255.255.255");
            int port = 10000;
            DatagramPacket dp = new DatagramPacket(bytes,bytes.length,ip,port);
    
            //发送
            ds.send(dp);
            ds.close();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    接收端与单播接收端一致

    TCP

    1.TCP通信原理

    TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象,通信之前要保证连接已经建立。

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

    2.TCP发送数据的步骤

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

    Socket(String host,int port)

    ② 获取输出流,写数据

    OutputStream getOutputStream()

    ③ 释放资源

    void close()

    public class ClientDemo4 {
        public static void main(String[] args) throws IOException {
            //创建Socket对象
            Socket socket = new Socket("127.0.0.1", 10001);
            //获取一个IO流开始写数据
            OutputStream os = socket.getOutputStream();
            os.write("hello".getBytes());
            //释放资源
            os.close();
            socket.close();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3.TCP接收数据的步骤

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

    ServerSocket(int port)

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

    Socket.accept()

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

    InputStream getInputStream()

    ④ 释放资源

    void close()

    public class ServerDemo4 {
    
        public static void main(String[] args) throws IOException {
            //1.创建客户端连接
            ServerSocket serverSocket = new ServerSocket(10001);
            //2.等待客户端连接
            System.out.println(1111);
            Socket accept = serverSocket.accept();
            System.out.println(2222);
            //3.获取输入流对象
            InputStream is = accept.getInputStream();
            int len;
            while ((len = is.read()) != -1) {
                System.out.print((char) len);
            }
            //4.释放资源
            is.close();
            serverSocket.close();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    4.细节

    ① accept()方法是阻塞的,作用等待客户端连接

    ② 客户端创建对象并连接服务器,此时是通过三次握手协议保证跟服务器之间的连接

    ③ 针对客户端来讲,是往外写的,所以是输出流,针对服务器来讲,是往里读的,所以是输入流

    ④ read()方法也是阻塞的

    ⑤ 在关流的时候,还多了一个往服务器写结束标记的动作

    ⑥ 最后一步断开连接,通过四次挥手协议保证连接终止

    5.三次握手

    6.四次挥手

    7.TCP通信程序练习

    练习1:

    ① 客户端:发送数据,接收服务器反馈

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

    客户端

    public class ClientDemo5 {
        public static void main(String[] args) throws IOException {
            //创建Socket对象
            Socket socket = new Socket("127.0.0.1", 10001);
            //获取一个IO流开始写数据
            OutputStream os = socket.getOutputStream();
            os.write("hello".getBytes());
            socket.shutdownOutput();
            /*InputStream is = socket.getInputStream();
            int b;
            while ((b=is.read())!=-1){
                System.out.println((char) b);
            }*/
            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();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    服务端

    public class ServerDemo5 {
        public static void main(String[] args) throws IOException {
            //1.创建客户端连接
            ServerSocket serverSocket = new ServerSocket(10001);
            //2.等待客户端连接
            System.out.println(1111);
            Socket accept = serverSocket.accept();
            System.out.println(2222);
            //3.获取输入流对象
            InputStream is = accept.getInputStream();
            int len;
            while ((len = is.read()) != -1) {
                System.out.print((char) len);
            }
            System.out.println("执行了吗");
           /* OutputStream os = accept.getOutputStream();
            os.write("你谁啊".getBytes());*/
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
            bw.write("你谁啊");
            //4.释放资源
            bw.close();
            is.close();
            accept.close();
            serverSocket.close();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    练习2:

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

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

    客户端

    public class ClientDemo6 {
        public static void main(String[] args) throws IOException {
            //创建Socket对象
            Socket socket = new Socket("127.0.0.1", 10001);
            //本地的流,用来读取本地文件
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream("filemodule\\ClientDir\\1.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);
            }
            //释放资源
            bis.close();
            socket.close();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    服务端

    public class ServerDemo6 {
        public static void main(String[] args) throws IOException {
            //1.创建客户端连接
            ServerSocket serverSocket = new ServerSocket(10001);
            while (true) {
                //2.等待客户端连接
                Socket accept = serverSocket.accept();
                //3.网络中的流,从客户端读取数据
                BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());
                //4.本地的IO流,把数据写到本地中,实现永久化存储
                BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("filemodule\\ServerDir\\"+ UUID.randomUUID().toString()+".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();
                //4.释放资源
                bos.close();
                accept.close();
            }
            //serverSocket.close();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    多线程优化服务端

    ① 创建ThreadSocket线程,客户端与之前一致

    public class ThreadSocket implements Runnable {
    
        private Socket acceptSocket;
    
        public ThreadSocket(Socket accept) {
            this.acceptSocket = accept;
        }
    
        @Override
        public void run() {
            BufferedOutputStream bos = null;
            try {
                BufferedInputStream bis = new BufferedInputStream(acceptSocket.getInputStream());
                //4.本地的IO流,把数据写到本地中,实现永久化存储
                bos = new BufferedOutputStream(new FileOutputStream("filemodule\\ServerDir\\" + UUID.randomUUID().toString() + ".jpg"));
                int b;
                while ((b = bis.read()) != -1) {
                    bos.write(b);
                }
                BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(acceptSocket.getOutputStream()));
                bw.write("上传成功");
                bw.newLine();
                bw.flush();
    
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //4.释放资源
                if (bos != null) {
                    try {
                        bos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (acceptSocket != null) {
                    try {
                        acceptSocket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    ② 服务端优化

    public class ServerDemo6 {
        public static void main(String[] args) throws IOException {
            //1.创建客户端连接
            ServerSocket serverSocket = new ServerSocket(10002);
            ThreadPoolExecutor pool = new ThreadPoolExecutor(
                    3,//核心线程数
                    10,//线程池的总数量
                    60,//临时线程空闲时间
                    TimeUnit.SECONDS,//临时线程空闲时间的单位
                    new ArrayBlockingQueue<>(5),//阻塞队列
                    Executors.defaultThreadFactory(),//创建线程的方式
                    new ThreadPoolExecutor.AbortPolicy()//任务拒绝策略
            );
            while (true) {
                //2.等待客户端连接
                Socket accept = serverSocket.accept();
                ThreadSocket ts = new ThreadSocket(accept);
                //new Thread(ts).start();
                pool.submit(ts);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
  • 相关阅读:
    mysql8.0以上修改密码-干货版
    解决Java异常java.sql.SQLException: Unexpected exception encountered during query.
    Typecho中handsome主题如何增加侧边导航栏
    一文让您读懂实时数仓(Apache Doris)
    60.WEB渗透测试-信息收集- 端口、目录扫描、源码泄露(8)
    职场Excel:求和家族,不简单
    服务器搭建(TCP套接字)-fork版(服务端)
    洛谷-P5019-铺设道路
    KY91 String Matching
    [附源码]java毕业设计社区志愿者服务系统
  • 原文地址:https://blog.csdn.net/weixin_46665411/article/details/127823829