计算机网络与网络编程

1.软件结构

1.1 C/S结构

全称为Client/Server结构,是指客户端和服务器结构。常见程序有QQ、迅雷等软件。

1.2 B/S结构

全称为Browser/Server结构,是指浏览器和服务器结构。常见浏览器有谷歌、火狐等。


两种架构各有优势,但是无论哪种架构,都离不开网络的支持。网络编程,就是在一定的协议下,实现两台计算机的通信的程序。

2.网络通信协议

  • 网络通信协议:通过计算机网络可以使多台计算机实现连接,位于同一个网络中的计算机在进行连接和通信时需要遵守一定的规则,这就好比在道路中行驶的汽车一定要遵守交通规则一样。在计算机网络中,这些连接和通信的规则被称为网络通信协议,它对数据的传输格式、传输速率、传输步骤等做了统一规定,通信双方必须同时遵守才能完成数据交换。
  • TCP/IP协议: 传输控制协议/因特网互联协议( Transmission Control Protocol/Internet Protocol),是Internet最基本、最广泛的协议。它定义了计算机如何连入因特网,以及数据如何在它们之间传输的标准。它的内部包含一系列的用于处理数据通信的协议,并采用了4层的分层模型,每一层都呼叫它的下一层所提供的协议来完成自己的需求。

    上图中,TCP/IP协议中的四层分别是应用层、传输层、网络层和链路层,每层分别负责不同的通信功能。
    链路层:链路层是用于定义物理传输通道,通常是对某些网络连接设备的驱动协议,例如针对光纤、网线提供的驱动。
    网络层:网络层是整个TCP/IP协议的核心,它主要用于将传输的数据进行分组,将分组数据发送到目标计算机或者网络。
    运输层:主要使网络程序进行通信,在进行网络通信时,可以采用TCP协议,也可以采用UDP协议。
    应用层:主要负责应用程序的协议,例如HTTP协议、FTP协议等。
  • OSI七层模型:
    应用层 负责对软件提供接口时程序能使用网络服务
    表示层 应用程序和网络之间的翻译官
    会话层 负责在网络中的两节点之间建立和维持通信
    传输层 建立端到端之间的连接,数据的分段和重组
    网络层 将网络地址翻译成对应的mac地址,指导数据包的转发
    数据链路层 将网络层接收到的数据包封装为特定的数据帧,使其在不可靠的物理链路上进行可靠的数据传递
    物理层 建立、维护、断开物理连接。(由底层网络定义协议)

3.UDP与TCP协议

3.1 UDP协议

​ UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。由于使用UDP协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输例如视频会议都使用UDP协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。但是在使用UDP协议传送数据时,由于UDP的面向无连接性,不能保证数据的完整性,因此在传输重要数据时不建议使用UDP协议。UDP的交换过程如下图所示。

3.2 TCP协议

​ TCP协议是面向连接的通信协议,即在传输数据前先在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。每次连接的创建都需要经过“三次握手”。

  • 第一次握手,客户端向服务器端发出连接请求,等待服务器确认
  • 第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求
  • 第三次握手,客户端再次向服务器端发送确认信息,确认连接。整个交互过程如下图所示

    由于TCP协议的面向连接特性,它可以保证传输数据的安全性,所以是一个被广泛采用的协议,例如在下载文件时,如果数据接收不完整,将会导致文件数据丢失而不能被打开,因此,下载文件时必须采用TCP协议。

