大数据预科20(补充之网络编程)

网络编程

网络通讯协议

  • 位于同一网络的计算机在进行连接和通讯时需要遵循一定的规则。这些连接和通讯的规则被称为网络通讯协议。
  • 网络通讯协议:对数据的传输格式、传输速率,传输步骤都做了统一规定,通讯双方必须同时遵守才可以完成数据交换。
  • TCP/IP协议:
    • 应用层(HTTP,FTP,DNS)
      • 主要负责应用程序的协议,
    • 传输层(TCP,UDP)
      • 主要使网络程序进行通讯,在进行网络通讯时,可以采用TCP协议,也可以采用UDP协议
    • 网络层(IP,ICMP,IGMP)
      • 网络层是整个TCP/IP的核心,它主要用于将传输数据进行分组,将分组数据发送到目标计算机或者网络
    • 链路层(驱动程序,接口)
      • 用于定义物理传输通道,通常是对某网络连接设备的驱动协议,例如针对光纤,网络提供的驱动
  • IP地址和端口号
    • TCP/IP协议中,IP地址唯一标识一台计算机
      • IP地址广泛使用IPv4--4个字节大小的二进制数来表示--为了便于记忆,将每一个字节写成十进制数来表示(每个字节0~255),数字间用.分隔开
      • 随着计算机网络的不断扩大,对IP地址的需求不断扩大,IPv4的资源面临枯竭,因此IPv6应运而生。IPv6使用了16个字节来表示IP地址,他所拥有的的容量是IPv4的8*1028倍,达到2128个(算上全0的)
      • 通过IP地址可以连接到指定的计算机,但是要访问计算机的某个应用程序,还需要指定端口号。在计算机中,不同的应用程序是通过端口号区分的,端口号是用两个字节(16位)表示的,它的取值是0~65535。0~1023之间的端口号用于一些知名的网络服务和应用,用户的普通应用程序用1024以上的端口,从而避免被另外一个应用或服务所占用。
      • 【源计算机】—(IP地址)—>【目标计算机】—(端口号)—>【应用程序】
  • InetAddress
    • 该类用于封装一个IP地址,并提供了一系列的与IP地址相关的方法
      • getByName(String host)给定主机名获取主机的IP地址
      • getLocalHost()返回本地主机
      • getHostName()返回此IP地址的主机名
      • getHostAddress()返回IP地址字符串
    • 实例

      //获取InetAddress对象
      InetAddress local=InetAddress.getLocalHost();
      InetAddress remote=InetAddress.getByName("www.itcast.cn");
      //获取IP地址
      local.getHostAddress();
      remote.getHostAddress();
      //获取主机名
      remote.getHostName();
      

TCP/UDP协议

  • UDP协议

    • User Datagram Protocol用户数据报协议
    • 无连接通讯协议--数据的发送端和接收端不建立逻辑连接:发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。
    • 优点:消耗资源小,通讯效率高
    • 适用:音频,视频,普通数据---丢失几个数据不会产生太大的影响
    • 缺点:UDP面向无连接性,不能保证数据的完整性--在传输重要数据时,不建议使用UDP协议。
  • Tcp协议

    • Transmission Control Protocol传输控制协议
    • TCP是面向连接的通讯协议,即在传输数据前先在发送端和接收端建立逻辑连接,然后再传输数据。
    • 无差错数据传输
    • 每次创建连接--三次握手
      • 第一次握手:客户端向服务器发出连接请求,等待服务器的确认
      • 第二次握手:服务器向客户端发送一个响应,通知客户端接收到了请求
      • 第三次握手:客户端再次向服务器端发送确认信息,确认连接
    • TCP面向连接的特性,它可以保证传输数据的安全性,所以是一个被广泛采用的协议--下载文件时必须采用TCP协议

