Linux-TCP之深入浅出send和recv

2023-05-16

概念

  先明确一个概念:每个TCP socket在内核中都有一个发送缓冲区和一个接收缓冲区,TCP的全双工的工作模式以及TCP的滑动窗口便是依赖于这两个独立的buffer以及此buffer的填充状态。接收缓冲区把数据缓存入内核,应用进程一直没有调用read进行读取的话,此数据会一直缓存在相应 socket的接收缓冲区内。再啰嗦一点,不管进程是否读取socket,对端发来的数据都会经由内核接收并且缓存到socket的内核接收缓冲区之中。 read所做的工作,就是把内核缓冲区中的数据拷贝到应用层用户的buffer里面,仅此而已。进程调用send发送的数据的时候,最简单情况(也是一般情况),将数据拷贝进入socket的内核发送缓冲区之中,然后send便会在上层返回。换句话说,send返回之时,数据不一定会发送到对端去(和 write写文件有点类似),send仅仅是把应用层buffer的数据拷贝进socket的内核发送buffer中。后续我会专门用一篇文章介绍 read和send所关联的内核动作。每个UDP socket都有一个接收缓冲区,没有发送缓冲区,从概念上来说就是只要有数据就发,不管对方是否可以正确接收,所以不缓冲,不需要发送缓冲区。

接收缓冲区被TCP和UDP用来缓存网络上来的数据,一直保存到应用进程读走为止。对于TCP,如果应用进程一直没有读取,buffer满了之后,发生的动作是:通知对端TCP协议中的窗口关闭。这个便是滑动窗口的实现。保证TCP套接口接收缓冲区不会溢出,从而保证了TCP是可靠传输。因为对方不允许发出超过所通告窗口大小的数据。 这就是TCP的流量控制,如果对方无视窗口大小而发出了超过窗口大小的数据,则接收方TCP将丢弃它。 UDP:当套接口接收缓冲区满时,新来的数据报无法进入接收缓冲区,此数据报就被丢弃。UDP是没有流量控制的;快的发送者可以很容易地就淹没慢的接收者,导致接收方的UDP丢弃数据报。

以上便是TCP可靠,UDP不可靠的实现。

if(条件1)
{
    向buffer_last_modified填充协议内容“Last-Modified: Sat, 04 May 2012 05:28:58 GMT”;
    send(buffer_last_modified);
}

if(条件2)
{
    向buffer_expires填充协议内容“Expires: Mon, 14 Aug 2023 05:17:29 GMT”;
    send(buffer_expires);
}

if(条件N)
{
    向buffer_N填充协议内容“。。。”;
    send(buffer_N);
}

对于这样的实现,当前的http应答在执行这段代码时,假设有M(M<=N)个条件都满足,那么会有连续的M个send调用,那是不是下层会依次向客户端发出M个TCP包呢?答案是否定的,包的数目在应用层是无法控制的,并且应用层也是不需要控制的

用下列四个假设场景来解释一下这个答案:

由于TCP是流式的,对于TCP而言,每个TCP连接只有syn开始和fin结尾,中间发送的数据是没有边界的,多个连续的send所干的事情仅仅是:

场景一

假如socket的文件描述符被设置为阻塞方式,而且发送缓冲区还有足够空间容纳这个send所指示的应用层buffer的全部数据,那么把这些数据从应用层的buffer,拷贝到内核的发送缓冲区,然后返回。

场景二

假如socket的文件描述符被设置为阻塞方式,但是发送缓冲区没有足够空间容纳这个send所指示的应用层buffer的全部数据,那么能拷贝多少就拷贝多少,然后进程挂起,等到TCP对端的接收缓冲区有空余空间时,通过滑动窗口协议(ACK包的又一个作用----打开窗口)通知TCP本端:“亲,我已经做好准备,您现在可以继续向我发送X个字节的数据了”,然后本端的内核唤醒进程,继续向发送缓冲区拷贝剩余数据,并且内核向TCP对端发送TCP数据,如果send所指示的应用层buffer中的数据在本次仍然无法全部拷贝完,那么过程重复。。。直到所有数据全部拷贝完,返回。请注意,对于send的行为,我用了“拷贝一次”,send和下层是否发送数据包,没有任何关系

