linux的UDP通信编程

2023-05-16

这篇文章将对linux下udp socket编程重要知识点进行总结,无论是开发人员应知应会的,还是说udp socket的一些偏僻知识点,本文都会讲到。尽可能做到,读了一篇文章之后,大家对udp socket有一个比较全面的认识。本文分为两个专题,第一个是常用的upd socket框架,第二个是一些udp socket并不常用但又相当重要的知识点。

一、基本的udp socket编程

1. UDP编程框架


要使用UDP协议进行程序开发,我们必须首先得理解什么是什么是UDP?这里简单概括一下。

UDP(user datagram protocol)的中文叫用户数据报协议,属于传输层。UDP是面向非连接的协议,它不与对方建立连接,而是直接把我要发的数据报发给对方。所以UDP适用于一次传输数据量很少、对可靠性要求不高的或对实时性要求高的应用场景。正因为UDP无需建立类如三次握手的连接,而使得通信效率很高。

UDP的应用非常广泛,比如一些知名的应用层协议(SNMP、DNS)都是基于UDP的,想一想,如果SNMP使用的是TCP的话,每次查询请求都得进行三次握手,这个花费的时间估计是使用者不能忍受的,因为这会产生明显的卡顿。所以UDP就是SNMP的一个很好的选择了,要是查询过程发生丢包错包也没关系的,我们再发起一个查询就好了,因为丢包的情况不多,这样总比每次查询都卡顿一下更容易让人接受吧。

UDP通信的流程比较简单,因此要搭建这么一个常用的UDP通信框架也是比较简单的。以下是UDP的框架图。

由以上框图可以看出,客户端要发起一次请求,仅仅需要两个步骤(socket和sendto),而服务器端也仅仅需要三个步骤即可接收到来自客户端的消息(socket、bind、recvfrom)。

2. UDP程序设计常用函数

socket()

#include <sys/types.h>          
#include <sys/socket.h>
int socket(int domain, int type, int protocol);

参数domain:用于设置网络通信的域,socket根据这个参数选择信息协议的族

Name                                     Purpose                         

AF_UNIX, AF_LOCAL          Local communication             

AF_INET                           IPv4 Internet protocols          //用于IPV4

AF_INET6                         IPv6 Internet protocols          //用于IPV6

AF_IPX                             IPX - Novell protocols

AF_NETLINK                     Kernel user interface device     

AF_X25                            ITU-T X.25 / ISO-8208 protocol   

AF_AX25                          Amateur radio AX.25 protocol

AF_ATMPVC                      Access to raw ATM PVCs

AF_APPLETALK                 AppleTalk                        

AF_PACKET                      Low level packet interface       

AF_ALG                           Interface to kernel crypto API

对于该参数我们仅需熟记AF_INET和AF_INET6即可

小插曲:PF_XXX和AF_XXX

我们在看Linux网络编程相关代码时会发现PF_XXX和AF_XXX会混着用,他们俩有什么区别呢?以下内容摘自《UNP》。

AF_前缀表示地址族(Address Family),而PF_前缀表示协议族(Protocol Family)。历史上曾有这样的想法:单个协议族可以支持多个地址族,PF_的值可以用来创建套接字,而AF_值用于套接字的地址结构。但实际上,支持多个地址族的协议族从来就没实现过,而头文件<sys/socket.h>中为一给定的协议定义的PF_值总是与此协议的AF_值相同。

所以我在实际编程时还是偏向于使用AF_XXX。

参数type(只列出最重要的三个):

SOCK_STREAM         Provides sequenced, reliable, two-way, connection-based byte streams.   //用于TCP

SOCK_DGRAM          Supports datagrams (connectionless, unreliable messages ). //用于UDP

SOCK_RAW              Provides raw network protocol access.  //RAW类型,用于提供原始网络访问

参数protocol:置0即可

返回值:成功:非负的文件描述符

           失败:-1

sendto()

#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
 

recvfrom()

#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,不阻塞填MSG_DONTWAIT

UDP socket 设置为的非阻塞模式 
Len = recvfrom(SocketFD, szRecvBuf, sizeof(szRecvBuf), MSG_DONTWAIT, (struct sockaddr *)&SockAddr,&ScokAddrLen);

