当前位置: 首页 > news >正文

C++学习之LINUX网络编程-套接字通信基础

目录

1.知识点概述

2.两种网络模型

3.服务器开发是什么

4.IP分类

5.IP协议

6.查看IP地址和测试主机之间是否能够通信

7.端口

8.IP和端口的使用以及域名作用

9.OSI 七层和四层模型

10.网络协议是什么

11.数据在网络环境中发送和接受过程

12.套接字通信涉及知识点

13.字节序

14.大小端存储举例

15.IP和端口大小端转换函数

16.字符串类型的主机字节序IP转网络字节序

17.网络字节序转字符串类型的主机字节序IP地址


1.知识点概述

- 网络设计模式

  - B/S
    - broswer - 浏览器 -> 客户端
      - html
      - css
      - js
    - server -> 服务器
    - 优势:
      - 跨平台
      - 开发成本低
    - 缺点:
      - 网络通信的时候, 必须要使用http协议
        - http / https -> 应用层协议
      - 不能在磁盘缓存或者从磁盘加载大量数据

2.两种网络模型

  - C/S
    - client -> 桌面应用程序  -> Qt
      - QQ
      - 迅雷
      - 微信
    - server -> 服务器
    - 特点:
      - 优点:
        - 使用的协议可以随意选择
        - 可以在本地缓存或者加载大量数据
      - 缺点:
        - 研发成本高
          - 在不同的平台开发不同的客户端版本

3.服务器开发是什么

服务器:

  - 硬件:  配置比较高的主机
    - 买阿里云, 百度云服务器
  - 软件:  
    - 有一台主机, 主机上运行了一个进程, 这个进程可以处理网络协议, 称这台主机是一个服务器
      - nginx
  - 服务器开发:
    - 工作不是去开发web服务器
    - 我们做的工作:
      - 在一台装有服务器的主机上开发应用程序
        - 应用程序:
          - 斗地主
          - 文件服务器

4.IP分类

IP和端口

  - IP地址分类

    - 公网IP
    - 可以访问Interface, 公网IP是唯一的
    - 局域网IP
      - 小的网络, 比如一个路由器对应的家里的网段
        - 192.168.1.xxxx
      - 在这个小的网络中IP是唯一的
      - 在这个网络中的主机可以互相通信
      - 如果局域网和外网连接, 那么通过局域网IP也可以连接外网

5.IP协议

 - IP协议
    - IPV4 - `“Internet Protocol Version 4`
      - 现在应用很广泛的协议
    - IP地址的点分十进制字符串
        - `192.168.1.100`
      - 本质是一个整形数, 4字节, 32位
        - 通过3个点分成4分, 每份一个字节
          - 字节的取值范围 0-255
          - 最大的IP地址: `255.255.255.255`
      - 可用的IP地址:
        - 2的32次方 -1
      - 现在IPv4的IP地址非常不够用, 在2011年就分配完了
    - IPV6  ->  `“Internet Protocol Version 6`
      - 现在应用不是很广泛, 将来主推的一种网络协议
      - 本质也是整形数, 16字节, 128bit
      - IP地址表示:
        - 分为8份, 每份2字节, 使用16进制的数字表示
        - `fe80::020c:29ff:fe40:473a`
      - ip地址的个数:
        - 2的128次方 -1


    

6.查看IP地址和测试主机之间是否能够通信

 ```shell
    # 查看IP地址
    # linux
    $ ifconfig
    # windows
    $ ipconfig
    # 测试两台主机之间是否可用通信
    ping ip地址
    $ ping 192.168.1.6
    PING 192.168.1.6 (192.168.1.6) 56(84) bytes of data.
    64 bytes from 192.168.1.6: icmp_seq=1 ttl=128 time=1.88 ms
    64 bytes from 192.168.1.6: icmp_seq=2 ttl=128 time=0.678 ms

7.端口

- 端口

    ```shell
    # 1. 端口的本质?
    无符号短整型数 -> unsigned short
    # 2. 端口取值范围?
    1. 可以有多少个端口:  2的16次方
    2. 取值范围: 0 - 65535
    # 3. 端口的作用?
    定位某台主机上运行的某个进程
    #      在电脑上运行了微信和QQ, 小明给我的的微信发消息, 电脑上的微信就收到了消息, 为什么?
    - 运行的qq和微信在启动的时候都绑定的了不同的端口
    - 小明给我的微信发送数据(点对点模型)
        - 需要知道我的IP地址 -> 定位我电脑
        - 如果定位电脑中的某一个进程呢? ---> 通过端口