场景三

假如socket的文件描述符被设置为非阻塞方式,而且发送缓冲区还有足够空间容纳这个send所指示的应用层buffer的全部数据,那么把这些数据从应用层的buffer,拷贝到内核的发送缓冲区,然后返回。

场景四

假如socket的文件描述符被设置为非阻塞方式,但是发送缓冲区没有足够空间容纳这个send所指示的应用层buffer的全部数据,那么能拷贝多少就拷贝多少,然后返回拷贝的字节数。多涉及一点,返回之后有两种处理方式:

  • 死循环,一直调用send,持续测试,一直到结束(基本上不会这么搞)。
  • 非阻塞搭配epoll或者select,用这两种东西来测试socket是否达到可发送的活跃状态,然后调用send(高性能服务器必需的处理方式)。

综上,以及请参考本文前述的 SO_RCVBUF和SO_SNDBUF,你会发现,在实际场景中,你能发出多少TCP包以及每个包承载多少数据,除了受到自身服务器配置和环境带宽影响,对端的接收状态也能影响你的发送状况。

至于为什么说“应用层也是不需要控制发送行为的”,这个说法的原因是:

软件系统分层处理、分模块处理各种软件行为,目的就是为了各司其职,分工。应用层只关心业务实现,控制业务。数据传输由专门的层面去处理,这样应用层开发的规模和复杂程度会大为降低,开发和维护成本也会相应降低。

再回到发送的话题上来,之前说应用层无法精确控制和完全控制发送行为,那是不是就是不控制了?非也!虽然无法控制,但也要尽量控制!

如何尽量控制?

现在引入本节主题 TCP_CORK 和 TCP_NODELAY。

cork:塞子,塞住
nodelay:不要延迟

TCP_CORK:尽量向发送缓冲区中攒数据,攒到多了再发送,这样网络的有效负载会升高。简单粗暴地解释一下这个有效负载的问题。假如每个包中只有一个字节的数据,为了发送这一个字节的数据,再给这一个字节外面包装一层厚厚的TCP包头,那网络上跑的几乎全是包头了,有效的数据只占其中很小的部分,很多访问量大的服务器,带宽可以很轻松的被这么耗尽。那么,为了让有效负载升高,我们可以通过这个选项指示TCP层,在发送的时候尽量多攒一些数据,把他们填充到一个TCP包中再发送出去。这个和提升发送效率是相互矛盾的,空间和时间总是一堆冤家!!

TCP_NODELAY:尽量不要等待,只要发送缓冲区中有数据,并且发送窗口是打开的,就尽量把数据发送到网络上去。

很明显,两个选项是互斥的。实际场景中该怎么选择这两个选项呢?

再次举例说明

例子1:webserver,下载服务器(ftp的发送文件服务器),需要带宽量比较大的服务器,用TCP_CORK。

例子2:涉及到交互的服务器,比如ftp的接收命令的服务器,必须使用TCP_NODELAY。默认是TCP_CORK。设想一下,用户每次敲几个字节的命令,而下层在攒这些数据,想等到数据量多了再发送,这样用户会等到发疯。

这个糟糕的场景有个专门的词汇来形容-----粘(nian拼音二声)包


接下来我们用一个测试机上的阻塞socket实例来说明主题。文章中所有图都是在测试系统上现截取的,需要理解的3个概念。

一、TCP socket 的 buffer

每个 TCP socket 在内核中都有一个发送缓冲区和一个接收缓冲区,TCP 的全双工的工作模式以及TCP的流量(拥塞)控制便是依赖于这两个独立的buffer以及buffer的填充状态。

接收缓冲区把数据缓存入内核,应用进程一直没有调用recv()进行读取的话,此数据会一直缓存在相应socket的接收缓冲区内。

再啰嗦一点,不管进程是否调用recv()读取socket,对端发来的数据都会经由内核接收并且缓存到socket的内核接收缓冲区之中。recv()所做的工作,就是把内核缓冲区中的数据拷贝到应用层用户的buffer里面,并返回,仅此而已。