UDP通讯

  • 生活小例子
    • 货运公司发送货物,集装箱来装载货物---这里的集装箱在程序中用DatagramPacket----码头DatagramSocket
    • 构造函数--发送方和接收方不同
      • 发送方:字节数组,IP地址,端口号DatagramPacket(byte[] buf,int length)
      • 接收方:只需一个字节数组DatagramPacket(byte[] buf,int length,InetAddress address,int port)
  • DatagramPacket常用方法
    • getAddress()
      • 返回某台机器的IP地址,此数据报包要发往该机器或者是从该机器接收到的
    • getPort()
      • 返回某台远程主机的端口号,此数据包将要发往该主机或者是从该主机接收到的
    • getData()
      • 返回数据缓冲区
    • getLength()
      • 返回将要发送或接受到的数据的长度
  • DatagramSocket
    • 运货的码头
    • 接受和发送DatagramPacket数据包
    • 构造函数--发送方和接收方不同
      • 发送端:DatagramSocket(),不指明端口,此时系统会分配一个没有被其他网络程序所使用的端口
      • 接收端(或接收端):DatagramSocket(int port),即可以创建接收端,又可以创建发送端
    • 常用方法
      • receive(DatagramPacket p)--此套接字用于接收数据包
      • send(DatagramPacket p)--从套接字发送数据包
  • UDP网络程序

    • 通讯时,只有接收端程序先运行才可以避免因发送端发送的数据而无法接收,而造成数据丢失
    • 发送端

      package com.peng.demo;
      
      import java.net.DatagramPacket;
      import java.net.DatagramSocket;
      import java.net.InetAddress;
      
      /**
       * @author kungfu~peng
       * @data 2017年9月28日
       * @description 接收端
       */
      public class SocketDemo {
          public static void main(String[] args) throws Exception {
              // 1.创建DatagramSocket对象,并指定端口号
              DatagramSocket receiveSocket = new DatagramSocket(12307);
              // 2.创建DatagramPacket对象,创建一个空的仓库
              byte[] buffer = new byte[1024];
              DatagramPacket dp = new DatagramPacket(buffer, 1024);
              // 3.接收数据存储到DatagramPacket对象中
              receiveSocket.receive(dp);
              // 4.获取DatagramPacket对象的内容
              InetAddress ipAddress = dp.getAddress();// 谁发来的数据
              String ip = ipAddress.getHostAddress();// 获取ip地址
              byte[] data = dp.getData();// 发来了什么数据
              int length = dp.getLength();// 数据的长度
              String dataStr = new String(data, 0, length);// 将数据转化为字符串
              System.out.println("ip地址:" + ip + ",数据时:" + dataStr);
              // 释放流资源
              receiveSocket.close();
          }
      }
      
      • 发送端

      package com.peng.demo;
      
      import java.net.DatagramPacket;
      import java.net.DatagramSocket;
      import java.net.InetAddress;
      
      /**
       * @author kungfu~peng
       * @data 2017年9月28日
       * @description 发送端
       */
      public class SocketDemo1 {
          public static void main(String[] args) throws Exception {
              // 1.创建DatagramSocket对象
              DatagramSocket sendSocket = new DatagramSocket();
              // 2.创建DatagramPacket对象,并封装数据--构造数据包,用长度为length的包发送到主机上的指定端口号
              byte[] buffer = "Hello,UDP,你好!".getBytes();
              DatagramPacket dp = new DatagramPacket(buffer, buffer.length,
                      InetAddress.getByName("192.168.43.242"), 12307);
              // 发送数据
              sendSocket.send(dp);
              // 释放流资源
              sendSocket.close();
          }
      }
      

TCP通讯

  • TCP严格区分客户端与服务端,在通讯中,必须先由客户端去连接服务器端才能实现通讯,服务端不可以主动连接客户端,并且服务器端程序需要事先启动,等待客户的连接。
  • ServerSocket表示服务器
  • Socket表示客户端
  • 通信

