【Linux网络编程必学!】——Linux_网络编程_UDP_arduino udpclient(3)

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前在阿里

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Linux运维全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上运维知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化的资料的朋友,可以点击这里获取!

+ [7.2 udp报文乱序问题](#72_udp_441)
+ [7.3 udp流量控制问题](#73_udp_446)

在这里插入图片描述

1. 预备知识

1.1 ip地址

  • 要想使网络中的计算机能够进行通信,必须为每台计算机指定一个标识号,通过这个标识号来指定接受数据的计算机或者发送数据的计算机。在TCP/IP协议中,这个标识号就是IP地址,它可以唯一标识一台计算机
  • 目前,IP地址广泛使用的版本是IPv4,它是由4个字节大小的二进制数来表示,如:00001010000000000000000000000001。由于二进制形式表示的IP地址非常不便记忆和处理,因此通常会将IP地址写成十进制的形式,每个字节用一个十进制数字(0-255)表示,数字间用符号“.”分开,如 “192.168.1.100”。
  • 源ip地址就是发出这个数据包的电脑的ip地址,它是数据的来源
  • 目标ip地址就是数据最终要到达的那台电脑的ip地址。
  • 路由器就是根据目标ip地址确定如何转发数据包,最终把数据以最佳路由发送到目标主机的。

1.2 端口号

  • 通过IP地址可以连接到指定计算机,但如果想访问目标计算机中的某个应用程序,还需要指定端口号。在计算机中,不同的应用程序是通过端口号区分的。
  • 端口号是用两个字节(16位的二进制数)表示的,它的取值范围是065535,其中,01023之间的端口号用于一些知名的网络服务和应用,用户的普通应用程序需要使用1024以上的端口号,从而避免端口号被另外一个应用或服务所占用。
  • 源端口就是本机程序用来发送数据的端口。
  • 目的端口就是对方主机用哪个端口接收。
  • IP地址 + 端口号能够标识网络上的某一台主机的某一个进程。
  • 一个端口号只能被一个进程占用。
    注意:一个进程可以绑定多个端口号; 但是一个端口号不能被多个进程绑定。

关系图:
在这里插入图片描述

2. 网络字节序

  • 网络字节序定义收到的第一个字节被当作高位看待,这就要求发送端发送的第一个字节应当是高位。而在发送端发送数据时,发送的第一个字节是该数字在内存中起始地址对应的字节。可见多字节数值在发送前,在内存中数值应该以大端法存放。
  • 网络协议指定了**通讯字节序:大端**。只有在多字节数据处理时才需要考虑字节序,运行在同一台计算机上的进程相互通信时,一般不用考虑字节序,异构计算机之间通讯,需要转换自己的字节序为网络字节。主机字节序是小端,所以才需要进行字节序转换。

2.1 大端模式和小端模式

字节序是指多字节数据的存储顺序,在设计计算机系统的时候,有两种处理内存中数据的方法:大端格式、小端格式。

  • 小端格式(Little-Endian):将低位字节数据存储在低地址;
  • 大端格式(Big-Endian):将高位字节数据存储在低地址。
    在这里插入图片描述

在这里插入图片描述
判断是否是小端:

bool isLittleEndian()
{
    union U
    {
        int  i;
        char c;
    };
    U u;
    u.i = 0x12345678;
    return u.c == 0x78;
}

2.2 字节序转换函数

#include <arpa/inet.h>
// 将 32位主机字节序数据转换成网络字节序数据
//(h:host, n:net,l:long)
uint32\_t htonl(uint32\_t hostint32);
// 将 16 位主机字节序数据转换成网络字节序数据
uint16\_t htons(uint16\_t hostint16);
// 将 32 位网络字节序数据转换成主机字节序数据
uint32\_t ntohl(uint32\_t netint32);
// 将 16 位网络字节序数据转换成主机字节序数据
uint16\_t ntohs(uint16\_t netint16);

3. sockaddr结构

struct sockaddr很多网络编程API诞生早于IPv4协议,那时候都使用的是sockaddr结构体,为了向前兼容,现在sockaddr退化成了(void *)的作用,传递一个地址给函数,至于这个函数是sockaddr_in还是其他的,由地址族确定,然后函数内部再强制转化为所需的地址类型。

结构图

在这里插入图片描述

struct sockaddr {  
    unsigned short    sa_family;    // 2 bytes address family, AF\_xxx unsiged short
    char              sa_data[14];     // 14 bytes of protocol address 
}; 

struct sockaddr\_in {  
    short            sin_family;       // 2 bytes e.g. AF\_INET, AF\_INET6 
    unsigned short   sin_port;    // 2 bytes e.g. htons(3490) 
    struct in\_addr   sin_addr;     // 4 bytes see struct in\_addr, below 
    char             sin_zero[8];     // 8 bytes zero this if you want to 
};  

  
struct in\_addr {  
    unsigned long s_addr;          // 4 bytes load with inet\_pton() 
}; 

用例
在这里插入图片描述

4. 认识UDP协议

  • Internet 协议集支持一个无连接的传输协议,该协议称为用户数据报协议(UDP,User Datagram Protocol)。UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法
  • Internet 的传输层有两个主要协议,互为补充。无连接的是 UDP,它除了给应用程序发送数据包功能并允许它们在所需的层次上架构自己的协议之外,几乎没有做什么特别的事情。面向连接的是 TCP,该协议几乎做了所有的事情
  • 传输层协议
  • 无连接
  • 不可靠传输
  • 面向数据报(SOCK_DGRAM)
  • UDP的框架图
    在这里插入图片描述

5. socket编程接口

  1. 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
#include <sys/types.h> 
#include <sys/socket.h>
int socket(int domain, int type, int protocol);

用例
在这里插入图片描述

  • domain:用于设置网络通信的域,socket根据这个参数选择信息协议的族(一般选择如下两个,但不止如此两个)
  1. AF_INET IPv4 Internet protocols //用于IPV4
  2. AF_INET6 IPv6 Internet protocols //用于IPV6
  • type:(只列出最重要的三个):
  1. SOCK_STREAM Provides sequenced, reliable, two-way, connection-based byte streams. //用于TCP
  2. SOCK_DGRAM Supports datagrams (connectionless, unreliable messages ). //用于UDP
  3. SOCK_RAW Provides raw network protocol access. //RAW类型,用于提供原始网络访问
  • protocol:置0即可
  • 返回值
    成功:非负的文件描述符
    失败:-1
  1. 绑定端口号 (TCP/UDP, 服务器)
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr\* my_addr, socklen_t addrlen);

用例
在这里插入图片描述

  • sockfd:正在监听端口的套接口文件描述符,通过socket获得
  • my_addr:需要绑定的IP和端口
  • addrlen:my_addr的结构体的大小
  • 返回值
    成功:0
    失败:-1
  1. 发送 (TCP/UDP, 服务器)
#include <sys/types.h>
#include <sys/socket.h>
ssize_t sendto(int sockfd, const void \*buf, size_t len, int flags,
              const struct sockaddr \*dest_addr, socklen_t addrlen);

用例
在这里插入图片描述

  • sockfd:正在监听端口的套接口文件描述符,通过socket获得
  • buf:发送缓冲区,往往是使用者定义的数组,该数组装有要发送的数据
  • len:发送缓冲区的大小,单位是字节
  • flags:填0即可
  • dest_addr:指向接收数据的主机地址信息的结构体,也就是该参数指定数据要发送到哪个主机哪个进程
  • addrlen:表示第五个参数所指向内容的长度
  • 返回值
    成功:返回发送成功的数据长度
    失败: -1
  1. 接收(TCP/UDP, 服务器)
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recvfrom(int sockfd, void \*buf, size_t len, int flags,
                struct sockaddr \*src_addr, socklen_t \*addrlen);

用例
在这里插入图片描述

  • sockfd:正在监听端口的套接口文件描述符,通过socket获得
  • buf:接收缓冲区,往往是使用者定义的数组,该数组装有接收到的数据
  • len:接收缓冲区的大小,单位是字节
  • flags:填0即可
  • src_addr:指向发送数据的主机地址信息的结构体,也就是我们可以从该参数获取到数据是谁发出的
  • addrlen:表示第五个参数所指向内容的长度
  • 返回值
    成功:返回接收成功的数据长度
    失败: -1

6. 代码实现UDP

  • udpClient.cpp
#include"udpClient.hpp"

void Usage(std::string proc)
{
  std::cout<<"Usage: "<<proc<<" svr\_ip svr\_port"<<std::endl;
}
int main(int argc,char \*argv[])
{
  if(argc != 3)
  {
    Usage(argv[0]);
    exit(1);

  }
  udpClient uc(argv[1],atoi(argv[2]));
  uc.initClient();
  uc.start();

  return 0;
}


  • udpClient.hpp
#pragma once 

#include<iostream>
#include<string>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<cstdlib>

class udpClient
{
  public:
    //Server ip , port;
    udpClient(std::string _ip="127.0.0.1",int _port=8080)
      :ip(_ip)
      ,port(_port)
  {}
    void initClient()
    {
      sock = socket(AF_INET,SOCK_DGRAM,0);
      std::cout<<"sock"<<sock<<std::endl;
    // struct sockaddr\_in local;
    // local.sin\_family = AF\_INET;
    // local.sin\_port = htons(port);
    // local.sin\_addr.s\_addr = inet\_addr(ip.c\_str());
    //
    //
    // if(bind(sock,(struct sockaddr\*)&local,sizeof(local)) < 0)
    // {
    // std::cerr<<"bind error!\n"<<std::endl;
    // exit(1);
    // }
    }

    void start()
    {
     // char msg[64];
      std::string msg;


### 最后的话

最近很多小伙伴找我要Linux学习资料,于是我翻箱倒柜,整理了一些优质资源,涵盖视频、电子书、PPT等共享给大家!

### 资料预览

给大家整理的视频资料:

![](https://img-blog.csdnimg.cn/img_convert/acf2b1bc6b01f04fff1a32b27761a661.png)

给大家整理的电子书资料:

  

![](https://img-blog.csdnimg.cn/img_convert/bbc4bc32645f6c9c43f8f177251d8fba.png)



**如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力!**

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/topics/618542503)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

[外链图片转存中...(img-QzfftqjU-1715003453491)]

给大家整理的电子书资料:

  

[外链图片转存中...(img-zOHVQ3xZ-1715003453491)]



**如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力!**

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/topics/618542503)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 8
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值