进程调用send()发送的数据的时候,最简单情况(也是一般情况),将数据拷贝进入socket的内核发送缓冲区之中,然后send便会在上层返回。

换句话说,send()返回之时,数据不一定会发送到对端去(和write写文件有点类似),send()仅仅是把应用层buffer的数据拷贝进socket的内核发送buffer中,发送是TCP的事情,和send其实没有太大关系。

接收缓冲区被 TCP 用来缓存网络上来的数据,一直保存到应用进程读走为止。

对于TCP,如果应用进程一直没有读取,接收缓冲区满了之后,发生的动作是:收端通知发端,接收窗口关闭(win=0)。这个便是滑动窗口的实现,保证TCP套接口接收缓冲区不会溢出,从而保证了TCP是可靠传输。

因为对方不允许发出超过所通告窗口大小的数据, 这就是TCP的流量控制,如果对方无视窗口大小而发出了超过窗口大小的数据,则接收方TCP将丢弃它。

查看测试机的socket发送缓冲区大小,如下图所示

第一个值是一个限制值,socket发送缓存区的最少字节数;

第二个值是默认值;

第三个值是一个限制值,socket发送缓存区的最大字节数;

根据实际测试,发送缓冲区的尺寸在默认情况下的全局设置是65536字节,即64k。

在测试系统上,发送缓存默认值是64k。

proc文件系统下的值和sysctl中的值都是全局值,应用程序可根据需要在程序中使用setsockopt()对某个socket的发送缓冲区尺寸进行单独修改,详见文章《TCP选项之SO_RCVBUF和SO_SNDBUF》,不过这都是题外话。

二、接收窗口(滑动窗口)

TCP连接建立之时的收端的初始接受窗口大小是14600,细节如图2所示(129是收端,130是发端)

接收窗口是 TCP 中的滑动窗口,TCP 的收端用这个接受窗口----win=14600,通知发端,我目前的接收能力是14600字节。

后续发送过程中,收端会不断的用ACK(ACK的全部作用请参照博文《TCP之ACK发送情景》)通知发端自己的接收窗口的大小状态,如图3,而发端发送数据的量,就根据这个接收窗口的大小来确定,发端不会发送超过收端接收能力的数据量。这样就起到了一个流量控制的的作用。

21,22 两个包都是收端发给发端的 ACK 包。

第21个包,收端确认收到的前 7240 个字节数据,7241 的意思是期望收到的包从 7241 号开始,序号加了1.同时,接收窗口从最初的 14656(如图2)经过慢启动阶段增加到了现在的 29120。用来表明现在收端可以接收 29120 个字节的数据,而发端看到这个窗口通告,在没有收到新的ACK的时候,发端可以向收端发送 29120 字节这么多数据。

第22个包,收端确认收到的前8688个字节数据,并通告自己的接收窗口继续增长为32000这么大。

三、单个TCP的负载量和MSS的关系

MSS在以太网上通常大小是1460字节,而我们在后续发送过程中的单个TCP包的最大数据承载量是1448字节,这二者的关系可以参考博文《TCP之1460MSS和1448负载》。

实例详解send()

实例功能说明:接收端129作为客户端去连接发送端130,连接上之后并不调用recv()接收,而是sleep(1000),把进程暂停下来,不让进程接收数据。内核会缓存数据至接收缓冲区。发送端作为服务器接收TCP请求之后,立即用ret = send(sock,buf,70k,0);这个C语句,向接收端发送70k数据。
我们现在来观察这个过程。看看究竟发生了些什么事。wireshark抓包截图如下图4

图4说明,包序号等同于时序

step-1. 客户端 sleep 在 recv() 之前,目的是为了把数据压入接收缓冲区。服务端调用"ret = send(sock,buf,70k,0);"这个C语句,向接收端发送70k数据。由于发送缓冲区大小16k,send()无法将70k数据全部拷贝进发送缓冲区,故先拷贝16k进入发送缓冲区,下层发送缓冲区中有数据要发送,内核开始发送。上层send()在应用层处于阻塞状态;

step-2. 11号TCP包,发端从这儿开始向收端发送1448个字节的数据;

