0%

网络编程

网络编程基础

计算机网络

  • 多台计算机通过通讯线路相连接

互联网

  • 将所有计算机网络相连接

  • 协议

    • TCP
    • IP

IP地址

  • 标识一个网络接口

  • 一台接入互联网的计算机至少有一个IP地址

    我感觉应该是一块无线网卡对应一个ip地址

  • 分类

    • 按格式

      • IPV4

        • 32位整数
        • 耗尽
      • IPV6

    • 按范围

      • 公网
      • 内网(局域网)

网络号

  • 获得

    • ip地址经过子网掩码过滤
  • 用途

    • 网络号相同

      • 设备在同一个网络下,可以直接通信
    • 网络号不同

      • 设备不在一个网络下,要依靠路由器或交换机通信

网络设备

  • 网关

    • 路由器
    • 交换机

路由

  • 通过网关把一个网络的数据包发送到另一个网络

域名

  • 为什么存在?

    • 因为IP地址太难记

      也就是说 域名就是给ip地址起个小名儿 叫起来方便

  • 特殊的localhost

    • 因为特殊所以特殊

      我看了C盘windows下的那个hosts文件,就像是字典一样,一个ip地址对应一个域名,我怀疑域名解析就是靠这个实现的。

      • 127.0.0.1

网络模型

  • 分层

    • 原因

      • 因为复杂所以分层
    • 目的

      • 简化网络操作
    • 有哪些层呢

      • 应用层

        • 提供应用程序之间的通信
      • 传输层

        • 提供端到端的传输
      • IP层

        • 根据目标地址选择路由传输数据
      • 网络接口层

        • 处理数据然后通过物理设备(网线\wifi)传输

协议

  • 作用

    • 交易之前总得商量好吧
  • 常用协议

    • IP协议

      • 负责发数据包

        好像是瞎jb‘发的 据说不保证顺序 正确与否
        也不知道是不是真的

    • TCP协议

      • 负责控制数据包传输

        负责的协议,通过一些手段(目前我还听不懂的名词)保证可靠、正确、稳定。

        • 建立连接
        • 传输数据
        • 断开连接
    • UDP

      • VS TCP

        • UDP完任务型选手

          我只管传输数据,有没有人接受我不care

        • 无连接

        • 速度更快

        • 协议更简单

        • 质量更垃圾

        • 数据必丢失

      • 应用

        • 能容忍数据丢失的场合

          据说音视频通话比较常用,我想也是,能听来或者看来个百分之八九十就可了。

TCP编程

socket

