发送到错误:无效的参数

Posted

技术标签:

【中文标题】发送到错误:无效的参数【英文标题】:sendto error: Invalid argument 【发布时间】:2015-08-23 12:16:47 【问题描述】:

我在套接字中使用sendto() 函数时遇到了麻烦

int main(int argc, const char * argv[]) 

    int acceptFd;
    struct sockaddr_in servaddr, cliaddr;
    char recieveBuf[512];
    char sendBuf[512];
    socklen_t cliLen;

    if(-1 == (acceptFd = socket(AF_INET,SOCK_DGRAM,0))) perror("socket() failed.\n");
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(6789);
    if(-1==bind(acceptFd,(struct sockaddr*)&servaddr,sizeof(servaddr))) perror("bind() failed.\n");


    bzero(&cliaddr, sizeof(cliaddr));

    while(1)


        if(recvfrom(acceptFd, recieveBuf, 512, 0, (struct sockaddr*) &cliaddr, &cliLen) == -1) 
            perror("recvfrom() failed");
            continue;
        

        strcpy(sendBuf,"recieved\n");
        printf("%s\n",sendBuf);
        if(-1 == sendto(acceptFd,sendBuf, 512,0,(struct sockaddr*)&cliaddr,cliLen))
            perror("sendto() failed");
            continue;
        
    

recvfrom() 工作正常,但每次调用 sendto() 时,错误处理都会打印出:sendto() failed: Invalid argument

发送程序在这里:

#include "test.AcceptMessage.pb.h"
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

int main(int argc, const char * argv[]) 



    int sendSocket;
    struct sockaddr_in cliaddr;
    char buf[512];
    if(-1 == (sendSocket = socket(AF_INET,SOCK_DGRAM,0))) perror("socket() failed.\n");
    bzero(&cliaddr, sizeof(cliaddr));
    cliaddr.sin_family = AF_INET;
    cliaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    cliaddr.sin_port = htons(6789);

    sendto(sendSocket,buf, 512,0,(
            struct sockaddr*)&cliaddr, sizeof(cliaddr));



    recvfrom(sendSocket,buf,512,0, nullptr, nullptr);
    printf("%s\n",buf);





    return 0;

那么这段代码有什么问题呢?

【问题讨论】:

将调用 sendto(2) 中的 cliLen 更改为 sizeof (struct sockaddr_in)sizeof cliaddr。可能系统调用自动检查使您传递给内核的参数大小无效。 【参考方案1】:

来自man recvfrom

在调用之前,它 [addrlen] 应该被初始化为 与 src_addr 关联的缓冲区。

因此,初始化您的 cliLen 变量:

socklen_t cliLen = sizeof(cliaddr);

【讨论】:

这确实有效,但我很想知道为什么:如果我已经知道 sockaddr 的长度,为什么还要麻烦以任何方式获取长度? 来自man recvfrom:“如果提供的缓冲区太小,返回的地址将被截断;在这种情况下,addrlen 将返回一个大于提供给调用的值。”这意味着addrlen 表示潜在的缓冲区溢出。 非常感谢,看来我应该更仔细地阅读 API 文档了。 @reavenisadesk,不是。你不知道。您已将调用中的cliLen 更改为recvefrom,因此您失去了价值。内核的系统调用接口期望将固定大小传递给内核,但是当从它返回时,您可以获得 struct sockaddr_in 结构中返回的大小的不同值,以允许您改进存储。如果你检查结构定义,你会发现结构上的填充(在从内核端返回时不考虑,但在系统调用参数检查中需要) @LuisColorado 是的,cliLen 最初是 init,但每次调用 recvfrom 时都会更改,对吗?【参考方案2】:

你没有任何理由在这里使用recvfrom()sendto()。这是一个连接的套接字。只需使用send()recv().

【讨论】:

以上是关于发送到错误:无效的参数的主要内容,如果未能解决你的问题,请参考以下文章

如何使用烧瓶将多个参数发送到路由?

将路由参数作为参数发送到中间件 Laravel

Sharekit - 将 url 链接发送到 facebook

如何将复杂的参数发送到 asp.net

数据中的Ajax传递参数发送到php

PyQt在连接到信号时将参数发送到插槽