Java基础——网络编程

一、网路编程介绍

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

二、软件架构分类

 1)CS架构(Client Server 客户端 服务端)

        在用户本地有一个客户端程序,在远程有一个服务端程序(如微信)

        优点:画面精美,功能丰富用户体验度更高

        缺点:需要开发客户端,也要开发服务端,用户需要下载和更新的时候比较麻烦

        场景:适合定制专业化的办公类软件如:IDEA、网游

2)BS架构(Browser Server 浏览器 服务器端)

        只需要一个浏览器,用户通过不同的网址,客户访问不同的服务器端程序

        优点:不需要开发客户端,只需要开发服务端,用户不需要下载,打开浏览器就能使用

        缺点:如果应用过大,用户体验受到影响

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

        注:微信小程序类是BS架构,因为没有安装独立的客户端

三、网络编程三要素

1.IP:设备在网络中的唯一标识

        IPV4:

        互联网通信协议第四版,采用32位地址长度(2^32个IP地址),分成四组(点分十进制表示法:192.168.1.88),2019年11月月26日全部分配完毕,主流使用

        1.公共地址(万维网使用)和私有地址(局域网使用)

        2.192.168.开头的就是私有地址,范围在192.168.0.0~192.168.255.255,专为组织机构内部使用,以此节省IP,由交换机分配

        IPV6:互联网通信协议第六版,由于互联网的蓬勃发展,IP地址的需求量越来越大,而IPV4的模式下IP的总数有限的采用128位地址长度(2^128个IP地址),分为8组(冒分16进制表示法:2001:DB8:0:23:8:800:200C:147A,如果计算出来的16进制表示形式中间有多个连续的0会省略,变成::,这种称为0位压缩表示法)

        特殊IP地址:

        127.0.0.1,也可以是我们常说的localhost:是回送地址也称本地回环地址,也称本机IP,永远只会寻找当前所在本机(常用于本地开发)

        常用的CMD命令:

        ipconfig:查看本机IP地址

        ping:检查网络是否联通

        InetAddress 对象:

        为了方便我们对IP地址的获取和操作,Java提供 了-一个类InetAddress供我们使

        InetAddress:此类表示Internet协议(IP) 地址。

方法名说明
static InetAddress getByName(String host)确定主机名称的IP地址,主机名称可以是机器名称,也可以是IP地址
String getHostName()获取此IP地址的主机名
String getHostAddress()返回文本显示中的IP地址字符串
public static void main(String[] args) throws UnknownHostException {
        InetAddress address =  InetAddress.getByName("LAPTOP-HPUBROHL");
        System.out.println(address); //用设备名称打印出来的就是LAPTOP-HPUBROHL/172.20.10.8,用IP打印出来的就是/172.20.10.8
        String hostName = address.getHostName();
        System.out.println(hostName);
        String hostAddress = address.getHostAddress();
        System.out.println(hostAddress);
    }

2.端口:程序在设备中的唯一标识

        由两个字节表示的整数,取值范围: 0~65535

        其中0~ 1023之间的端口号用于一些知名的网络服务或者应用。

        我们自己使用1024以上的端口号就可以了。.

        注意:一个端口号只能被-一个应用程序使用。

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

       1) UDP:用户数据协议(User Datagram protocol)

        UDP是面向无连接通信协议:速度快,有大小限制一次最多64K,数据不安全,易丢失数据

        不管是否已经连接成功,都能发送

         2)TCP: 传输控制协议TCP(transmission Control Protocol)

        TCP协议是面向连接的通信协议:速度慢,没大小限制,数据安全

        需要确保连接成功才能发送数据

四、UDP 协议应用

 UDP通信——发送数据步骤:

        1.创建发送端的DatagramSocket对象
        2.数据打包(DatagramPacket)
        3.发送数据
        4.释放资源

  UDP通信——接收数据步骤:

        1.创建接收端的DatagramSocket对象
        2.接收打包好的数据
        3.解析数据包
        4.释放资源 

Send.java 

public class Send {
    public static void main(String[] args) throws Exception {
        //1.DatagramSocket创建对象,如果不传参,创建的是随机绑定的
        DatagramSocket socket = new DatagramSocket(8888);
        /*
        2.DatagramPacket创建包,打包数据
           第一个参数是字节数组
           第二个参数是字节数据长度
           第三个参数是InetAddress
           第四个是接收端的端口号
        */
        String msg = "你好,蓝天白云";
        byte[] bytes = msg.getBytes();
        //3.打包
        DatagramPacket msgPacket = new DatagramPacket(bytes,bytes.length, InetAddress.getByName("127.0.0.1"),9999);
        //4.发送
        socket.send(msgPacket);
        socket.close();
    }
}

