Java网络编程(UDP、TCP)

什么是网络编程?

在网络通信协议下,不同计算机上运行的程序,进行的数据传输。

  • 应用场景:即时通信、网游对战、金融证券、国际贸易、邮件、等等。

不管是什么场景,都是计算机跟计算机之间通过网络进行数据传输。

  • Java中可以使用java.net包下的技术轻松开发出常见的网络应用程序。

    总结

  1. 什么网络编程?

    计算机跟计算机之间通过网络进行数据传输。

  2. 常见软件架构有哪些?

    CS/BS

  3. 通信的软件架构CS1BS的各有什么区别和优缺点

    CS:客户端服务端模式需要开发客户端
    BS:浏览器服务端模式不需要开发客户端。
    CS:适合定制专业化的办公类软件如:IDEA、网游
    BS:适合移动互联网应用,可以在任何地方随时访问的系统。

网络编程三要素

  • IP

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

  • 端口号

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

  • 协议

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

总结

  1. 网络编程三要素分别是什么?

    IP、端口号、协议

  2. 网络编程三要素分别表示什么?

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

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

    协议:数据在网络中传输的规则

    ​ 常见的协议有UDP、TCP、http、https、ftp

IP

全称:Internet Protocol,是互联网协议地址,也称IP地址。

是分配给上网设备的数字标签。

通俗理解 上网设备在网络中的地址,是唯一的

常见的IP分类为IPV4、IPV6

IPv4

全称:Internet Protocol version4,互联网通信协议第四版。
采用32位地址长度,分成4组

IPv6

全称:Internet Protocol version6,互联网通信协议第六版。
由于互联网的蓬勃发展,IP地址的需求量愈来愈大,而引PV4的模式下IP的总数是有限的。
采用128位地址长度,分成8组。 2^128

IPV4的地址分类形式

  • 公网地址(万维网使用)和私有地址(局域网使用)。
  • 192.168.开头的就是私有址址,范围即为192.168.0.0–192.168.255.255,专门为组织机构内部使用,以此节省1P

特殊IP地址

​ 127.0.0.1,也可以是localhost:是回送地址也称本地回环地址,也称本机IP,永远只会寻找当前所在本机。

InetAddress类

端口号

​ 应用程序在设备中唯一的标识。
端口号:由两个字节表示的整数,取值范围:0~65535
​ 其中0~1023之间的端口号用于一些知名的网络服务或者应用。
​ 我们自己使用1024以上的端口号就可以了。
注意:一个端口号只能被一个应用程序使用。

协议

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

  • OS引参考模型:世界互联协议标准,全球通信规范,单模型过于理想化,未能在因特网上进行广泛推广
  • TCP/IP参考模型(或TCP/IP协议):事实上的国际标准。
OSI参考模型TCP/IP 参考模型TCP/IP 参考模型各层对应协议面向哪些
应用层应用层HTTP\FTP\Telnet\DNS
表示层应用层HTTP\FTP\Telnet\DNS
会话层应用层HTTP\FTP\Telnet\DNS
传输层传输层TCP\UDP…选择传输使用的TCP,UDP协议
网络层网络层IP\ICMP\ARP封装IP
数据链路层物理+数据链路层硬件设备 010101010101…转换成二进制利用物理设备传输
物理层物理+数据链路层硬件设备 010101010101…转换成二进制利用物理设备传输

UDP协议

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

TCP协议

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

JDP通信程序

UDP通信程序(发送数据)

  1. 找快递公司 创建发送端的DatagramSocket对象
  2. 打包礼物 数据打包(DatagramPacket)
  3. 快递公司发送包裹 发送数据
  4. 付钱走人 释放资源
public class SendMessageDemo {
    //发送数据通过Socket发送
    public static void main(String[] args) throws IOException {
        // 1. 创建Socket
        DatagramSocket datagramSocket = new DatagramSocket();
        byte buf[] = "Hello Word".getBytes(StandardCharsets.UTF_8);
        int offset = buf.length;
        InetAddress address = InetAddress.getByName("127.0.0.1");
        int port = 10086;
        	// 打包数据,此处需要明确address, port这样创建的DatagramPacket才可以被发送
        	// 否则会提示 null address || null buffer
        	// 该构造函数有英文 Constructs a datagram packet for sending packets 
        DatagramPacket p = new DatagramPacket(buf, offset, address, port);
		// 发送打包的内容并关闭Socket
        datagramSocket.send(p);
        datagramSocket.close();
    }
}

UDP通信程序(接收数据)

  1. 找快递公司 创建接收端的DatagramSocketi对象
  2. 接收箱子 接收打包好的数据
  3. 从箱子里面获取礼物 解析数据包
  4. 签收走人 释放资源