8.IP和端口的使用以及域名作用

 - ip和端口的使用

    ```shell
    # 通过IP定位网络环境中的主机, 通过端口定位主机上的进程
    # 比如通过浏览器进行网络服务器访问
  # 服务器有IP地址/域名, 服务器需要绑定端口
    # b/s  -> 协议http -> 使用的端口是80, https协议端口-> 443
    # 如果服务器使用的就是协议的默认端口, 访问的时候端口是可以省略不写的
    http://www.baidu.com:80
    https://www.baidu.com:443
    
    http://192.168.1.100:9999
    

9.OSI 七层和四层模型

OSI/ISO 网络分层模型

  > OSI(Open System Interconnect),即开放式系统互联。 一般都叫OSI参考模型,是ISO(国际标准化组织组织)在1985年研究的网络互联模型。

  ```shell
  上层 
   |        
   |     七层模型               四层模型        
   |        
   |        应用层
   |        表示层                   应用层      http/ftp/ssh/ftps
   |        会话层
   --------------------------------------------------
   |        传输层                   传输层        tcp / udp
   --------------------------------------------------
   |        网络层                   网络层       ip -> ipv4/ipv6
   --------------------------------------------------
   |        数据链路层             网络接口层   以太网帧协议
  底层     物理层

10.网络协议是什么

 > - 物理层负责最后将信息编码成电流脉冲或其它信号用于网上传输
  > - 数据链路层:  
  >   - 数据链路层通过物理网络链路供数据传输。
  >   - 规定了0和1的分包形式,确定了网络数据包的形式;
  > - 网络层
  >   - 网络层负责在源和终点之间建立连接;
  >   - 此处需要确定计算机的位置,怎么确定?IPv4,IPv6
  > - 传输层
  >   - 传输层向高层提供可靠的端到端的网络数据流服务。
  >   - 每一个应用程序都会在网卡注册一个端口号,该层就是端口与端口的通信
  > - 会话层
  >   - 会话层建立、管理和终止表示层与实体之间的通信会话;
  >   - 建立一个连接(自动的手机信息、自动的网络寻址);
  > - 表示层:
  >   - 对应用层数据编码和转化, 确保以一个系统应用层发送的信息 可以被另一个系统应用层识别;
  >   - 可以理解为:解决不同系统之间的通信,eg:手机上的QQ和Windows上的QQ可以通信;
  > - 应用层:
>   - 规定数据的传输协议

11.数据在网络环境中发送和接受过程

> - 网络协议:
>
>   计算机双方共同遵守的一组约定, 通过这个约定就可以完成连接的建立, 相互识别, 按照某种特定的数据格式进行网络通信
>
>   - 发送端: 按照约定的数据格式组织数据
>   - 接收端: 按照约定的数据格式解析数据



- 常见协议

  - TCP协议 -> 传输层协议

    ![](assets/tcp.png)

  - UDP协议 -> 传输层协议

    ![](assets/udp.png)

  - IP协议 -> 网络层协议

    ![](assets/ip.png)

  - 以太网帧协议

    ![](assets/mac.png)

12.套接字通信涉及知识点

