【linux应用软件编程】进程间的通信方式2【网络通信从入门到UDP编程】

文章目录

网络通信

一、网络通信的基本概念

网络通信:不同主机间的进程间通信。

  1. 主机1和主机2在物理层面互联互通;
  2. 主机1和主机2在软件层面互联互通。

传输一个数据一般会包括下面几个信息:

IP地址:计算机的软件地址,标记主机

MAC地址:计算机的硬件地址,局域网内通信

端口号:识别同一主机上的不同网络进程

二、OSI七层模型(理论模型)

OSI:开放系统互联模型

  1. 应用层;要传输的数据信息,如文件传输,电子邮件等。
  2. 表示层;数据加密,解密操作,压缩,解压缩。
  3. 会话层;建立数据传输通道。
  4. 传输层;传输的方式 UDP TCP 端口号。
  5. 网络层;实现数据路由 路径规划 路由器 ip。
  6. 数据链路层;封装成帧,点对点通信(局域网内通信) 差错检测 交换机 ARP
  7. 物理层;定义物理设备标准,比如网线、光纤等传输介质 传输比特流 bit 0 1

三、TCP/IP模型(生产模型)

3.1 四层模型:

应用层:应用层、表示层、会话层

传输层:传输层

网络层:网络层

网络接口层:数据链路层、物理层

3.2 五层模型:

应用层:应用层、表示层、会话层

传输层:传输层

网络层:网络层

数据链路层:数据链路层

物理层:物理层

3.3 各层常用的一些协议

  • 应用层

    HTTP协议:超文本传输协议(超文本:集链接、图片、文字音视频等一体的文件。)

    HTTPS协议:超文本传输协议(SSL加密)

    FTP:文件传输协议(TCP)

    TFTP:简单传输协议(UDP)

    DNS服务:域名解析服务:把域名转化成IP地址

    MQTT协议:消息队列遥测传输协议(物联网协议)

  • 传输层

    TCP协议:传输控制协议(流式套接字)

    UDP协议:用户数据报协议

  • 网络层

    IPv4:IP协议

    IPv6:IP协议

  • 数据链路层

    MAC<------>IP

    ARP协议:地址解析协议

    RARP:逆地址解析协议

  • 物理层:

3.4 IP协议:

IPv4 :32位

IPv6:128位 (主要解决IPv4地址不够用而产生的)

例如

192.168.1.3 (用户表示形式) 点分十进制

1100 0000 1010 1000 0000 0001 0000 0011 (计算机存储形式) 32bit

IP地址 = 网络位 + 主机位

网络位 :该IP地址位于哪个网段(局域网)内

主机位:这个网段的位数

tips:linux查看ip地址终端指令: ifconfig

ens33 :实际进行数据发送的网卡;

lo:本地回环网卡(自己发数据自己收)

当前主机IP地址:inet 192.168.87.128

子网掩码 :netmask 255.255.255.0

1111 1111.1111 1111.1111 1111.0000 0000

用来区分IP地址的网络位和主机位,搭配IP地址使用。

子网掩码是1的部分对应IP地址的网络位

子网掩码是0的部分对应IP地址的主机位

有的也这样表示:

192.168.0.121/24

24:网络位的位数

这样就不用子网掩码也能区分网络位和主机位。

网段号

IP地址网络位不变,主机位全为0,则为该IP地址的网段号

192.168.1.3

255.255.0.0

192.168.0.0(网段号)

广播号 :

192.168.1.255

IP地址网络位不变,主机位全为1,则为该IP地址的广播号

192.168.1.3

255.255.255.0广播号:

192.168.1.255(向广播号发送信息,所有局域网内IP都能收到此信息)

网关地址:192.168.1.1

3.5 IP地址的划分:

(1)A类地址:

范围:1.0.0.0 - 126.255.255.255

子网掩码:255.0.0.0 126*2^24

用于管理大规模网络

复制代码
    私有IP地址:10.0.0.0 - 10.255.255.255

    127.0.0.0   回环地址

(2)B类地址:

范围:128.0.0.0 - 191.255.255.255

子网掩码:255.255.0.0 2^16

管理大中规模网络

复制代码
    私有IP地址:172.16.0.0 - 172.31.255.255

(3)C类地址:

范围:192.0.0.0 - 223.255.255.255

子网掩码:255.255.255.0 2^8

管理中小规模网络

复制代码
    私有IP地址:192.168.0.0 - 192.168.255.255

(4)D类地址:

224.0.0.0 - 239.255.255.255

组播和广播使用

(5)E类地址:

240.0.0.0 - 255.255.255.254

组播和广播使用

公有IP :电信公司直接分配,并需要付费的IP地址,可以直接访问internet

私有IP:不能直接访问internet的ip地址

四、网络协议栈

IP+PORT:可以找到目标主机上的目标进程

端口号 :16位的数值 0-65535 unsigned short

作用 :唯一的标识一个网络进程