UDP socket 设置为的阻塞模式 
Len = recvfrom(SocketFD, szRecvBuf, sizeof(szRecvBuf), 0, (struct sockaddr *)&SockAddr,&ScokAddrLen);

第五个参数src_addr:指向发送数据的主机地址信息的结构体,也就是我们可以从该参数获取到数据是谁发出的

第六个参数addrlen:表示第五个参数所指向内容的长度

返回值:成功:返回接收成功的数据长度

           失败: -1

bind()

#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

close()

#include <unistd.h>
int close(int fd);

close函数比较简单,只要填入socket产生的fd即可。

3. 搭建UDP通信框架

server:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>

#define SERVER_PORT 8888
#define BUFF_LEN 1024

void handle_udp_msg(int fd)
{
    char buf[BUFF_LEN];  //接收缓冲区,1024字节
    socklen_t len;
    int count;
    struct sockaddr_in clent_addr;  //clent_addr用于记录发送方的地址信息
    while(1)
    {
        memset(buf, 0, BUFF_LEN);
        len = sizeof(clent_addr);
        count = recvfrom(fd, buf, BUFF_LEN, 0, (struct sockaddr*)&clent_addr, &len);  //recvfrom是拥塞函数,没有数据就一直拥塞
        if(count == -1)
        {
            printf("recieve data fail!\n");
            return;
        }
        printf("client:%s\n",buf);  //打印client发过来的信息
        memset(buf, 0, BUFF_LEN);
        sprintf(buf, "I have recieved %d bytes data!\n", count);  //回复client
        printf("server:%s\n",buf);  //打印自己发送的信息给
        sendto(fd, buf, BUFF_LEN, 0, (struct sockaddr*)&clent_addr, len);  //发送信息给client,注意使用了clent_addr结构体指针

    }
}


/*
    server:
            socket-->bind-->recvfrom-->sendto-->close
*/

int main(int argc, char* argv[])
{
    int server_fd, ret;
    struct sockaddr_in ser_addr;

    server_fd = socket(AF_INET, SOCK_DGRAM, 0); //AF_INET:IPV4;SOCK_DGRAM:UDP
    if(server_fd < 0)
    {
        printf("create socket fail!\n");
        return -1;
    }

    memset(&ser_addr, 0, sizeof(ser_addr));
    ser_addr.sin_family = AF_INET;
    ser_addr.sin_addr.s_addr = htonl(INADDR_ANY); //IP地址,需要进行网络序转换,INADDR_ANY:本地地址
    ser_addr.sin_port = htons(SERVER_PORT);  //端口号,需要网络序转换

    ret = bind(server_fd, (struct sockaddr*)&ser_addr, sizeof(ser_addr));
    if(ret < 0)
    {
        printf("socket bind fail!\n");
        return -1;
    }

    handle_udp_msg(server_fd);   //处理接收到的数据

    close(server_fd);
    return 0;
}

client:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>

#define SERVER_PORT 8888
#define BUFF_LEN 512
#define SERVER_IP "172.0.5.182"


void udp_msg_sender(int fd, struct sockaddr* dst)
{

    socklen_t len;
    struct sockaddr_in src;
    while(1)
    {
        char buf[BUFF_LEN] = "TEST UDP MSG!\n";
        len = sizeof(*dst);
        printf("client:%s\n",buf);  //打印自己发送的信息
        sendto(fd, buf, BUFF_LEN, 0, dst, len);
        memset(buf, 0, BUFF_LEN);
        recvfrom(fd, buf, BUFF_LEN, 0, (struct sockaddr*)&src, &len);  //接收来自server的信息
        printf("server:%s\n",buf);
        sleep(1);  //一秒发送一次消息
    }
}

/*
    client:
            socket-->sendto-->revcfrom-->close
*/

int main(int argc, char* argv[])
{
    int client_fd;
    struct sockaddr_in ser_addr;

    client_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(client_fd < 0)
    {
        printf("create socket fail!\n");
        return -1;
    }

    memset(&ser_addr, 0, sizeof(ser_addr));
    ser_addr.sin_family = AF_INET;
    //ser_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
    ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);  //注意网络序转换
    ser_addr.sin_port = htons(SERVER_PORT);  //注意网络序转换

    udp_msg_sender(client_fd, (struct sockaddr*)&ser_addr);

    close(client_fd);

    return 0;
}

以上的框架用于一台主机不同端口的UDP通信,现象如下:

我们先建立server端,等待服务;然后我们建立client端请求服务。

server端:

client端:

自己主机跟自己通信不是很爽,我们想跟其他主机通信怎么搞?很简单,上面client的代码的第49行的注释打开,并注释掉下面那行,在宏定义里填入自己想通信的serverip就可以了。现象如下:

server端:

client端:

这样我们就实现了主机172.0.5.183和172.0.5.182之间的网络通信。

UDP通用框架搭建完成,我们可以利用该框架跟指定主机进行通信了。

如果想学习UDP的基础知识,以上的知识就足够了;如果想继续深入学习一下UDP SOCKET一些高级知识(奇技淫巧),可以花点时间往下看。

二、高级udp socket编程

1. udp的connect函数


什么?UDP也有conenct?connect不是用于TCP编程的吗?
是的,UDP网络编程中的确有connect函数,但它仅仅用于表示确定了另一方的地址,并没有其他含义。
有了以上认识后,我们可以知道UDP套接字有以下区分:
1)未连接的UDP套接字
2)已连接的UDP套接字

对于未连接的套接字,也就是我们常用的的UDP套接字,我们使用的是sendto/recvfrom进行信息的收发,目标主机的IP和端口是在调用sendto/recvfrom时确定的;

在一个未连接的UDP套接字上给两个数据报调用sendto函数内核将执行以下六个步骤:
1)连接套接字
2)输出第一个数据报
3)断开套接字连接
4)连接套接字
5)输出第二个数据报
6)断开套接字连接

对于已连接的UDP套接字,必须先经过connect来向目标服务器进行指定,然后调用read/write进行信息的收发,目标主机的IP和端口是在connect时确定的,也就是说,一旦conenct成功,我们就只能对该主机进行收发信息了。

已连接的UDP套接字给两个数据报调用write函数内核将执行以下三个步骤:
1)连接套接字
2)输出第一个数据报
3)输出第二个数据报

由此可以知道,当应用进程知道给同一个目的地址的端口号发送多个数据报时,显示套接字效率更高。

下面给出带connect函数的UDP通信框架

具体框架代码不再给出了,因为跟上面不带connect的代码大同小异,仅仅多出一个connect函数处理而已,下面给出处理conenct()的基本步骤。

void udp_handler(int s, struct sockaddr* to)
{
    char buf[1024] = "TEST UDP !";
    int n = 0;
    connect(s, to, sizeof(*to);
 
    n = write(s, buf, 1024);
 
    read(s, buf, n);
}

2. udp报文丢失问题


因为UDP自身的特点,决定了UDP会相对于TCP存在一些难以解决的问题。第一个就是UDP报文缺失问题。
在UDP服务器客户端的例子中,如果客户端发送的数据丢失,服务器会一直等待,直到客户端的合法数据过来。如果服务器的响应在中间被路由丢弃,则客户端会一直阻塞,直到服务器数据过来。

防止这样的永久阻塞的一般方法是给客户的recvfrom调用设置一个超时,大概有这么两种方法:
1)使用信号SIGALRM为recvfrom设置超时。首先我们为SIGALARM建立一个信号处理函数,并在每次调用前通过alarm设置一个5秒的超时。如果recvfrom被我们的信号处理函数中断了,那就超时重发信息;若正常读到数据了,就关闭报警时钟并继续进行下去。

2)使用select为recvfrom设置超时
设置select函数的第五个参数即可。

3. udp报文乱序问题


所谓乱序就是发送数据的顺序和接收数据的顺序不一致,例如发送数据的顺序为A、B、C,但是接收到的数据顺序却为:A、C、B。产生这个问题的原因在于,每个数据报走的路由并不一样,有的路由顺畅,有的却拥塞,这导致每个数据报到达目的地的顺序就不一样了。UDP协议并不保证数据报的按序接收。

解决这个问题的方法就是发送端在发送数据时加入数据报序号,这样接收端接收到报文后可以先检查数据报的序号,并将它们按序排队,形成有序的数据报。

4. udp流量控制问题


