什么是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();
    }
}

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();
    }
}

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();
    }
}

接收端

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();
    }
}

广播实现:

广播地址: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();
    }
}

接收端与单播接收端一致

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();
    }
}

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();
    }
}

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();
    }
}

服务端

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();
    }
}

练习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();
    }
}

服务端

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();
    }
}

多线程优化服务端

① 创建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();
                }
            }
        }
    }
}

② 服务端优化

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);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值