1. 首先创建代表服务器的ServerSocket对象,该对象相当于开启一个服务,并等待客户的连接
2. 然后创建代表客户端的Socket对象向服务器端发出连接请求
3. 服务器端响应请求,两者建立连接,开始通信
  • ServerSocket
    • 构造方法ServerSocket(int port)
    • 常用方法
      • accept()侦听并接收此套接字的连接
      • getInetAddress()返回此套接字的本地地址
    • 流程

      1. ServerSocket对象负责监听计算机的某个端口号
      2. 调用对象的accept()方法,接收来自客户端的请求-----服务端程序会发生阻塞
      3. 直到客户端发出连接请求,accept()方法才会返回一个Socket对象用于和客户端实现通信
      
  • Socket
    • TCP实现TCP客户端程序
    • 构造函数
      • Socket(String host,int port)
      • Socket(IpnetAddress address,int port)
    • 常用方法
      • getPort()Socket对象与服务器连接的端口号
      • getLocalAddress()获取Socket对象绑定的本地IP地址并封装成InetAddress对象
      • close()该方法关闭Socket连接,
      • getInputStream()该方法返回输入流对象-----服务器和客户端都可以有,用于读取数据
      • getOutputStream该方法返回输出流对象-----服务器和客户端都可以有,用于写入数据
  • 简单的TCP程序

    • 服务端

      package com.peng.demo;
      
      import java.io.OutputStream;
      import java.net.ServerSocket;
      import java.net.Socket;
      
      /**
       * @author kungfu~peng
       * @data 2017年9月28日
       * @description tcp服务端
       */
      public class TcpServer {
          public static void main(String[] args) throws Exception {
              // 1.创建服务器ServerSocket对象(指定服务器端口号)
              ServerSocket ss = new ServerSocket(8888);
              // 2.开启服务器,等待客户端的连接,当客户端连接后,可以获取到连接到服务器端的的客户端Socket对象
              Socket s = ss.accept();
              // 3.给客户端反馈信息--获取客户端的输出流,写数据给客户端
              OutputStream out = s.getOutputStream();
              out.write("已经连接到客户端!".getBytes());
              // 4.关闭流资源
              out.close();
              s.close();
              // ss.close();//通常服务器是不关闭的
          }
      
      }
      
    • 客户端

      package com.peng.demo;
      
      import java.io.InputStream;
      import java.net.Socket;
      
      /**
       * @author kungfu~peng
       * @data 2017年9月28日
       * @description tcp客户端
       */
      public class TcpClient {
          public static void main(String[] args) throws Exception {
              // 1.创建客户端Socket对象,指定服务器地址与端口号
              Socket s = new Socket("192.168.43.242", 8888);
              // 2.获取服务器端反馈回来的数据
              InputStream in = s.getInputStream();
              // 3.获取流中的数据
              byte[] buffer = new byte[1024];
              // 把流中的数据存储到数组中,并记录读取字节的个数
              int length = in.read(buffer);
              // 显示数据
              System.out.println(new String(buffer, 0, length));
              // 关闭流
              in.close();
              s.close();
          }
      
      }
      