step-3. 12号TCP包,发端没有收到之前发送的1448个数据的ACK包,仍然继续向收端发送1448个字节的数据;

step-4. 13号TCP包,收端向发端发送1448字节的确认包,表明收端成功接收总共1448个字节。此时收端并未调用recv()读取,目前发送缓冲区中被压入1448字节。由于处于慢启动状态,win接收窗口持续增大,表明接受能力在增加,吞吐量持续上升;

step-5. 14号TCP包,收端向发端发送2896字节的确认包,表明收端成功接收总共2896个字节。此时收端并未调用 recv() 读取,目前发送缓冲区中被压入2896字节。由于处于慢启动状态,win接收窗口持续增大,表明接受能力在增加,吞吐量持续上升;

step-6. 15号TCP包,发端继续向收端发送1448个字节的数据;

step-7. 16号TCP包,收端向发端发送4344字节的确认包,表明收端成功接收总共4344个字节。此时收端并未调用recv()读取,目前发送缓冲区中被压入4344字节。由于处于慢启动状态,win接收窗口持续增大,表明接受能力在增加,吞吐量持续上升;

step-8. 从这儿开始,我略去很多包,过程类似上面过程。同时,由于不断的发送出去的数据被收端用ACK确认,发送缓冲区的空间被逐渐腾出空地,send()内部不断的把应用层buf中的数据向发送缓冲区拷贝,从而不断的发送,过程重复。70k数据并没有被完全送入内核,send()不管是否发送出去,send不管发送出去的是否被确认,send()只关心buf中的数据有没有被全部送往内核发送缓冲区。如果buf中的数据没有被全部送往内核发送缓冲区,send()在应用层阻塞,负责等待内核发送缓冲区中有空余空间的时候,逐步拷贝buf中的数据;如果buf中的数据被全部拷入内核发送缓冲区,send()立即返回。

step-9. 经过慢启动阶段接收窗口增大到稳定阶段,TCP吞吐量升高到稳定阶段,收端一直处于sleep状态,没有调用recv()把内核中接收缓冲区中的数据拷贝到应用层去,此时收端的接收缓冲区中被压入大量数据;

step-10. 66号、67号TCP数据包,发端继续向收端发送数据;

step-11. 68号TCP数据包,收端发送ACK包确认接收到的数据,ACK=62265表明收端已经收到62265字节的数据,这些数据目前被压在收端的接收缓冲区中。win=3456,比较之前的16号TCP包的win=23296,表明收端的窗口已经处于收缩状态,收端的接收缓冲区中的数据迟迟未被应用层读走,导致接收缓冲区空间吃紧,故收缩窗口,控制发送端的发送量,进行流量控制;

step-12. 69号、70号TCP数据包,发端在接收窗口允许的数据量的范围内,继续向收端发送2段1448字节长度的数据;

step-13. 71号TCP数据包,至此,收端已经成功接收65160字节的数据,全部被压在接收缓冲区之中,接收窗口继续收缩,尺寸为1600字节;

step-14. 72号TCP数据包,发端在接收窗口允许的数据量的范围内,继续向收端发送1448字节长度的数据;

step-15. 73号TCP数据包,至此,收端已经成功接收66609字节的数据,全部被压在接收缓冲区之中,接收窗口继续收缩,尺寸为192字节。

step-16. 74号TCP数据包,和我们这个例子没有关系,是别的应用发送的包;

step-17. 75号TCP数据包,发端在接收窗口允许的数据量的范围内,向收端发送192字节长度的数据;

step-18. 76号TCP数据包,至此,收端已经成功接收66609字节的数据,全部被压在接收缓冲区之中,win=0接收窗口关闭,接收缓冲区满,无法再接收任何数据;

step-19. 77号、78号、79号TCP数据包,由keepalive触发的数据包,响应的ACK持有接收窗口的状态win=0,另外,ACK=66801表明接收端的接收缓冲区中积压了66800字节的数据。