4.相关面试题

  1. TCP断开连接的四次挥手
    第一次挥手:客户端发送一个FIN包(seq=x),进入FIN_WAIT(结束等待)状态
    第二次挥手:服务器收到FIN包,发回一个ACK包(ack=x+1),进入CLOSE_WAIT(关闭等待)状态
    第三次挥手:服务器关闭客户端的连接,并发送一个FIN包(seq=y),进入LAST_ACK(最后确认)状态
    第四次挥手:客户端发回ACK(ack=y+1)包确认,发送完毕后,连接断开
  2. 需要三次握手的原因
    为了防止失效的连接请求报文突然又传送到服务器产生错误。假如不三次握手,客户端发送连接确认给服务端就立即建立连接,如果有个连接请求阻塞了很久才到服务端,而此时本来已经关闭了连接的又重新建立了连接,然而等了很久都没有数据发送,这就会白白浪费资源
  3. Http协议与Https协议
  • Http协议即超文本传输协议,是一种基于TCP的应用层协议,还是一种无状态协议。用于服务器和客户端的数据传输,客户端和服务器使用URL来建立连接和传输数据。客户端发送Http请求给服务器,服务器根据请求返回Html、文本或多媒体文件给客户端
  • Https协议是一种安全的Http协议。Http协议是一种明文传输的协议,存在被窃听,信息篡改等安全隐患,在Http协议的基础上加入了SSL或TLS协议,实现了数据的加密传输。因为加上了加密的协议,所以Https的响应速度会比Http慢很多。并不是所有情况下都需要使用Https协议,对于隐私的,重要的信息最好用Https协议,不重要的或者可以公开的信息就没有必要用Https协议
  1. Http请求报文和响应报文
  • 请求报文包括请求行,请求头,空行和请求体(GET请求没有请求体)
  • 响应报文包括状态行,响应头,空行和响应体
  1. Http请求常见状态码
  • 200 OK,请求成功
  • 404 Not Found,对应的URL上不存在资源
  • 405 Method Not Allowed,请求不被允许,即请求方式错误
  • 500 Internal Server Error,服务器内部错误,发现严重BUG,要及时修复
  1. GET请求与POST请求的区别
  • GET请求一般用于获取服务器上的资源,是幂等的。POST请求一般用于对服务器上资源进行更新非幂等的(幂等即每次请求返回结果一样)
  • GET请求没有请求体,请求参数跟是在URL后面的,所以使用GET请求时请求参数用户是可以直接看到的。POST请求有请求体,请求参数放在请求体,对用户是不可见的。相对来说POST请求比GET请求更安全
  • GET请求的参数长度有限制,这是因为URL长度有限导致的。POST请求的参数长度可以认为是无限制
  1. TCP 和 UDP的区别
  • TCP是一种面向连接的可靠传输协议,UDP是面向无连接的不可靠传输协议
  • TCP支持报文传输,还支持字节流的传输。而UDP协议只支持传输报文
  • TCP数据报格式比较复杂,传输过程数据不容易丢失和出错,而UDP数据报格式较为简单,容易丢失
  • TCP传输在接收端会进行重排,所以是有序的,UDP则不保证有序
  • TCP速度慢,UDP速度快
  • TCP有流量控制和拥塞控制,而UDP没有
  1. 应用层协议有哪些
  • DNS协议,域名解析系统。基于TCP和UDP的协议,通过DNS可以将域名转换成IP地址
  • SMTP协议,电子邮件协议。基于TCP的协议,通过SMTP协议可以发送电子邮件,SMTP通信的过程建立连接、邮件传送、连接释放
  • Telnet协议,远程终端协议。基于TCP的协议,通过Telnet协议可以对远程的终端进行控制
  • Http协议,超文本传输协议。基于TCP的协议,通过Http协议实现客户端和服务端的数据传输
  • FTP协议,文件传输协议。基于TCP的协议,通过FTP协议达到相互传输文件的效果
  1. OSI参考模型与TCP/IP参考模型
    (1) OSI参考模型由7层组成:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层
    (2) TCP/IP参考模型由4层组成:主机-网络层、网际层、传输层、应用层
    (3) 对应关系中,OSI参考模型的物理层、数据链路层对应TCP/IP的主机-网络层,网络层对应网际层,传输层对应传输层,会话层、表示层、应用层对应应用层
  2. cookie 和 session的区别
    (1) cookie由于把信息保存在客户端中。session把信息保存在服务器中
    (2) cookie性能更高一点,速度较快,用户的信息存在各自的浏览器中,可以分担服务器的一部分存储工作。session速度较慢,所有用户的信息都存在服务器中,在高并发时必然影响服务器性能
    (3) cookie有限制大小,在4K以内。session没有限制
    (4) cookie对用户是透明的,安全性低,不重要的或者可以公开的信息保存在cookie。session对用户是不可见的,安全性高,重要信息应该保存在session
  3. forward 和 redirect的区别
    (1) forward为转发,进行forward操作后,请求URL不发生变化,并且会把请求的数据携带到下一个请求中。redirect是重定向,进行redirect操作后,请求URL是发生变化的
    (2) forward是服务器内部请求转发,不可以请求到其它站点,redirect是服务器通知客户端重新请求,可以请求到其它站点
    (3) forward速度快,redirect速度慢
  4. DNS劫持和DNS污染
    (1) DNS劫持:指用户访问一个域名时,DNS服务器故意将此地址指向一个错误的IP地址的行为。比如进入一个网站显示的却是另外一个网站的内容
    (2) DNS污染:指用户访问一个域名时,国内的服务器(非DNS)监控到用户访问的已经被标记地址时,服务器伪装成DNS服务器向用户发回错误的地址的行为。比如国内不能访问Google、YouTube等

5.TCP通信程序

5.1 简单的TCP网络程序