- 数据的封装

  ![1558001080021](assets/1558001080021.png)
  
  ```shell
  # 两台主机A,B
  1. A给B发送字符串 "hello, world" , 字符串不会以这种形态发送到Internet, 需要在发送之前需要封装
  2. 封装是由操作系统或者调用的API自动完成的, 程序猿无需关心
  3. 如果程序猿需要封装数据, 一般是在应用层做处理, 应用层数据可封装也可以不封装
  
  数据 "hello, world"  在应用层 进行发送
      1. 在应用层对这个字符串封装(可选, 程序猿做的)
      2. 数据往下走-> 传输层 -> 根据协议格式打包数据 , tcp
      3. 数据往下走-> 网络层 -> 根据协议格式打包数据 , ip
      4. 数据往下走-> 网络接口层 -> 根据协议格式打包数据, 以太网帧协议
      5. 数据通过网口发送给B
      
  B接收数据, 拆包
      1. 网络接口层 -> 根据协议格式拆包, 以太网帧协议拆开
      2. 得到了网络层的包 -> 拆包
      3. 传输层的包 -> 拆包
      4. 应用层的包
      5. 应用层如果使用协议封装了数据继续拆包, 如果没有封装得到了 "hello, world" 
      
  程序猿只需要处理应用层, 应用层以下, 不需要我们处理

13.字节序

 3. socket编程

> Socket套接字由远景研究规划局(Advanced Research Projects Agency, ARPA)资助加里福尼亚大学伯克利分校的一个研究组研发。其目的是将TCP/IP协议相关软件移植到UNIX类系统中。设计者开发了一个接口,以便应用程序能简单地调用该接口通信。这个接口不断完善,最终形成了Socket套接字。Linux系统采用了Socket套接字,因此,Socket接口就被广泛使用,到现在已经成为事实上的标准。与套接字相关的函数被包含在头文件sys/socket.h中。

![](assets/插座.png)

```c
套接字通信就是网络通信, 跟语言没有关系, 因为通信是基于协议的, 所有的编程都需要基于这些协议对数据进行处理
// 1. 套接字是什么?
1. 套接字是一套网络通信的接口, 这个接口中封装了传输层协议( tcp / udp )
2. 接口就是 api, 也就是一套函数
    
// 2. socket(插座), 套接字通信的组成部分?
1. 服务器端, 插座的作用
    - 被动接受连接的角色, 不会主动发起连接的
    - 绑定固定IP和端口, 这样客户端才能进行连接
    
2. 客户端
    - 主动发起连接的角色, 连接服务器
    - 连接服务器需要地址:
        - IP + 端口
            
// 3. 怎么用? -> 所有编程语言的通信流程都是固定的
- 服务器有通信流程
- 客户端有通信流程

14.大小端存储举例

```c
// 支持ipv4 和ipv6 格式的ip地址
#include <arpa/inet.h>    // 套接字通信只需要包含这个头文件就可以了
// p-> 主机字节序的 字符串类型的IP地址
// 将主机字节序的字符串类型的IP -> 大端的整形数
int inet_pton(int af, const char *src, void *dst); 
参数:
    - af: 地址族协议
        - AF_INET: 使用ipv4的网络协议
        - AF_INET6: 使用ipv6的网络协议
    - src: 主机字节序的字符串类型的IP地址, 要被转换的数据
    - dst: 传出参数, 存储了转换之后的大端的IP地址
返回值:
    成功: 0
    失败: -1
        
// 大端的整形数 --> 主机字节序的字符串类型的IP
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
参数:
    - af: 地址族协议
        - AF_INET: 使用ipv4的网络协议
        - AF_INET6: 使用ipv6的网络协议
    - src: 传入参数, 要被转换的数据, 指针指向的内存中存储了大端的IP地址(整形数)
    - dst: 传出参数, 指针指向的内存中存储了主机字节序 字符串类型的IP地址
    - size: 参数dst指向的内存的大小
返回值:
    失败: NULL
    成功: 指针指向函数第三个参数 dst 指向的内存
```

15.IP和端口大小端转换函数

```c
// 在写数据的时候不好用
struct sockaddr {
    sa_family_t sa_family;    // 地址族协议, ipv4, ipv6
    char        sa_data[14];    // 端口(2字节) + IP地址(4字节) + 填充(8字节)
}

typedef unsigned short  uint16_t;
typedef unsigned int    uint32_t;
typedef uint16_t in_port_t;
typedef uint32_t in_addr_t;
typedef unsigned short int sa_family_t;
#define __SOCKADDR_COMMON_SIZE (sizeof (unsigned short int))

struct in_addr
{
    in_addr_t s_addr;
};  

// sizeof(struct sockaddr) == sizeof(struct sockaddr_in)
struct sockaddr_in
{
    sa_family_t sin_family;        /* 地址族协议: AF_INET */
    in_port_t sin_port;         /* 端口, 2字节-> 大端  */
    struct in_addr sin_addr;    /* IP地址, 4字节 -> 大端  */
    /* 填充 8字节 */
    unsigned char sin_zero[sizeof (struct sockaddr) - sizeof(sin_family) -
               sizeof (in_port_t) - sizeof (struct in_addr)];
};  
```