step-20. 从以上过程,我们应该熟悉了滑动窗口通告字段win所说明的问题,以及ACK确认数据等等。现在可得出一个结论,接收端的接收缓存尺寸应该是66800字节(此结论并非本篇主题)。send()要发送的数据是70k,现在发出去了66800字节,发送缓存中还有16k,应用层剩余要拷贝进内核的数据量是N=70k-66800-16k。接收端仍处于sleep状态,无法recv()数据,这将导致接收缓冲区一直处于积压满的状态,窗口会一直通告0(win=0)。发送端在这样的状态下彻底无法发送数据了,send()的剩余数据无法继续拷贝进内核的发送缓冲区,最终导致send()被阻塞在应用层;

step-21. send()一直阻塞中。。。

图4和send()的关系说明完毕。

那什么时候send返回呢?有3种 send()返回场景

场景1,我们继续图4这个例子,不过这儿开始我们就跳出图4所示的过程了

step-22. 接收端sleep(1000)到时间了,进程被唤醒,代码片段如图5

随着进程不断的用"recv(fd,buf,2048,0);"将数据从内核的接收缓冲区拷贝至应用层的buf,在使用win=0关闭接收窗口之后,现在接收缓冲区又逐渐恢复了缓存的能力,这个条件下,收端会主动发送携带"win=n(n>0)"这样的ACK包去通告发送端接收窗口已打开;

step-23. 发端收到携带"win=n(n>0)"这样的ACK包之后,开始继续在窗口运行的数据量范围内发送数据。发送缓冲区的数据被发出;

step-24. 收端继续接收数据,并用ACK确认这些数据;

step-25. 发端收到ACK,可以清理出一些发送缓冲区空间,应用层 send() 的剩余数据又可以被不断的拷贝进内核的发送缓冲区;

step-26. 不断重复以上发送过程;

step-27. send()的70k数据全部进入内核,send()成功返回。

场景2,我们继续图4这个例子,不过这儿开始我们就跳出图4所示的过程了

step-22. 收端进程或者socket出现问题,给发端发送一个RST,请参考博文《》;

step-23. 内核收到RST,send返回-1。

场景3,和以上例子没关系

连接上之后,马上send(1k),这样,发送的数据肯定可以一次拷贝进入发送缓冲区,send()拷贝完数据立即成功返回。

send()发送结论

其实场景1和场景2说明一个问题,send()只是负责拷贝,拷贝完立即返回,不会等待发送和发送之后的ACK。如果socket出现问题,RST包被反馈回来。在RST包返回之时,如果send()还没有把数据全部放入内核或者发送出去,那么send()返回-1,errno被置错误值;如果RST包返回之时,send()已经返回,那么RST导致的错误会在下一次send()或者recv()调用的时候被立即返回

场景3 完全说明send()只要完成拷贝就成功返回,如果发送数据的过程中出现各种错误,下一次send()或者recv()调用的时候被立即返回。

概念上容易疑惑的地方

1. TCP协议本身是为了保证可靠传输,并不等于应用程序用tcp发送数据就一定是可靠的,必须要容错;

2. send() 和 recv() 没有固定的对应关系,不定数目的 send() 可以触发不定数目的 recv(),这话不专业,但是还是必须说一下,初学者容易疑惑;

3. 关键点,send() 只负责拷贝,拷贝到内核就返回,我通篇在说拷贝完返回,很多文章中说send()在成功发送数据后返回,成功发送是说发出去的东西被ACK确认过。send() 只拷贝,不会等ACK

4. 此次send()调用所触发的程序错误,可能会在本次返回,也可能在下次调用网络IO函数的时候被返回

实际上理解了阻塞式的,就能理解非阻塞的。

 

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