TCP通信分析图解

  1. 【服务端】启动,创建ServerSocket对象,等待连接。
  2. 【客户端】启动,创建Socket对象,请求连接。
  3. 【服务端】接收连接,调用accept方法,并返回一个Socket对象。
  4. 【客户端】Socket对象,获取OutputStream,向服务端写出数据。
  5. 【服务端】Scoket对象,获取InputStream,读取客户端发送的数据。

    到此,客户端向服务端发送数据成功。

    自此,服务端向客户端回写数据。

  6. 【服务端】Socket对象,获取OutputStream,向客户端回写数据。
  7. 【客户端】Scoket对象,获取InputStream,解析回写数据。
  8. 【客户端】释放资源,断开连接。
    服务端实现:
    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
    public class ServerTCP {
    public static void main(String[] args) throws IOException {
    System.out.println("服务端启动 , 等待连接 .... ");
    // 1.创建 ServerSocket对象,绑定端口,开始等待连接
    ServerSocket ss = new ServerSocket(6666);
    // 2.接收连接 accept 方法, 返回 socket 对象.
    Socket server = ss.accept();
    // 3.通过socket 获取输入流
    InputStream is = server.getInputStream();
    // 4.一次性读取数据
    // 4.1 创建字节数组
    byte[] b = new byte[1024];
    // 4.2 据读取到字节数组中.
    int len = is.read(b);
    // 4.3 解析数组,打印字符串信息
    String msg = new String(b, 0, len);
    System.out.println(msg);
    // =================回写数据=======================
    // 5. 通过 socket 获取输出流
    OutputStream out = server.getOutputStream();
    // 6. 回写数据
    out.write("我很好,谢谢你".getBytes());
    // 7.关闭资源.
    out.close();
    is.close();
    server.close();
    }
    }
    客户端实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class ClientTCP {
public static void main(String[] args) throws Exception {
System.out.println("客户端 发送数据");
// 1.创建 Socket ( ip , port ) , 确定连接到哪里.
Socket client = new Socket("localhost", 6666);
// 2.通过Scoket,获取输出流对象
OutputStream os = client.getOutputStream();
// 3.写出数据.
os.write("你好么? tcp ,我来了".getBytes());
// ==============解析回写=========================
// 4. 通过Scoket,获取 输入流对象
InputStream in = client.getInputStream();
// 5. 读取数据数据
byte[] b = new byte[100];
int len = in.read(b);
System.out.println(new String(b, 0, len));
// 6. 关闭资源 .
in.close();
os.close();
client.close();
}
}

5.2 文件上传

文件上传分析图解

  1. 【客户端】输入流,从硬盘读取文件数据到程序中。
  2. 【客户端】输出流,写出文件数据到服务端。
  3. 【服务端】输入流,读取文件数据到服务端程序。
  4. 【服务端】输出流,写出文件数据到服务器硬盘中。
  5. 【服务端】获取输出流,回写数据。
  6. 【客户端】获取输入流,解析回写数据。

    服务端实现:
    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
    public class FileUpload_Server {
    public static void main(String[] args) throws IOException {
    System.out.println("服务器 启动..... ");
    // 1. 创建服务端ServerSocket
    ServerSocket serverSocket = new ServerSocket(6666);
    // 2. 循环接收,建立连接
    while (true) {
    Socket accept = serverSocket.accept();
    /*
    3. socket对象交给子线程处理,进行读写操作
    Runnable接口中,只有一个run方法,使用lambda表达式简化格式
    */
    new Thread(() -> {
    try (
    //3.1 获取输入流对象
    BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());
    //3.2 创建输出流对象, 保存到本地 .
    FileOutputStream fis = new FileOutputStream(System.currentTimeMillis() + ".jpg");
    BufferedOutputStream bos = new BufferedOutputStream(fis);
    ) {
    // 3.3 读写数据
    byte[] b = new byte[1024 * 8];
    int len;
    while ((len = bis.read(b)) != -1) {
    bos.write(b, 0, len);
    }

    // 4.=======信息回写===========================
    System.out.println("back ........");
    OutputStream out = accept.getOutputStream();
    out.write("上传成功".getBytes());
    out.close();
    //================================

    //5. 关闭 资源
    bos.close();
    bis.close();
    accept.close();
    System.out.println("文件上传已保存");
    } catch (IOException e) {
    e.printStackTrace();
    }
    }).start();
    }
    }
    }
    客户端实现:
    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
    public class FileUpload_Client {
    public static void main(String[] args) throws IOException {
    // 1.创建流对象
    // 1.1 创建输入流,读取本地文件
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream("test.jpg"));
    // 1.2 创建输出流,写到服务端
    Socket socket = new Socket("localhost", 6666);
    BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());

    //2.写出数据.
    byte[] b = new byte[1024 * 8 ];
    int len ;
    while (( len = bis.read(b))!=-1) {
    bos.write(b, 0, len);
    }
    // 关闭输出流,通知服务端,写出数据完毕
    socket.shutdownOutput();
    System.out.println("文件发送完毕");
    // 3. =====解析回写============
    InputStream in = socket.getInputStream();
    byte[] back = new byte[20];
    in.read(back);
    System.out.println(new String(back));
    in.close();
    // ============================

    // 4.释放资源
    socket.close();
    bis.close();
    }
    }
请作者喝瓶肥宅快乐水