每一个应用进程都有一个端口号;

通讯时用来区分数据包属于哪一个进程。

分类:

  1. 任何TCP/IP实现所提供的服务都用1-1023间的端口号。

    http: 80

    FTP:20/21

    TFPT: 69

    HTTPS: 443

    MQTT:1883

  2. 端口号从1024-49151是被注册的端口号,被IANA指定为特殊服务使用。

  3. 从49152-65535是动态或私有端口号。

五、数据包的封装和解封过程

六、网络配置

桥接模式

  1. 点击右上角虚拟机------>点击设置------>点击网络适配器------>桥接模式------>已连接和启动时连接也勾选上

  2. 编辑------>虚拟网络编辑器------>更改设置------>Vmnet0------>桥接模式------>桥接到windows正在上网的网卡------>应用------>确定

  3. 修改网络配置文件:

    sudo vim /etc/network/interfaces

    dhcp:动态IP分配

  4. 重启网络服务

    sudo /etc/init.d/networking restart

    如果网络重启不行,就重启系统

    sudo reboot

  5. ifconfig

    查看linux系统下的网卡信息

  6. ping www.baidu.con

    检查网络是否为通。

  7. ipconfig

    windows系统下查看IP地址。

七、UDP协议

传输层

UDP协议:User DataGrames Protocol 用户数据报协议

UDP特点 :

  1. 无连接;

  2. 面向数据报;

  3. 尽最大努力交付协议,不安全不可靠(丢包、乱序);

  4. 机制简单,实时性效率高。

使用场景:直播、游戏画面

网络通信模型:

  • B/S:Browser/Server:浏览器/服务器

    1. 通用客户端;
    2. 数据资源基本都保存在服务端;
    3. 只需要开发服务端。
  • C/S:Client/Server:客户端/服务端

    1. 专用客户端;
    2. 客户端和服务端共同保存数据资源;
    3. 客户端和服务端都需要开发。
  • P2P

7.1 UDP通信

客户端

  1. 创建socket套接字 socket()
  2. 发送UDP报文 sendto()
  3. 接受UDP报文 recvfrom()
  4. 关闭套接字 close()

套接字:应用层网络通信的端口,可以理解为一个文件描述符。

服务端

  1. 创建socket套接字 socket()
  2. 绑定服务端的IP和端口号 bind()
  3. 接受UDP报文 recvfrom()
  4. 发送UDP报文 sendto()
  5. 关闭套接字 close()

7.2 UDP通信相关函数接口

7.2.1 socket()
  • 函数原型:

    c 复制代码
    #include <sys/types.h>          /* See NOTES */
    #include <sys/socket.h>
    
    int socket(int domain, int type, int protocol);
  • 功能: 创建通信的套接字。

  • 参数: domain:使用的协议族;

    1. AF_INET:IPv4;
    2. AF_INET6:IPv6;

    type:传输层的协议类型。

    1. SOCK_STREAM:TCP
    2. SOCK_DGRAM:UDP

    protocol:0默认方式

  • 返回值: 成功:文件描述符(套接字);

    失败:-1;

7.2.2 sendto()
  • 函数原型:

    c 复制代码
    #include <sys/types.h>
    #include <sys/socket.h>
    
    ssize_t send(int sockfd, const void *buf, size_t len, int flags);
    
    ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
    const struct sockaddr *dest_addr, socklen_t addrlen);
  • 功能: 发送UDP数据报文。

  • 参数: sockfd:套接字;

    buf:要发送的数据的首地址;

    len:发送的数据的长度;

    flags:0,按默认方式发送;

    dest_addr:服务端的地址信息(IP+PORT);

    addrlen:结构体的大小(地址的长度)。

    c 复制代码
    struct sockaddr_in {
        sa_family_t    sin_family; /* address family: AF_INET */
        in_port_t      sin_port;   /* port in network byte order */
        struct in_addr sin_addr;   /* internet address */
    };
    c 复制代码
    /* Internet address. */
    struct in_addr {
       uint32_t s_addr;     /* address in network byte order */
    };

    网络字节序:大端(高地址存低字节位,低地址存高字节位);
    主机字节序:小端(高地址存高字节位,低地址存低字节位)。
    s_addr需要的是网络地址,因此需要借助后面的辅助函数转化地址信息形式。

  • 返回值: 成功:ssize_t 类型发送的字节数;

    失败:-1;

7.2.3 bind()
  • 函数原型:

    c 复制代码
    #include <sys/types.h>          /* See NOTES */
    #include <sys/socket.h>
    
    int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
  • 功能: 绑定当前的套接字和IP地址及端口号。

  • 参数: sockfd:套接字;

    addr:要绑定的地址信息的指针;

    addrlen:地址信息的长度

  • 返回值: 成功:返回0;

    失败:返回-1.