据说socket、tcp和部分ip的功能是由操作系统实现并提供的,不同的语言只是对操作系统提供的接口进行了一些包装

  • 啥是socket

    • application通过socket在网络间传输数据
    • socket通过TCP/IP协议在网络间传输数据
  • 为啥需要socket

    • ip地址是网卡的标识

      说的粗糙一点就是 设备的标识

    • ip地址过于粗糙

    • socket精确到application

  • socket长啥样啊

    • ip地址再加点儿料(端口)
  • 端口

    • 为啥需要端口啊

      ip地址标识网络接口,if我的电脑有一个网卡,这个网卡有一个ip地址,我的电脑上运行了好多需要联网的应用,比如qq、战网、steam,还有很多其他应用。我的网卡对于从远方发过来的包照单全收,但这些包都是名花有主的,因为物质资料还没有到极大丰富的地步,所以不能实行共产主义平均分配或者每人来一份,我们得按需分配,按闹分配,比如qq你只能领取属于自己的包,那怎么实现这样的需求呢?
      咱这样,你们每个应用,给自己整一个端口,比如战网,你的port是988,那我网卡以后就通过这个端口跟你keep touch,其他应用都要有自己的端口,俺网卡按照包的标识,按照咱约定好的端口,按需分配,这样就解决问题了。

      • 因为socket
    • 特权端口

      比如我的应用是用一个普通user打开的,那这个应用就不能使用1024以下的端口

      • 1024以下需要管理员权限
  • socket编程

    • 服务器端

      • 服务客户端的端

      • 服务端会监听某个端口

    • 从端口获得数据包然后服务客户端(我猜的

      • 代码

        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
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        package Laboratory;

        import javax.xml.crypto.Data;
        import java.io.*;
        import java.net.*;
        import java.nio.charset.StandardCharsets;

        public class Experiment {
        public static void main(String[] args) throws IOException {
        //服务器端,可能会有很多客户端请求与我共舞
        //监听指定的端口,可以指定ip地址,ip地址标识网络接口,如果不指定ip地址,表明监听计算机上的所有网络接口
        ServerSocket serverSocket = new ServerSocket(6666);
        System.out.println("server is running");
        //处理和客户端之间的连接
        while (true) {
        //ServerSocket的accept方法,如果有客户端请求连接,我就整个socket对象给他,如果没有人请求连接,这个方法就会block
        Socket socket = serverSocket.accept();
        System.out.println("Connected from " + socket.getRemoteSocketAddress());
        Thread thread = new Handler(socket);
        thread.start();
        }
        }
        }

        class Handler extends Thread {
        Socket socket;

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

        @Override
        public void run() {
        try (InputStream inputStream = this.socket.getInputStream()) {
        try (OutputStream outputStream = this.socket.getOutputStream()) {
        handle(inputStream, outputStream);
        }
        } catch (Exception e) {
        try {
        this.socket.close();
        } catch (IOException ioe) {
        }
        System.out.println("Client disconnected");
        }
        }

        private void handle(InputStream inputStream, OutputStream outputStream) throws IOException {
        var writer = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8));
        var reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
        writer.write("Fku\n");
        writer.flush();
        while (true) {
        String s = reader.readLine();
        if (s.equals("bye")) {
        writer.write("bye too");
        writer.flush();
        break;
        }
        writer.write("fku 3000 times " + s);
        writer.flush();
        }
        }

        }
      1
      2
      	    

      • 客户端

        • 主动连接服务器的ip和指定端口

        • 代码

          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
          package Laboratory;

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

          public class Experiment {
          public static void main(String[] args) throws IOException {
          //客户端的TCP程序
          //连接指定的服务器和端口,如果连接成功,会返回一个socket实例,用于日后的通信
          Socket socket = new Socket("localhost", 6666);
          try (InputStream inputStream = socket.getInputStream()) {
          try (OutputStream outputStream = socket.getOutputStream()) {
          handle(inputStream, outputStream);
          }
          }
          socket.close();
          System.out.println("Disconnected");
          }

          private static void handle(InputStream inputStream, OutputStream outputStream) throws IOException {
          var reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
          var writer = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8));
          Scanner scanner = new Scanner(System.in);
          System.out.println("[server] " + reader.readLine());
          while (true) {
          System.out.print(">>> "); //打印提示
          String s = scanner.nextLine(); //读取一行输入
          writer.write(s);
          writer.newLine();
          writer.flush();
          String str = reader.readLine();
          System.out.println("<<<" + str);
          if (str.equals("bye")) {
          break;
          }
          }
          }

          }
      • 编程使得客户端和服务端进行通信

三次握手

tcp是要和服务器建立连接的啊

  • 屌丝:可以吗?
  • 女神:可以,你想什么时候?
  • 屌丝:今ここだ

UDP编程

UDP VS TCP

  • UDP不需要建立连接

    当然也就不需要断开连接

  • UDP没有流的概念

  • 两者的端口相互独立

    就是 假如有两个应用,一个用UDP,一个用TCP,就算两个用一个端口也没事儿