总所周知,TCP有滑动窗口进行流量控制和拥塞控制,反观UDP因为其特点无法做到。UDP接收数据时直接将数据放进缓冲区内,如果用户没有及时将缓冲区的内容复制出来放好的话,后面的到来的数据会接着往缓冲区放,当缓冲区满时,后来的到的数据就会覆盖先来的数据而造成数据丢失(因为内核使用的UDP缓冲区是环形缓冲区)。因此,一旦发送方在某个时间点爆发性发送消息,接收方将因为来不及接收而发生信息丢失。

解决方法一般采用增大UDP缓冲区,使得接收方的接收能力大于发送方的发送能力。

int n = 220 * 1024; //220kB

setsocketopt(sockfd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n));

这样我们就把接收方的接收队列扩大了,从而尽量避免丢失数据的发生。

参考资料:

  • UDP socket 设置为的非阻塞模式_weixin_34186931的博客-CSDN博客
  • 《UNIX网络编程卷1》
  • 《Linux网络编程》
  • 《嵌入式Linux软件开发从入门到精通》

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux的UDP通信编程 的相关文章

  • 如何调用位于其他目录的Makefile?

    我正在尝试这样做 我想打电话给 make Makefile存在于其他目录中 abc可以使用位于不同目录中的 shell 脚本的路径 我该怎么做呢 由于 shell 脚本不允许我cd进入Makefile目录并执行make 我怎样才能编写she
  • 将数组传递给函数名称冲突

    Specs GNU bash 版本 3 1 17 无法升级 Premise 我一直在摆弄数组 我想知道是否有任何方法可以让函数的本地变量与所述函数外部的数组同名 Example 在下面的示例中 我将尝试显示该问题 Working bin b
  • 如何成功使用RDAP协议代替whois

    我对新的 RDAP 协议有点困惑 也不知道何时进一步追求它有意义 在我看来 每个人都同意它是 whois 的继承者 但他们的数据库似乎是空的 在 ubuntu 上我尝试了 rdapper nicinfo 甚至他们的 RESTful API
  • 为什么在 Linux 上字符串文字的内存地址与其他字符串文字的内存地址如此不同?

    我注意到字符串文字在内存中的地址与其他常量和变量 Linux 操作系统 非常不同 它们有许多前导零 未打印 Example const char h Hi int i 1 printf p n void h printf p n void
  • 无法执行'x86_64-conda_cos6-linux-gnu-gcc':没有这样的文件或目录(pysam安装)

    我正在尝试安装 pysam 执行后 python path to pysam master setup py build 这个错误的产生是 unable to execute x86 64 conda cos6 linux gnu gcc
  • 如何以编程方式从Linux中的进程名称获取进程ID

    在我的项目中 我们使用 ACE 自适应通信环境 中间件来编写可在 Windows 和 Linux 上运行的独立于操作系统的代码 要求是从进程名称中获取进程 ID 由于 ACE 不支持这一点 因此我们必须使用特定于平台的宏来分离 Window
  • sleep 0 有特殊含义吗?

    我看到很多用法sleep 0在我的一个客户项目中 代码看起来像这样 while true sleep 0 end 阅读一些像这样的答案this https stackoverflow com questions 3727420 signif
  • C 程序从连接到系统的 USB 设备读取数据

    我正在尝试从连接到系统 USB 端口的 USB 设备 例如随身碟 获取数据 在这里 我可以打开设备文件并读取一些随机原始数据 但我想获取像 minicom teraterm 这样的数据 请让我知道我可以使用哪些方法和库来成功完成此操作以及如
  • 无需 cron 在后台发送邮件

    我想知道是否有一种方法可以运行 PHP 循环 以便在后台向订阅者发送几百封电子邮件 我的目标是格式化新闻通讯 单击发送 然后关闭浏览器或更改页面 当然 发送电子邮件的实际过程将在后台运行 不会因浏览器关闭而中断 我知道这可以通过 cron
  • 为什么 Linux 对目录使用 getdents() 而不是 read()?

    我浏览 K R C 时注意到 为了读取目录中的条目 他们使用了 while read dp gt fd char dirbuf sizeof dirbuf sizeof dirbuf code Where dirbuf是系统特定的目录结构
  • Docker:处理 tar 文件时出错(退出状态 1):设置枢轴目录时出错:不是目录

    我是 Docker 新手 不知道是什么原因导致此错误或如何诊断它 任何有关此问题的具体帮助或有关首先检查何处以诊断此类问题的提示将不胜感激 我的 Dockerfile FROM java 8 Install maven RUN apt ge
  • 在 /dev/input/eventX 中写入事件需要哪些命令?

    我正在开发一个android需要将触摸事件发送到 dev input eventX 的应用程序 我知道C执行此类操作的代码结构如下 struct input event struct timeval time unsigned short
  • GCC 和 ld 找不到导出的符号...但它们在那里

    我有一个 C 库和一个 C 应用程序 尝试使用从该库导出的函数和类 该库构建良好 应用程序可以编译 但无法链接 我得到的错误遵循以下形式 app source file cpp text 0x2fdb 对 lib namespace Get
  • 如何模拟ARM处理器运行环境并加载Linux内核模块?

    我尝试加载我的vmlinux into gdb并使用 ARM 内核模拟器 但我不明白为什么我会得到Undefined target command sim 这是外壳输出 arm eabi gdb vmlinux GNU gdb GDB 7
  • 在Linux上编译C# + WPF以便在Windows上运行

    我有一个 C 应用程序 其中某些部分是使用 WPF 编写的 Mono 不支持 可以在 Linux 上编译这个应用程序吗 最终 该应用程序将在 Windows 上运行 但它是更大框架的一部分 并且我们的整个构建过程在 Linux 上运行 因此
  • 在 Mac OS X 上构建 Linux 内核

    我正在做一个修改Linux内核的项目 我有一台桌面 Linux 机器 在上面构建内核没有问题 不过 我要去旅行 我想在途中工作 我只有一台 MacBook 当我尝试构建 Linux 内核时 它抱怨说elf h was not found 我
  • 如何修复“iptables:没有该名称的链/目标/匹配”?

    我在我的 Linux 嵌入式系统上构建并安装了 iptables 如果我列出所有规则 则一切正常 iptables list Chain INPUT policy ACCEPT target prot opt source destinat
  • 拆分字符串以仅获取前 5 个字符

    我想去那个地点 var log src ap kernelmodule 10 001 100 但看起来我的代码必须处理 ap kernelmodule 10 002 100 ap kernelmodule 10 003 101 等 我想使用
  • awk 子串单个字符

    这是columns txt aaa bbb 3 ccc ddd 2 eee fff 1 3 3 g 3 hhh i jjj 3 kkk ll 3 mm nn oo 3 我可以找到第二列以 b 开头的行 awk if substr 2 1 1
  • Bash 解析和 shell 扩展

    我对 bash 解析输入和执行扩展的方式感到困惑 对于输入来说 hello world 作为 bash 中的参数传递给显示其输入内容的脚本 我不太确定 Bash 如何解析它 Example var hello world displaywh

