资源临时不可用 - MSG_DONTWAIT标志

时间:2016-10-10 13:11:36

标签: c linux sockets unix networking

我在c中使用tcp套接字服务器和客户端。 使用AF_INET,SOCK_STREAM和IPPROTO_TCP

我在客户端的发送功能

sent_now = send(sockId, buffer + sent_total, len - sent_total, MSG_DONTWAIT);

当我发送MSG达到20K-40KB的大小时,它工作正常。 当我发送MSG大小像365K(这就是我需要的)时,我在服务器端收到以下错误:资源暂时不可用!

我在服务器端的接收功能

totalRecvMsgSize = recieve(clntSocket,Buffer,RCVBUFSIZE,MSG_DONTWAIT);

我发送int数据类型。

如何在一次发送和接收操作中接收所有阵列?

旧帖子

有一篇文章What can cause a “Resource temporarily unavailable” on sock send() command,Davide Berra在那里说

  

那是因为您正在使用非阻塞套接字和输出   缓冲区已满。

     

来自send()手册页

     

当消息不适合发送缓冲区时   socket,send()通常阻塞,除非已放置套接字   在非阻塞I / O模式下。在非阻塞模式下,它将返回   在这种情况下,EAGAIN。

     

EAGAIN是绑定到"资源暂时不可用的错误代码"

     

考虑使用select()来更好地控制这种行为

我的问题是:

* 1)如何在一次发送和接收操作中接收所有阵列? *

2)select()会帮助我处理这个数组大小吗?

3)我可以更改缓冲区大小以及如何更改?

2 个答案:

答案 0 :(得分:1)

由于这是一个流套接字,因此您在send()上使用循环,在recv()上使用MSG_WAITALL

考虑这些辅助函数:

/* Receive the entire buffer.
 * Returns 0 if success, nonzero errno otherwise.
*/
static int recv_all(const int sockfd, void *buffer, const size_t len)
{
    ssize_t n;

    n = recv(sockfd, buffer, len, MSG_WAITALL);
    if (n == 0)
        return errno = EPIPE; /* Other end will not send more data */
    else
    if (n == -1)
        return errno;
    else
    if (n < -1)
        return errno = EIO;   /* Should never occur */
    else
    if (n != (ssize_t)len)
        return errno = EINTR; /* Interrupted, or sender goofed */
    else
        return 0;
}

/* Send the entire buffer.
 * Returns 0 if success, nonzero errno otherwise.
*/
static int send_all(const int sockfd, const void *buffer, const size_t len)
{
    const char       *pos = (const char *)buffer;
    const char *const end = (const char *)buffer + len;
    ssize_t           n;

    while (pos < end) {

        n = send(sockfd, pos, (size_t)(end - pos), 0);
        if (n > 0)
            pos += n; 
        else
        if (n != -1)
            return errno = EIO;
        else
            return errno;
    }
}

答案 1 :(得分:0)

  1. 你无法可靠地实现这一目标。您始终可以编写自己的sendallrecvall函数,将套接字设置为阻塞,然后重复调用send(/ recv),直到发送/接收所有数据。 (通常带有阻塞套接字的单个send调用将导致所有数据在一次操作中发送,但有些情况[例如传输某些数据后的信号]将导致早期返回,所以你不应该依赖它。)

  2. 您可以使用select来实现与非阻塞套接字相同的功能,但它会使缓冲区管理变得更加复杂。您需要跟踪每个缓冲区中的位置/剩余的数据量,以及select报告套接字“可读”或“可写”的新尝试时,在适当的位置发送/接收相应的缓冲区。

  3. 是的,您可以根据需要制作缓冲区大小,但如果您的意思是“我可以设置系统缓冲区大小以避免这种情况吗?”然后,没有办法配置系统,使其无需额外代码即可100%可靠地工作。 TCP不维护消息边界。您的协议必须在TCP提供的逻辑流上加上边界。