Resolve.java 

public class Resolve {
    public static void main(String[] args) throws Exception {
        //1.DatagramSocket创建对象,注意端口号不要与发送端相同,端口号唯一
        DatagramSocket socket = new DatagramSocket(9999);
        //2.创建DatagramPacket对象,传一个字符数组,一个长度
        DatagramPacket datapcket = new DatagramPacket(new byte[1024],1024);
        //3.接收数据
        socket.receive(datapcket);
        //4.拆解
        byte[] data = datapcket.getData();
        String msg = new String(data,0,datapcket.getLength());
        System.out.println(msg);
        socket.close();
    }
}

 注意:启动是县启动接收,在启动发送

案例:

按照下面的要求实现程序
UDP发送数据:数据来自于键盘录入,直到输入的数据是886,发送数据结束
UDP接收数据:因为接收端不知道发送端什么时候停止发送,故采用死循环接收

public class Senders {
    public static void main(String[] args) throws Exception {
        //1.创建DatagramSocket对象,这里命名时为了多次启动多个报错
        DatagramSocket datagramSocket = new DatagramSocket();
        //2.输入发送的数据
        Scanner scanner = new Scanner(System.in);
        while (true){
            System.out.println("请输入:");
            final String s = scanner.nextLine();

            byte[] st = s.getBytes();
            DatagramPacket dPacket = new DatagramPacket(
                    st,s.length(), InetAddress.getByName("127.0.0.1"),3333);
            datagramSocket.send(dPacket);
            if("886".equals(s)){
                break;
            }
        }
        datagramSocket.close();
    }
}
public class ChatRoom {
    public static void main(String[] args) throws Exception {
        //1.创建DatagramSocket对象
        DatagramSocket datagramSocket = new DatagramSocket(3333);
        while (true){
            //2.创建包裹
            DatagramPacket CPacket = new DatagramPacket(new byte[1024], 1024);
            //3.接收数据
            datagramSocket.receive(CPacket);
            byte[] data = CPacket.getData();
            String cs = new String(data, 0, CPacket.getLength());
            System.out.println(cs);
        }

    }
}

五、TCP协议应用

客户端:

1.创建Socket对象指定ip 和端口
        Socket(String host, int port)
2.通过socket对象获取传输数据的流对象
       将客户端的流写入到服务端: OutputStream getoutputStream( ) 
        读取服务端书写过来的数据:InputStream getInputStream()
3.通过流对象收发数据
4.释放资源

服务端:

1.创建ServerSocket对象指定端口
        ServerSocket(int port )
2.响应客户端发送的请求
        Socket accept( )
3.通过socket 对象获取传输数据的流对象
        向客户端输出:OutputStream getoutputStream()
        读客户端输出流:InputStream getInputStream()
4.通过流对象收发数据
5.释放资源 

public class Server {
    public static void main(String[] args) throws Exception {
        /*
        1.创建ServerSocket对象指定端口
            ServerSocket(int port )
        2.响应客户端发送的请求
            Socket accept( )
        3.通过socket 对象获取传输数据的流对象
            向客户端输出:OutputStream getoutputStream()
            读客户端输出流:InputStream getInputStream()
        4.通过流对象收发数据
        5.释放资源
        * */
        //1.创建ServerSocket对象指定端口,ServerSocket(int port )
        ServerSocket serverSocket = new ServerSocket(8899);
        //2.响应客户端发送的请求
        Socket accept = serverSocket.accept();
        //3.通过socket 对象获取传输数据的流对象
        InputStream inputStream = accept.getInputStream();
        OutputStream outStream = accept.getOutputStream();
        //4.通过流对象收发数据
        byte[] bytes = new byte[1024];
        int len = inputStream.read(bytes);
        String msg = new String(bytes, 0, len);
        String hAddress = accept.getInetAddress().getHostAddress();
        System.out.println("这是" + hAddress + "发的消息:" + msg);
        outStream.write("你好".getBytes());
        //5.释放资源
        accept.close();
    }
}
public class Client {
    public static void main(String[] args) throws Exception {
        /*
        1.创建Socket对象指定ip 和端口
          Socket(String host, int port)
        2.通过socket对象获取传输数据的流对象
          将客户端的流写入到服务端:OutputStream getoutputStream( )
          读取服务端书写过来的数据:InputStream getInputStream()
        3.通过流对象收发数据
        4.释放资源
        * */
        //1.创建Socket对象指定ip 和端口,Socket(String host, int port)
        Socket socket = new Socket("127.0.0.1",8899);
        //2.通过socket对象获取传输数据的流对象
       OutputStream outStream = socket.getOutputStream();//将客户端的流写入到服务端
       InputStream inputStream = socket.getInputStream();//读取服务端写过来的数据
        //3.通过流对象收发数据
        String msg1 = "你是谁";
        outStream.write(msg1.getBytes());
        byte[] bytes = new byte[1024];
        int len = inputStream.read(bytes);
        String msg = new String(bytes, 0, len);
        String hAddress = socket.getInetAddress().getHostAddress();
        System.out.println("这是" + hAddress + "发的消息:" + msg);
        //4.释放资源
        socket.close();
    }
}