## 3.4 套接字函数

16.字符串类型的主机字节序IP转网络字节序

#include <arpa/inet.h>
// 创建一个套接字(文件描述符), 用于通信或者监听都是可以的
int socket(int domain, int type, int protocol);
参数:
    - domain:
        - AF_INET: 使用ipv4的网络协议
        - AF_INET6: 使用ipv6的网络协议
    - type: 
        - SOCK_STREAM: 使用流式传输协议
        - SOCK_DGRAM: 使用报式传输协议
    - protocol: 默认写0
        - 流式协议默认使用tcp
        - 报式协议默认使用udp
返回值:
    成功: 返回一个文件描述符
    失败: -1
  
// 将监听的套接字和本地IP和端口进行关联
struct sockaddr_in addr;
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数:
    - sockfd: 用于监听的套接字, 通过调用socket函数创建的
    - add: 将本地IP和端口信息初始化给该结构体, ip和端口使用大端
        - 绑定的时候服务器端一般ip地址使用 INADDR_ANY == 0
            - 0 == 0.0.0.0
            - 表示绑定本机的所有的ip地址
            - 一台主机有多个网卡 -> 多个IP地址
                - 先识别实际IP让后绑定
    - addrlen: 记录第二个参数指针指向的内存大小, sizeof(struct sockaddr)
返回值:
    成功: 0
    失败: -1
        

17.网络字节序转字符串类型的主机字节序IP地址

// 发送数据
// 写缓冲区中数据写满了, 写阻塞
ssize_t write(int fd, const void *buf, size_t len);
ssize_t send(int fd, const void *buf, size_t len, int flags);
参数: 
    - fd: 通信的文件描述符
        - accept的返回值(服务器端)
        - 通过socket函数创建得到的, 通过connect初始化连接(客户端)
    - buf: 要发送的数据, 数据进入到了通信的文件描述符的写缓冲区
        - 写缓冲区数据是由内核维护管理的, 这里边有数据, 内核就会进行发送
    - len: 发送的数据的实际长度, strlen();
    - flag: 使用默认属性, 指定为0即可
返回值:
    >0: 发送的实际字节数
    =0: 没有发送任何数据
    -1: 发送失败, 异常

// 客户端用来连接服务器
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数:
    - sockfd: 通信的文件描述符, 通过socket()得到
    - addr: 连接的服务器的IP和端口信息, 初始化该变量中, 使用网络字节序(ip+端口)
    - addrlen: 参数addr指向的内存大小
返回值:
    成功: 0
    失败: -1
```


http://www.mrgr.cn/news/97194.html

相关文章:

  • 【51单片机】3-3【定时器/计数器/中断】超声波测距模块测距
  • Spring Cloud 框架为什么能处理高并发
  • 25.4 GLM-4+RAG智能标注实战:标注成本暴降60%,检索准确率飙升40%!
  • 【蓝桥杯】十五届省赛B组c++
  • 3-Visual Studio 2022打包NET开发项目为安装包
  • Android使用OpenGL和MediaCodec录制
  • 走进未来的交互世界:下一代HMI设计趋势解析
  • 力扣刷题-热题100题-第31题(c++、python)
  • mysql and redis简化版
  • 虚幻5学习笔记,疑点
  • 八、重学C++—动态多态(运行期)
  • MySQL-SQL-DDL语句、表结构创建语句语法、表约束、表数据类型,表结构-查询SQL、修改SQL、删除SQL
  • 【Android】界面布局-线性布局LinearLayout-例子
  • Linux常用基础命令应用
  • 理解OSPF 特殊区域Stub和各类LSA特点
  • Android学习总结之算法篇四(排序)
  • Vite环境下解决跨域问题
  • 黑马点评redis改 part 1
  • 源支付开源全套,源支付V7开源全套,源支付V1.8.9,源支付开源版
  • Docker 命令简写配置