服务器端

  • 监听指定的端口

  • 代码

    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
    package Laboratory;

    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.SocketException;
    import java.nio.charset.StandardCharsets;

    public class Experiment {
    public static void main(String[] args) throws IOException {
    //服务端的操作:准备一个datagramSocket对象,利用他的receive和send方法接收和发送数据
    //服务器端首先使用如下语句在指定的端口监听UDP数据包:
    DatagramSocket datagramSocket = new DatagramSocket(6666);
    while (true) {
    //准备一个byte[]类型的缓冲包用来接收来自端口的数据
    byte[] buffer = new byte[1024];
    //通过DatagramPacket对象的方法receive接收数据包
    DatagramPacket datagramPacket = new DatagramPacket(buffer, buffer.length);
    datagramSocket.receive(datagramPacket);
    //通过DatagramPacket的getOffset和getLength方法确定接收到的数据在缓冲区的起始位置
    String s = new String(datagramPacket.getData(), datagramPacket.getOffset(), datagramPacket.getLength(), StandardCharsets.UTF_8);
    byte[] data = "ACK".getBytes(StandardCharsets.UTF_8);
    datagramPacket.setData(data);
    datagramSocket.send(datagramPacket);
    }
    }
    }

客户端

  • 操作

    • 向服务器发送UDP包
    • 接收服务器返回的UDP包
  • 代码

    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
    package Laboratory;

    import javax.xml.crypto.Data;
    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetAddress;
    import java.net.SocketException;
    import java.nio.charset.StandardCharsets;

    public class Experiment {
    public static void main(String[] args) throws IOException {
    //客户端
    //客户端创建DatagramSocket的时候不需要指定端口,分配端口这个活儿是OS干的,所以说OS是程序员的好朋友
    DatagramSocket datagramSocket = new DatagramSocket();
    //此处有别于服务器端,服务器端可以循环到天荒地老,但客户端有所不同,需要设置最长等待时间,过期不候
    datagramSocket.setSoTimeout(1000);
    //UDP不需要建立连接,没错,这里的connect并不是真连接,而是想把服务器的ip和端口保存下来,以便之后向服务器发送UDP数据包
    datagramSocket.connect(InetAddress.getByName("localhost"), 6666);
    //现在可以发送数据了
    //先来点数据
    byte[] data = "What's going on?".getBytes();
    //和DatagramPacket绑在一起
    DatagramPacket datagramPacket = new DatagramPacket(data, data.length);
    //通过Socket的方法send将Packet发送到服务器,必须是先发再收,不然服务器不知道客户端的ip和端口号
    datagramSocket.send(datagramPacket);
    //发送之后就可以接受数据了
    //接受数据,和服务端一样
    //先准备一个byte数组用来接受数据
    byte[] buffer = new byte[1024];
    //把buffer和packet绑定起来
    datagramPacket = new DatagramPacket(buffer, buffer.length);
    //通过socket的receive方法接受数据存到预先设定的packet里
    datagramSocket.receive(datagramPacket);
    //转换成String
    String str = new String(datagramPacket.getData(), datagramPacket.getOffset(), datagramPacket.getLength());
    //如果可以,可以选择断开连接
    //既然不存在连接,当然也就不存在断开的对象,确实如此,此处的disconnect只是把socket对象恢复出厂设置,以便于socket可以再利用而已
    datagramSocket.disconnect();
    }
    }

Email