注意:先启动服务端

 TCP的三次握手

         第一次:客户单端向服务器发出连接请求(SYN包),等待服务器确认

         第二次:服务器向客户端返回一个响应(SYN包 + ACK包),告诉客户端收到请求

         第三次:客户端向服务器再次发出确认信息(ACK包),连接建立

 TCP的四次挥手

         第一次:客户端向服务器发出取消连接请求

         第二次:服务器向客户端返回一个响应,表示接收到客户端取消请求

                (服务器讲最后的数据处理完毕)

         第三次:服务器向客户端发出确认取消信息

         第四次:客户端再次发送确认信息,连接取消 

 案例:模拟上传文件

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

要求:处理文件重名、多线程、使用线程池

Server.java 

public class Server {
    public static void main(String[] args) throws Exception {
        ThreadPoolExecutor pool = new ThreadPoolExecutor(
                2,
                5,
                60,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(10),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy()
        );
        //1.创建Socket对象
        ServerSocket server = new ServerSocket(8899);
        System.out.println("服务端已启动……");
        while (true){
            //2.响应客户端发送的请求
            Socket socket = server.accept();
            //实现多线程,频繁新建和销毁线程会降低效率
            //new Thread(new SubmintText(socket)).start();
            //线程池维护线程,提高效率
            pool.submit(new SubmintText(socket));

        }



    }
}

SubmintText.java 

public class SubmintText implements Runnable{
    private Socket socket;
    public SubmintText(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {


        try {
            //3.获取传输数据的流对象
            InputStream is = socket.getInputStream();
            OutputStream os = socket.getOutputStream();

            BufferedReader bR = new BufferedReader(new InputStreamReader(is));
            BufferedWriter bW = new BufferedWriter(new OutputStreamWriter(os));
            //4.读取上传文件名
            String fileName = bR.readLine();
            //5.会写客户端信息(可以上传字节了)
            bW.write("ok");
            bW.newLine();//写换行
            bW.flush();//刷数据

            //注意:手动拼接服务端的存储位置
            //UUID.randomUUID().toString()生成一个随机字符串用于解决文件名字重复问题
            File file = new File("D:\\java\\javaStudy\\javaStudy\\img", UUID.randomUUID().toString() + fileName);
            //6.读取客户端上传的文件(字节)
            FileOutputStream fos = new FileOutputStream(file);
            byte[] bys = new byte[1024];
            int len;
            while ((len = is.read(bys)) != -1){
                fos.write(bys,0,len);
            }
            fos.close();

            //7.回写给客户端消息
            bW.write("上传成功");
            bW.newLine();
            bW.flush();
            socket.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

 Client.java

public class Client {
    public static void main(String[] args) throws Exception {
        //1.创建Socket对象
        Socket socket = new Socket("127.0.0.1", 8899);
        //2.获取传输数据的流对象
        InputStream is = socket.getInputStream();
        OutputStream os = socket.getOutputStream();

        BufferedReader bR = new BufferedReader(new InputStreamReader(is));
        BufferedWriter bW = new BufferedWriter(new OutputStreamWriter(os));
        //3.写出文件名
        File file = new File("E:\\Java_study\\A.jpg");
        bW.write(file.getName());
        bW.newLine();
        bW.flush();

        //4.读取服务端回写的信息
        String flag = bR.readLine();
        if ("ok".equals(flag)){
            //5.创建本地字节流,关联要上传的文件
            FileInputStream fis = new FileInputStream(file);
            //6.上传文件的字节
            byte[] bys = new byte[1024];
            int len;
            while ((len = fis.read(bys)) != -1){
                //因为这里获取到的事字节流所以用字节流写出
                os.write(bys,0,len);
            }
            fis.close();
            //重点:给服务端一个结束得标记
            socket.shutdownOutput();
        }

        //7.读取服务端的返回消息
        String result = bR.readLine();
        System.out.println(result);
        socket.close();

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值