随机推荐

  • Ubuntn设置程序开机启动 指定浏览器

    setp1 xff1a 设置jar开机启动 xff08 非服务启动方式 xff09 1 新建启动脚本 auto start sh xff08 并基于权限命令 xff1a sudo chmod 777 auto start sh xff09
  • 企业微信开发实战:自建审批流引擎

    1 概述 企业微信上是这样介绍的 不过经本人的研究测试 xff0c 该工作流引擎的功能是比较有限的 首先只有移动端才能发起 xff0c 流程的定义是必须在企业微信控制台中定义 xff0c 而且不支持条件分支 xff0c 适用于比较简单的应用
  • CmakeLists 复杂c++工程应用实例

    project vir data process cmake minimum required VERSION 2 8 add compile options std 61 c 43 43 11 include directories us
  • ROS学习笔记7_服务端Server

    在上图所示的模型中 xff0c Client作为请求的发送端 xff0c Server端接收Client发送的指令 xff0c 并且完成topic指令的发送 其中请求的信息类型是std srvs Trigger类 xff0c 同时返回一个R
  • char和int转换

    char和int的转换有两种方式 最简单的方法就是利用ASSCII码的差值 xff0c 直接用char的值减去 0 就行了 eg xff1a char a 61 39 9 39 int a 61 a 39 0 39 或者就用atof函数 x
  • printf缓冲区踩坑

    问题 碰到了这样一段代码 经过简化的 span class token macro property span class token directive hash span span class token directive keywo
  • PSINS学习笔记---姿态解算(1)---圆锥运动

    PSINS堪称中国导航领域的福音了 计划将工具箱中常用于工程实际中的相关算法根据个人理解做个解读注释 并且利用严老师网站中公开的数据集进行测试 由于个人水平有限 料想会漏洞百出 希望大家发现了不吝赐教 xff0c 感谢 xff01 1 加载
  • 使用matlab读取excel并作图

    在写论文时无奈非要用matlab xff0c 于是用地面站把传感器数据导出到了excel xff0c 用matlab画个图 用地面站向excel中读入数据 读入完保存即可 我读的是两种传感器数据 xff0c 一个是光流的位置值 xff0c
  • 坐标系梳理

    在很久以来 xff0c 我以为世界上只有两种坐标系 n系导航系和b系机体坐标系 最近在调试厂实验期间才知道原来还有特么这么多坐标系 机体系 xff1a 无人机 潜航器这些刚体自身的坐标系 xff0c 坐标系符合右手法则 xff0c x轴为机
  • 串口通信实现Int或float类型数据传输的方法

    方法 xff1a 发送方拆分数据为多个字节 xff0c 接收方再合并 串口通信程序中发送和接受数据以字节为单位 xff0c 将int或float类型的数据拆成单个字节存放到发送字符数组中 xff0c 然后接收方按照大小端模式将其重新合并为i
  • Gazebo Plugins教程

    Overview of Gazebo plugins Gazebo插件通过标准C 43 43 类直接控制Gazebo模型 xff0c 其具有以下优点 可以控制gazebo中几乎各个方面 xff1b 容易共享 xff1b 能够在运行的系统中插
  • 基于STM32读取SBG Ellipse A型号惯导数据

    之前在飞控上用的都是mpu6050 xff0c 但AUV在执行任务时主要在水下环境 xff0c 收不到GPS信号 xff0c 因此对INS的精度要求较高 xff0c 在姿态解算时要考虑地球自转等因素 xff0c 因此需要一款惯导器件能够感受
  • gcc-arm-none-eabi + scons环境搭建、固件烧录小记

    环境搭建在win7系统下进行 1 装git https gitforwindows org 正常下载即可 xff0c 装完后将git路径 xff08 D Program Files Git bin xff09 添加到环境变量中 添加方法 x
  • C语言中常用宏__FUNCTION_和__FILE__、__LINE__的用法介绍

    C C 43 43 提供了三个宏 FUNCTION FILE 和 LINE 用于定位程序运行时发生错误的位置 程序预编译时预编译器将用所在的函数名 xff0c 文件名和行号替换 当运行时错误产生后这三个宏分别能返回错误所在的函数 xff0c
  • Linux命令发送Http的get或post请求(curl和wget两种方法) 及定时任务的设置

    Http请求指的是客户端向服务器的请求消息 xff0c Http请求主要分为get或post两种 xff0c 在Linux系统下可以用curl和wget命令来模拟Http的请求 下面就来介绍一下Linux系统如何模拟Http的get或pos
  • ROS path问题解决方案

    1 问题描述 1 1 在Roboware里面直接右键运行launch文件会出现如下错误 ResourceNotFound hector gazebo worlds ROS path 0 61 opt ros kinetic share ro
  • ubuntu下socket通信

    点击打开原文链接 第一部分为C 43 43 实现 xff0c 第二部分为python实现 第一部分 该socket 的功能是在客户端输入了两个浮点数组成的字符串 xff0c 在服务端接受后将其转换为浮点数输出 xff0c 统一时刻只能有一个
  • ZED相机深度模式+ZED sl中函数介绍

    ZED SDK提供两种深度感应模式 xff1a STANDARD和FILL 该STANDARD模式是ZED的默认深度感应模式 该STANDARD模式保留距离度量和形状 xff0c 并且比FILL模式运行得更快 xff0c 但它包含由于视觉遮
  • 串行通信的数据位,起始位,停止位?

    参考链接 单片机串口通信一般是11位 xff0c 起始位1bit xff0c 数据位8bit xff0c 校验位1bit xff0c 停止位1bit xff0c 串口通信分两种一种是同步通信 xff0c 一种是异步通信 xff0c 像ps
  • linux的UDP通信编程

    这篇文章将对linux下udp socket编程重要知识点进行总结 xff0c 无论是开发人员应知应会的 xff0c 还是说udp socket的一些偏僻知识点 xff0c 本文都会讲到 尽可能做到 xff0c 读了一篇文章之后 xff0c