发送

  • 传统的邮件

    • 投递到邮局——邮局2——邮局3——信箱
  • 电子邮件

    • 从用户的邮箱软件发送到服务器——服务器2——服务器3——邮箱
  • 邮箱软件

    • MUA
    • Mail User Agent
  • 邮件服务器

    • MTA

    • MDA

      • 邮件最终的归属
      • 或许是某个服务器的某块硬盘
  • 代码

    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
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
      
    import javax.mail.*;
    import javax.mail.internet.AddressException;
    import javax.mail.internet.InternetAddress;
    import javax.mail.internet.MimeMessage;
    import java.util.Properties;

    public class Mail {
    public static void main(String[] args) throws MessagingException {
    String smtp = "smtp.qq.com";
    String username = "674602921@qq.com";
    String password = "grzbslakcefkbceg";
    Properties properties = new Properties();
    properties.put("mail.smtp.host", smtp);
    properties.put("mail.smtp.port", 465);
    properties.put("mail.smtp.auth", "true");
    properties.put("mail.starttls.enable", "true");
    properties.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
    Session session = Session.getInstance(properties, new Authenticator() {
    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
    return new PasswordAuthentication(username, password);
    }
    });
    session.setDebug(true);
    MimeMessage message = new MimeMessage(session);
    message.setFrom(new InternetAddress("674602921@qq.com"));
    message.setRecipient(Message.RecipientType.TO, new InternetAddress("ljm158675@gmail.com"));
    message.setSubject("Hey", "UTF-8");
    message.setText("Java,please!");
    Transport.send(message);
    }
    }

    public class Mail {
    public static void main(String[] args) throws MessagingException {
    String smtp = "smtp.qq.com";
    String username = "674602921@qq.com";
    String password = "grzbslakcefkbceg";
    Properties properties = new Properties();
    properties.put("mail.smtp.host", smtp);
    properties.put("mail.smtp.port", 465);
    properties.put("mail.smtp.auth", "true");
    properties.put("mail.starttls.enable", "true");
    properties.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
    Session session = Session.getInstance(properties, new Authenticator() {
    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
    return new PasswordAuthentication(username, password);
    }
    });
    session.setDebug(true);
    MimeMessage message = new MimeMessage(session);
    message.setFrom(new InternetAddress("674602921@qq.com"));
    message.setRecipient(Message.RecipientType.TO, new InternetAddress("ljm158675@gmail.com"));
    message.setSubject("Hey", "UTF-8");
    message.setText("Java,please!");
    Transport.send(message);
    }
    }

接收

  • 代码

    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
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
      
    import com.sun.mail.pop3.POP3SSLStore;


    import javax.mail.*;
    import javax.mail.internet.AddressException;
    import javax.mail.internet.InternetAddress;
    import javax.mail.internet.MimeMessage;
    import javax.mail.internet.MimeUtility;
    import java.io.IOException;
    import java.util.Properties;

    public class Mail {
    public static void main(String[] args) throws MessagingException, IOException {
    String host = "pop3.example.com";
    String username = "bob@example.com";
    String password = "********";
    int port = 995;
    Properties properties = new Properties();
    properties.setProperty("mail.store.protocol", "pop3");
    properties.setProperty("mail.pop3.host", host);
    properties.setProperty("mail.pop3.port", String.valueOf(port));
    properties.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
    properties.put("mail.smtp.socketFactory.port", String.valueOf(port));
    URLName urlName = new URLName("pop3", host, port, "", username, password);
    Session session = Session.getInstance(properties, null);
    session.setDebug(true);
    Store store = new POP3SSLStore(session, urlName);
    store.connect();
    // 获取收件箱:
    Folder folder = store.getFolder("INBOX");
    // 以读写方式打开:
    folder.open(Folder.READ_WRITE);
    // 打印邮件总数/新邮件数量/未读数量/已删除数量:
    System.out.println("Total messages: " + folder.getMessageCount());
    System.out.println("New messages: " + folder.getNewMessageCount());
    System.out.println("Unread messages: " + folder.getUnreadMessageCount());
    System.out.println("Deleted messages: " + folder.getDeletedMessageCount());
    // 获取每一封邮件:
    Message[] messages = folder.getMessages();
    for (Message message : messages) {
    // 打印每一封邮件:
    printMessage((MimeMessage) message);
    }
    }

    static void printMessage(MimeMessage msg) throws IOException, MessagingException {
    // 邮件主题:
    System.out.println("Subject: " + MimeUtility.decodeText(msg.getSubject()));
    // 发件人:
    Address[] froms = msg.getFrom();
    InternetAddress address = (InternetAddress) froms[0];
    String personal = address.getPersonal();
    String from = personal == null ? address.getAddress() : (MimeUtility.decodeText(personal) + " <" + address.getAddress() + ">");
    System.out.println("From: " + from);
    // 继续打印收件人:
    }

    }

HTTP编程

建立TCP连接

请求(HTTP,浏览器)

  • HTTP HEADER
  • HTTP BODY

响应(HTTP,服务器)