Linux-TCP之深入浅出send和recv 的相关文章

  • Mono 和 WebRequest 速度 - 测试

    在 mono 4 6 2 linux 中 我注意到 wget 下载文件的速度与webclient DownloadString 所以我做了一个小测试来调查 为什么 wget 明显比 C 快 根据我自己的实验 使用 wget 下载 手动读取文
  • 是否可以找到哪个用户位于 localhost TCP 连接的另一端?

    这是一个编程问题 但它是 Linux Unix 特定的 如果我从本地主机获得 TCP 连接 是否有一种简单的方法可以告诉哪个用户在 C 程序内建立了连接而无需 shell 我知道这对于 Unix 域套接字来说并不太难 我已经知道远程 IP
  • 如何删除树莓派的相机预览

    我在我的 raspberryPi 上安装了 SimpleCv 并安装了用于使用相机板的驱动程序 uv4l 驱动程序 现在我想使用它 当我在 simpleCV shell Camera 0 getImage save foo jpg 上键入时
  • 无法为 Python 3.4 创建工作虚拟环境

    I 安装Python 3 4 2 https docs python org 3 using unix html building python和我的 Linux Mint 17 1 中的 Virtualenv 12 0 5 然后我尝试创建
  • 使用 MongoDB docker 镜像停止虚拟机而不丢失数据

    我已经在 AWS EC2 上的虚拟机中安装了官方的 MongoDB docker 映像 并且数据库上已经有数据 如果我停止虚拟机 以节省过夜费用 我会丢失数据库中包含的所有数据吗 在这些情况下我怎样才能让它持久 有多种选择可以实现此目的 但
  • 如何使用 bash 脚本关闭所有终端,在每个终端中有效地按 Ctrl+Shift+Q

    我经常打开许多终端 其中一些正在运行重要的进程 例如服务器 而另一些则没有运行任何东西并且可以关闭 如果您按 重要 则会弹出确认提示Cntrl Shift Q在其中 如下所示 我想要一个 bash 脚本 它可以关闭所有终端 但将 重要 终端
  • ARM 系统调用的接口是什么?它在 Linux 内核中的何处定义?

    我读过有关 Linux 中的系统调用的内容 并且到处都给出了有关 x86 架构的描述 0x80中断和SYSENTER 但我无法追踪 ARM 架构中系统调用的文件和进程 任何人都可以帮忙吗 我知道的几个相关文件是 arch arm kerne
  • 在中断时获取 current->pid

    我正在Linux调度程序上写一些东西 我需要知道在我的中断到来之前哪个进程正在运行 当前的结构可用吗 如果我在中断处理程序中执行 current gt pid 我是否可以获得我中断的进程的 pid 你可以 current gt pid存在并
  • gdb 错误 - 文件不是可执行格式:无法识别文件格式

    我正在尝试使用 gdb 调试某个名为 xdf 的程序 但是当我运行 gdb xdf 时 出现以下错误 home nealtitusthomas X ray astronomy heasoft 6 24 x86 64 pc linux gnu
  • Windows 与 Linux 文本文件读取

    问题是 我最近从 Windows 切换到 Ubuntu 我的一些用于分析数据文件的 python 脚本给了我错误 我不确定如何正确解决 我当前仪器的数据文件输出如下 Header 有关仪器等的各种信息 Data 状态 代码 温度 字段等 0
  • 我应该害怕使用 UDP 进行客户端/服务器广播通话吗?

    我在过去的两天里阅读了每一篇StackOverflow问题和答案 以及googling当然 关于印地TCP and UDP协议 以便决定在我的用户应用程序和 Windows 服务之间的通信方法中应该使用哪一种 从我目前所看到的来看 UDP是
  • linux下如何获取昨天和前天?

    我想在变量中获取 sysdate 1 和 sysdate 2 并回显它 我正在使用下面的查询 它将今天的日期作为输出 bin bash tm date Y d m echo tm 如何获取昨天和前天的日期 这是另一种方法 对于昨天来说 da
  • R 未获取用户库

    我有一个带 R 3 6 0 的 Fedora 30 系统 用户库设置在Renviron就像这个 R LIBS USER R LIBS USER R x86 64 redhat linux gnu library 3 6 事实上 它出现在交互
  • 如何从 Linux 的 shell 中删除所有以 ._ 开头的文件?

    确实如标题所示 我已将许多文件从 Mac 复制到 Raspberry Pi 这导致了许多以前缀开头的多余文件 我想删除以以下开头的文件夹中的每个文件 我该怎么做 尝试类似的方法 cd path to directory rm rf 或者 如
  • 在 shell 脚本中查找和替换

    是否可以使用 shell 在文件中搜索然后替换值 当我安装服务时 我希望能够在配置文件中搜索变量 然后在该值中替换 插入我自己的设置 当然 您可以使用 sed 或 awk 来完成此操作 sed 示例 sed i s Andrew James
  • 如何从类似于 eclipse 的命令行创建可运行的 jar 文件

    我知道 eclipse 会生成一个可运行的 jar 文件 其中提取并包含在该 jar 文件中的所有库 jar 文件 从命令提示符手动创建 jar 文件时如何执行类似的操作 我需要将所有 lib jar 解压到类文件夹中吗 目前我正在使用 j
  • “grep -q”的意义是什么

    我正在阅读 grep 手册页 并遇到了 q 选项 它告诉 grep 不向标准输出写入任何内容 如果发现任何匹配 即使检测到错误 也立即以零状态退出 我不明白为什么这可能是理想或有用的行为 在一个程序中 其原因似乎是从标准输入读取 处理 写入
  • 如何从linux命令行运行.exe可执行文件? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我在 Windows 中有一个 abc exe 可执行文件 我可以使用 DOS 命令提示来执行此应用程序 并为其提供一些运行时变量 我想从
  • 无法仅在控制台中启动 androidstudio

    你好 我的问题是下一个 我下载了Android Studio如果我去 路径 android studio bin 我执行studio sh 我收到以下错误 No JDK found Please validate either STUDIO
  • 套接字:监听积压并接受

    listen sock backlog 在我看来 参数backlog限制连接数量 这是我的测试代码 server initialize the sockaddr of server server sin family AF INET ser