public class ReceiveMessageDemo {
    public static void main(String[] args) throws IOException {
        DatagramSocket datagramSocket = new DatagramSocket(PORT);
        byte[] buf = new byte[1024];
        DatagramPacket p = new DatagramPacket(buf, buf.length);
        // 该方法是阻塞的
        datagramSocket.receive(p);
        System.out.println(new String(p.getData(), 0, p.getLength()));
        datagramSocket.close();
    }
}

发送与接收都使用到了DatagramSocket、DatagramPacket,DatagramPacket不指定端口号则代表为接收方,

DatagramSocket 的receive方法也代表了此文接收方。

UDP的三种通信方式

  • 单播

    以前的代码就是单播

  • 组播

    组播地址:

224.0.0.0 ~ 239 - 255.255.255

(其中 224.0.0.0 ~ 224.0.0.255 为预留的组播地址)

  • 广播

    广播地址:255.255.255.255

TCP通信程序

TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象
通信之前要保证连接已经建立
通过Socket产生IO流来进行网络通信

综合练习

聊天室多发练习

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;

public class ChatRoom {
    public static void main(String[] args) throws IOException {
        System.out.println("Please enter your username:");
        Scanner scanner = new Scanner(System.in);
        String username = scanner.nextLine();
        User user = new User(username);
        user.start();
    }
}

class User {
    private InetAddress group;
    private int port;
    private String username;

    public User(String username) throws UnknownHostException {
        this.group = InetAddress.getByName("224.0.0.1");
        this.port = 8888;
        this.username = username;
    }

    public void start() throws IOException {
        MulticastSocket multicastSocket = new MulticastSocket(this.port);
        multicastSocket.joinGroup(this.group);

        new Thread(new RunnableTask(multicastSocket, this.username)).start();

        System.out.println("Begin Chat...");
        Scanner scanner = new Scanner(System.in);
        while (true) {
            String messages = scanner.nextLine();
            messages = this.username + ":" + messages;
            byte[] buf = messages.getBytes(StandardCharsets.UTF_8);

            DatagramPacket packet = new DatagramPacket(buf, buf.length, group, this.port);
            multicastSocket.send(packet);
        }
    }
}

class RunnableTask implements Runnable {
    private MulticastSocket multicastSocket;
    private String username;

    public RunnableTask(MulticastSocket multicastSocket, String username) {
        this.multicastSocket = multicastSocket;
        this.username = username;
    }

    @Override
    public void run() {
        byte[] bytes = new byte[1024];
        while (true) {
            try {
                DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length);
                multicastSocket.receive(packet);

                String userNameAndMessage = new String(packet.getData(), 0, packet.getLength());
                if (userNameAndMessage.contains(this.username)) {
                    continue;
                }
                System.out.println(userNameAndMessage);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

TCP 文件传输练习

注意点:客户端/服务端 发送完数据需要通过socket关闭OutPut,为了增加读写效率使用了Buffered流

客户端

import java.io.*;
import java.net.Socket;

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

        File file = new File("D:\\Program Files\\IdeaProjects\\mysocketnet\\clientdir\\1.png");
        FileInputStream fileInputStream = new FileInputStream(file);
        BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
        OutputStream outputStream = socket.getOutputStream();
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
        // 数据缓冲区
        byte[] bytes = new byte[1024];
        int len;
        while ((len = bufferedInputStream.read(bytes)) != -1) {
            // 缓冲区最后一次的长度可能不是1024,需要通过InputStream.read 确定
            bufferedOutputStream.write(bytes, 0, len);
        }

        socket.shutdownOutput();

        InputStream inputStream = socket.getInputStream();
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        System.out.println(bufferedReader.readLine());

        socket.close();
    }
}

服务端


import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Server {

    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(10000);
        ExecutorService executorService = Executors.newCachedThreadPool();
        while (true) {
            Socket socket = serverSocket.accept();
            executorService.submit(new MyRunnable(socket));
        }
//        serverSocket.close();
    }


}

自定义任务


import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.UUID;

public class MyRunnable implements Runnable {
    Socket socket;

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

    @Override
    public void run() {
        InputStream inputStream = null;
        try {
            inputStream = this.socket.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        String replace = UUID.randomUUID().toString().replace("-", "");
        FileOutputStream fileOutputStream = null;
        try {
            fileOutputStream = new FileOutputStream("D:\\Program Files\\IdeaProjects\\mysocketnet\\serverdir\\" + replace + ".png");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        byte[] bytes = new byte[1024];
        int read = 0;
        // inputStream.read 会一致读取,直到socket发送了shutdownOutput
        while (true) {
            try {
                if ((read = inputStream.read(bytes)) != -1) {
                    break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                fileOutputStream.write(bytes, 0, read);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        OutputStream outputStream = null;
        try {
            outputStream = socket.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        String message = "数据接受完毕";
        try {
            outputStream.write(message.getBytes(StandardCharsets.UTF_8));
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            socket.shutdownOutput();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值