7.2.4 recvfrom()
  • 函数原型:

    c 复制代码
    #include <sys/types.h>
    #include <sys/socket.h>
    
    ssize_t recv(int sockfd, void *buf, size_t len, int flags);
    
    ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
  • 功能: 接受UDP数据报文。

  • 参数: sockfd:套接字;

    buf:存放接受数据空间的地址;

    len:期望接受到数据大小;

    flags:0, 默认方式接受;

    src_addr:保存发送方地址信息的空间的指针;

    addrlen:地址信息的长度。

  • 返回值: 成功:返回实际接受到的字节数;

    失败:返回-1;

    特殊情况:当对方发送0字节数据包时,返回0.

7.2.5 辅助函数

inet_addr():将点分十进制的字符串ip地址转换成32位的二进制IP地址形式;

inet_ntoa():将结构体的ip地址转换成点分十进制的字符串ip地址;

htons():2字节数据,主机字节序转网络字节序;

htonl():4字节数据,主机字节序转网络字节序;

ntohs():2字节数据,网络字节序转主机字节序;

ntohl():4字节数据,网络字节序转主机字节序;

host------>net,s------>short,l------>long

7.3 UDP使用示例

客户端

首先调用socket()创建一个 UDP 套接字,填充服务端的struct sockaddr_in地址结构体,指定服务端 IP 地址与端口号;程序进入循环,通过fgets()读取控制台输入的字符串,使用sendto()将读取到的数据以 UDP 报文的形式发送给指定服务端,打印发送返回值,循环持续接收用户输入并发送数据,最后关闭套接字,实现 UDP 下向服务端持续发送数据的功能。

c 复制代码
int main()
{
    //socket()
    //sendto()
    //recvfrom()
    //close
    
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(-1 == sockfd)
    {
        perror("socket error");
        return -1;
    }

    struct sockaddr_in seraddr;

    seraddr.sin_family = AF_INET;
    seraddr.sin_port = htons(50000);
    seraddr.sin_addr.s_addr = inet_addr("10.251.215.158");

	char buff[1024] = {0};
	while (1)
	{
		fgets(buff, sizeof(buff), stdin);
		ssize_t size = sendto(sockfd, buff, strlen(buff), 0, (struct sockaddr *)&seraddr, sizeof(seraddr));
		if (-1 == size)
		{
			perror("sendto error");
			return -1;
		}
		printf("size = %ld\n", size);
	}

	close(sockfd);

    return 0;
}

服务端

首先调用socket()创建 UDP 套接字,初始化本机地址信息,通过bind()将套接字绑定到指定 IP 和 50000 端口;随后进入循环,每次先清空接收缓冲区,调用recvfrom()阻塞等待接收 UDP 数据包(不保存对端地址信息),接收成功后打印接收字节数和收到的字符串内容,循环持续等待客户端报文,最终关闭套接字,完成 UDP 服务端接收客户端数据的逻辑。

c 复制代码
int main(void)
{
    //socket()
    //bind()
    //recvfrom()
    //close()
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        perror("socket error");
        return -1;
    }
    struct sockaddr_in seraddr;
    seraddr.sin_family = AF_INET;
    seraddr.sin_port = htons(50000);
    seraddr.sin_addr.s_addr = inet_addr("10.251.215.158");

    int ret = bind(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));
    if (ret < 0)
    {
        perror("bind error");
        return -1;
    }
    char buff[1024] = {0};
    while (1)
    {
        memset(buff, 0, sizeof(buff));
        ssize_t size = recvfrom(sockfd, buff, sizeof(buff), 0, NULL, NULL);
        if (size < 0)
        {
            perror("recvfrom error");
            return -1;
        }
        printf("size = %ld, buff : %s\n", size, buff);
    }

    close(sockfd);
    return 0;
}
相关推荐
MSTcheng.17 分钟前
【Linux】Linux学习第三弹——Linux基本指令2
linux·windows·学习·ubuntu·操作系统
希望奇迹很安静23 分钟前
Linux基本使用命令
linux·运维·服务器
邪修king29 分钟前
Re:Linux 系统篇(十七):进程篇(六):环境变量深度解析|命令行参数、环境变量表、4 种获取方式与继承机制万字详解
linux·服务器·c++
张小姐的猫1 小时前
【C++开发脚手架】 —— Jsoncpp上手
java·linux·开发语言·网络·c++·tcp/ip·udp
昌原的儿子LEO1 小时前
Linux网络编程:TCP/UDP与HTTP协议核心笔记
linux·网络·tcp/ip
好评1241 小时前
【Linux】应用层协议HTTP
linux·运维·http
M78佐菲10 小时前
Linux学习笔记:TCP协议
linux·笔记·学习·tcp/ip·算法
Brilliantwxx10 小时前
【Linux】 进程(9)程序与进程地址空间(基础+进阶+面试题)
linux·运维·服务器·开发语言·c++
不怕犯错,就怕不做10 小时前
git prune 自动删除本地记录中那些远程已经不存在的分支引用
linux·服务器·git