随机推荐

  • Linux系统Fcitx中文输入法开机启动方法

    Linux系统Fcitx中文输入法开机启动方法 在GNOME下的启动在KDE下的启动 Debian FC Ubuntu的默认中文输入法都是SCIM xff0c 其实也挺好用的 xff0c 有点类似windows下微软拼音输入法 xff0c
  • linux sftp文件上传与下载

    何为sftp sftp是Secure File Transfer Protocol的缩写 xff0c 安全文件传送协议 可以为传输文件提供一种安全的加密方法 回到顶部 连接 linux下直接在终端中输入 xff1a sftp usernam
  • win10专业版 原版安装教程

    WINDOWS10 的安装很是辛酸 xff0c 折腾了很久 xff0c 写下教程 xff0c 以防以后再入坑 Notes 不建议安装Ghost版 xff0c 会有许多问题 xff0c 电脑升级内存条后 xff0c 发现电脑有时候莫名奇妙蓝屏
  • Qt面试以及常用类继承关系图

    关于Qt的事件 事件的产生 xff1a 产生来源有timer事件外设的事件 xff08 mouseMoveEvent xff09 timer事件 xff0c 滚轮事件 xff0c 界面重绘制事件等等事件的接受与处理 xff1a QObjec
  • 无人驾驶虚拟仿真(四)--通过ROS系统控制小车行走

    简介 xff1a 实现键盘控制虚拟仿真小车移动 xff0c w s a d 空格 xff0c 对应向前 向后 向左 向右 急停切换功能 xff0c q键退出 1 创建key control节点 进入工作空间源码目录 xff1a cd myr
  • 云台控制协议

    PELCO D与PELCO P协议 PELCO D 数据格式 xff1a 1位起始位 8位数据 1位停止位 xff0c 无校验位 波特率 xff1a 2400B S 命令格式 xff1a 字节1 字节2 字节3 字节4 字节5 字节6 字节
  • 继承中子类与父类构造\析构的调用和顺序

    1 子类被构造的时候会先调用父类的构造函数 2 子类析构的时候先析构子类后析构父类 3 如果直接用子类构造一个父类的对象 删除这个父类的对象不会调用子类的析构函数 xff0c 这就是引入虚析构函数的原因 xff01
  • 28335GPIO及外部中断配置介绍

    弄了两周终于把28335的启动流程 寄存器及中断向量表的映射方法 内存的划分等有了一个全面的了解 xff0c 今天看到久违的LED灯的闪烁 xff0c 顿扫阴霾 特在此总结下28335GPIO及外部中断配置介绍 其实对于一个微控制器 xff
  • DSP28335与AD7606通过SPI的串行数据交互

    弄了三天的DSP28335与AD7606的通信终于实现了 最终的方案是通过DSP28335控制AD7606的采样 xff0c 采集的数据通过SPI串口发送给28335 xff0c 然后28335通过串口发送给上位机显示 其实程序第一天就写好
  • 利用28335的epwm产生spwm波的总结

    一 SPWM设计简介 设计的内容是产生倍频的SPWM波 xff0c 也即是用的是同一个调制波 xff0c 两个桥臂上的载波相差180度 产生spwm时 xff0c 利用TB产生载波 xff0c 也即是三角波 xff08 计数方式采用增减模式
  • 段错误总结

    最近试着写了华为编程大赛的程序 xff0c 出现较多的一个问题是段错误 xff0c 由此看来对指针与边界的处理还不熟练 网上有些总结的很不错 xff0c 因此结合网上资料整理下 xff08 下面的还有些地方没有深究 xff0c 有时间继续深
  • 启发式算法总结

    下面是一些学习到的算法 xff0c 有些没有具体用到 xff0c 所以只是概念的解释 xff0c 方便自己以后回忆 一 粒子群算法 1 1基本思想 粒子群算法是模拟群体智能所建立起来的一种优化算法 xff0c 粒子群算法可以用鸟类在一个空间
  • 线程、进程通信再总结

    下面这个部分摘抄自网上 xff0c 谢谢贡献的作者 一 进程间的通信方式 管道 pipe xff1a 管道是一种半双工的通信方式 xff0c 数据只能单向流动 xff0c 而且只能在具有亲缘关系的进程间使用 进程的亲缘关系通常是指父子进程关
  • 结构体类型的动态数组操作

    链接 xff1a https www nowcoder com questionTerminal 6fc9a928c7654b0fbc37d16b8bd29ff9 来源 xff1a 牛客网 假如我们有3种月饼 xff0c 其库存量分别为18
  • 基于Linkit 7697的红绿灯控制系统

    1 硬件准备 LinkIt 7697 1 xff0c 继电器模块 1 xff0c 面包板 1 xff0c RGB LED灯 1 xff08 共阳极 xff0c 工作电流20mA xff0c 红灯压降2 2 2V xff0c 绿灯蓝灯压降3
  • 利用背包问题解决的双核处理问题

    一种双核CPU的两个核能够同时的处理任务 xff0c 现在有n个已知数据量的任务需要交给CPU处理 xff0c 假设已知CPU的每个核1秒可以处理1kb xff0c 每个核同时只能处理一项任务 n个任务可以按照任意顺序放入CPU进行处理 x
  • 简单整蛊室友,只需几行bat病毒代码

    为了让整蛊更方便 xff0c 不能搞什么花里胡哨 xff0c 所有直接使用bat代码来编写 首先新建1个txt文件 xff0c 更改为任意名称 xff0c 但后缀名必须更改为bat或com 然后右键编辑 再输入以下代码 xff1a star
  • 四轴飞行器,PID调节过程心得记录

    初次接触四轴 xff0c 编写四轴的姿态PID控制部分 xff0c xff0c 横滚俯仰是把遥控器的杆量转换为目标角度 xff0c 然后目标角度PID运算转换为目标角速度 xff0c 然后目标角速度PID运算转换为电机输出量 xff0c x
  • 天地飞接收机输出信号解析

    今天测试了下天地飞8通道的接收机的pwm输出 接收机的输出信号 xff0c 可以按照50HZ的pwm信号来解析 xff0c 在stm32中 xff0c 使用外部高地电平触发中断的方式 xff0c 来记录一个脉宽的时间 用示波器实际查看信号的
  • Linux-TCP之深入浅出send和recv

    概念 先明确一个概念 xff1a 每个TCP socket在内核中都有一个发送缓冲区和一个接收缓冲区 xff0c TCP的全双工的工作模式以及TCP的滑动窗口便是依赖于这两个独立的buffer以及此buffer的填充状态 接收缓冲区把数据缓