补充

  • 套接字
    • 实际上是一套用于网络通讯的API,本质上是一套基于网络传输数据的流
    • IP地址--IPv4--由四组组成的IP地址,每组范围0-255(232
    • IP地址--IPv6--由6组组成的IP地址,每组范围0000-ffff(296
    • 端口--用于和外界进行信息交互的媒介--0~65535,其中0~1024是已经被计算机内部和常用应用占用;访问网站的默认端口为80
    • 255.255.255.255广播地址,只要在同一个网段中,都可以接收到
    • UDP每次发送数据不超64k,TCP每次方式理论上无限制
    • TCP中:
      • socket.connect(new InetSocketAddress(String address,int port)//连接
      • socket.shutdownOutput();//给一个数据发送结束标志
    • 阻塞:receive;connect;accept;read;write;
    • 扩展:BIO阻塞式IO,同步式阻塞式IO--BlockingIO
    • 扩展:NIO--JDK1.4--非阻塞式IO--NonBlockingIO
    • 扩展:AIO--AsynchronousIO--异步式非阻塞IO---JDK1.8
  • UDP命令式输入

    package com.peng.threaddemo;
    
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetSocketAddress;
    import java.util.Scanner;
    
    /**
     * @author kungfu~peng
     * @data 2017年11月11日
     * @description
     */
    public class ThreadDemo {
        public static void main(String[] args) {
            new Thread(new Udp_Server()).start();
            new Thread(new Udp_Client()).start();
        }
    }
    
    class Udp_Client implements Runnable {
        // 输入流
        Scanner scanner = new Scanner(System.in);
        // 命令
        String order = "over";
        // 端口
        DatagramSocket ds = null;
        // 数据包
        DatagramPacket dp = null;
        // 聊天内容
        String temp = "hello!";
        // 退出标志
        boolean flag_exit = false;
    
        @Override
        public void run() {
            try {
                // 创建端口
                ds = new DatagramSocket();
                while (!flag_exit) {
                    System.out.println("请输入命令:退出--over,进入--in");
                    order = scanner.nextLine();
                    // 获得命令
                    if ("over".equals(order)) {
                        System.out.println("Byebye~~");
                        flag_exit = true;
                        ds.close();
                    } else if ("in".equals(order)) {
                        while (true) {
                            System.out.println("请输入具体内容,over结束");
                            temp = scanner.nextLine();
                            // 判断输入的内容
                            if ("over".equals(temp)) {
                                System.out.println("Byebye~~");
                                flag_exit = true;
                                ds.close();
                                break;
                            }
                            // 制作数据包
                            dp = new DatagramPacket(temp.getBytes(),
                                    temp.getBytes().length, new InetSocketAddress(
                                            "127.0.0.1", 6666));
                            // 发送数据包
                            ds.send(dp);
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    class Udp_Server implements Runnable {
        DatagramSocket ds = null;
        DatagramPacket dp = null;
    
        @Override
        public void run() {
            try {
                // 套接字
                ds = new DatagramSocket(6666);
                // 常开服务器,接收数据
                while (true) {
                    // 数据包
                    dp = new DatagramPacket(new byte[1024], 1024);
                    // 接收数据
                    ds.receive(dp);
                    // 打印数据
                    System.out.println("Client Say:"
                            + new String(dp.getData(), 0, dp.getLength()));
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

文件的上传

  • 文件名一致
    • 合并:文件名+数据-->和
    • 分开:和-->文件名+数据

    package com.peng.threaddemo;

    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.ServerSocket;
    import java.net.Socket;

    /**
     * @author kungfu~peng
     * @data 2017年11月11日
     * @description 客户端文件的上传与下载
     */
    public class FileSocket {
        public static void main(String[] args) {
            new Thread(new FileServer()).start();
            new Thread(new FileClient(new File(
                    "C:\\Users\\Administrator.PC-20160710IJPJ\\Desktop\\校招.md")))
                    .start();
        }
    }

    /**
     * 
     * @author kungfu~peng
     * @data 2017年11月11日
     * @description文件上传
     */
    class FileClient implements Runnable {
        File file = null;

        // 构造函数--将上传的文件传入
        public FileClient(File file) {
            this.file = file;
        }

        @Override
        public void run() {
            try {
                // 准备端口
                Socket socket = new Socket("127.0.0.1", 6666);
                // 获得文件的输入流进行读取文件
                InputStream is = new FileInputStream(file);
                // 获取端口输出流
                OutputStream os = socket.getOutputStream();
                // 加入文件名和特殊字符【文件名***】
                os.write((file.getName() + "666").getBytes(), 0,
                        (file.getName() + "666").getBytes().length);
                // 将文件写出
                byte[] data = new byte[1024];
                int len = -1;
                // 开始写到文件到流中
                while ((len = is.read(data)) != -1) {
                    os.write(data, 0, len);
                }
                // 文件名的上传
                socket.shutdownOutput();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 
     * @author kungfu~peng
     * @data 2017年11月11日
     * @description服务端文件的获取
     */
    class FileServer implements Runnable {

        @Override
        public void run() {
            try {
                // 获得服务器端的端口
                ServerSocket ss = new ServerSocket(6666);
                // 获得发来数据的端口
                Socket s = ss.accept();
                // 获得输入流进行读取数据
                InputStream is = s.getInputStream();
                // 准备数据
                byte[] data = new byte[1024];
                int len = -1;
                String temp = "";
                // 获得文件的数据字符串
                while ((len = is.read(data)) != -1) {
                    temp += new String(data, 0, len);
                }
                // 拆分文件名和数据
                String[] data22 = temp.split("666");
                System.out.println(data22[0]);
                // 写数据到该文件
                File file = new File("E:\\" + data22[0]);
                // 将文件写出到特定的位置--获取文件名+获取具体的数据
                OutputStream os = new FileOutputStream(file);
                os.write(data22[1].getBytes());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乘风御浪云帆之上

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值