zoukankan      html  css  js  c++  java
  • Windows网络编程-循环发送和接收消息

    知识点:https://blog.csdn.net/mijichui2153/article/details/81118171

    Socket缓冲区

    每一个socket在被创建之后,系统都会给它分配两个缓冲区,即输入缓冲区和输出缓冲区。

    (1)send函数并不是直接将数据传输到网络中,而是负责将数据写入输出缓冲区,数据从输出缓冲区发送到目标主机是由TCP协议完成的。数据写入到输出缓冲区之后,send函数就可以返回了,数据是否发送出去,是否发送成功,何时到达目标主机,都不由它负责了,而是由协议负责。

    (2)recv函数也是一样的,它并不是直接从网络中获取数据,而是从输入缓冲区中读取数据。

    输入输出缓冲区,系统会为每个socket都单独分配,并且是在socket创建的时候自动生成的。一般来说,默认的输入输出缓冲区大小为8K。套接字关闭的时候,输出缓冲区的数据不会丢失,会由协议发送到另一方;而输入缓冲区的数据则会丢失。

    Socket数据的发送与接收问题

    数据的发送和接收是独立的,并不是发送方执行一次send,接收方就执行一次recv。recv函数不管发送几次,都会从输入缓冲区尽可能多的获取数据。如果发送方发送了多次信息,接收方没来得及进行recv,则数据堆积在输入缓冲区中,取数据的时候会都取出来。换句话说,recv并不能判断数据包的结束位置。

    send函数: 
    在数据进行发送的时候,需要先检查输出缓冲区的可用空间大小,如果可用空间大小小于要发送的数据长度,则send会被阻塞,直到缓冲区中的数据被发送到目标主机,有了足够的空间之后,send函数才会将数据写入输出缓冲区。

    TCP协议正在将数据发送到网络上的时候,输出缓冲区会被锁定(生产者消费者问题),不允许写入,send函数会被阻塞,直到数据发送完,输出缓冲区解锁,此时send才能将数据写入到输出缓冲区。

    要写入的数据大于输出缓冲区的最大长度的时候,要分多次写入,直到所有数据都被写到缓冲区之后,send函数才会返回。

    recv函数: 
    函数先检查输入缓冲区,如果输入缓冲区中有数据,读取出缓冲区中的数据,否则的话,recv函数会被阻塞,等待网络上传来数据。如果读取的数据长度小于输出缓冲区中的数据长度,没法一次性将所有数据读出来,需要多次执行recv函数,才能将数据读取完毕。

    If no incoming data is available at the socket, the recv call blocks and waits for data to arrive according to the blocking rules defined for WSARecv with the MSG_PARTIAL flag not set unless the socket is nonblocking. In this case, a value of SOCKET_ERROR is returned with the error code set to WSAEWOULDBLOCK. The select, WSAAsyncSelect, or WSAEventSelect functions can be used to determine when more data arrives.

    If the socket is connection oriented and the remote side has shut down the connection gracefully, and all data has been received, a recv will complete immediately with zero bytes received. If the connection has been reset, a recv will fail with the error WSAECONNRESET.

    循环发送和接收

    防止send或者 recv不完整,这样你想发一个 
    几MB直接调用下面方法就okay,不会少发~

    bool SendAll(SOCKET &sock, char*buffer, int size)
    {
        while (size>0)
        {
            int SendSize= send(sock, buffer, size, 0);
            if(SOCKET_ERROR==SendSize)
                return false;
            size = size - SendSize;//用于循环发送且退出功能
            buffer+=SendSize;//用于计算已发buffer的偏移量
        }
        return true;
    }
     
    bool RecvAll(SOCKET &sock, char*buffer, int size)
    {
        while (size>0)//剩余部分大于0
        {
            int RecvSize= recv(sock, buffer, size, 0);
            if(SOCKET_ERROR==RecvSize)
                return false;
            size = size - RecvSize;
            buffer+=RecvSize;
        }
        return true;
    }
  • 相关阅读:
    使用Apworks开发基于CQRS架构的应用程序(六):创建.NET WCF服务
    Microsoft NLayerApp案例理论与实践 项目简介与环境搭建
    使用Apworks开发基于CQRS架构的应用程序(七):配置数据库
    测试一下亚马逊联盟
    Revit参数族之DMD系列静电水处理器
    Revit参数族之ZP系列消声器
    第一个Ruby程序:Hello world!
    百度文库下载器冰点下载
    sketchup ruby编程之绘制梯段
    加西亚马尔克斯枯枝败叶
  • 原文地址:https://www.cnblogs.com/a-s-m/p/12624526.html
Copyright © 2011-2022 走看看