草庐IT

C套接字编程: Invalid argument error on connect()

coder 2023-09-18 原文

我正在编写客户端作为 TCP 客户端服务器程序的一部分。

我的代码到达连接部分并抛出一个 Invalid argument 错误,我已经检查了几次代码,但我找不到问题。

代码接收 3 个参数,第一个是 IP 地址或主机名,第二个是端口,第三个是要发送的消息的最大长度。

我的代码使用 getaddrinfo 来转换 IP 地址或主机名、创建所需的变量、启动连接、读取文件、发送数据和接收数据。

我运行代码:

gcc -std=gnu99 -O3 -Wall -o pcc_client pcc_client.c
./pcc_client 127.0.0.1 2233 4

输出是:

sockaddr_in initialized
Error starting connection : Invalid argument

#include <stdlib.h>
#include <stdio.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <dirent.h>

#define FILE_ADDR   "/dev/urandom"

int main(int argc, char *argv[]) {
    if (argc != 4) {
        printf("should receive 3 arguments Received %d args\n", argc);
        exit(1);
    }

    //Get command line arguments
    unsigned int port = atoi(argv[2]);
    int length = atoi(argv[3]); //Number of bytes to read
    char* buffer = malloc(length * sizeof(char)); //Buffer to hold data read from file
    char* recvBuf = malloc(10 * sizeof(char)); // Buffer to hold response from server

    struct addrinfo hints, *servinfo, *p;
    struct sockaddr_in *serv_addr;
    int rv;
    char ip[100];

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;

    if ((rv = getaddrinfo(argv[1], argv[2], &hints, &servinfo)) != 0) {
        perror("getaddrinfo error\n");
        return 1;
    }
    for (p = servinfo; p != NULL; p = p->ai_next) {
        serv_addr = (struct sockaddr_in *) p->ai_addr;
        strcpy(ip, inet_ntoa(serv_addr->sin_addr));
    }
    //   inet_aton(ip, &h.sin_addr);
    freeaddrinfo(servinfo);

    //Initialize socket
    int sockfd;
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) //Error creating socket
            {
        perror("Error creating socket \n");
        exit(1);
    }

    printf("socket created\n");

    //Initialize sockaddr_in structure
    memset((void*)serv_addr, 0,(size_t) sizeof(*serv_addr));
    serv_addr->sin_family = AF_INET;
    serv_addr->sin_port = htons(port);
    serv_addr->sin_addr.s_addr = inet_addr("127.0.0.1"); //change?


    //Initialize connection
    if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { //Error connecting
        perror("Error starting connection \n");
        exit(1);
    }
    printf("connect succesful\n");

    exit(0);

}

最佳答案

您使用的 serv_addr 完全错误。

您已将 serv_addr 声明为 sockaddr_in* 指针。 getaddrinfo() 成功退出后,您将循环输出列表,分配 serv_addr 指向列表中的每个 ai_addr,然后您释放列表,使 serv_addr 指向无效内存。然后,当您尝试用数据填充 serv_addr 时,您会浪费内存。然后你最终甚至根本没有将指向 sockaddr_in 的有效指针传递给 connect(),你实际上传递了一个指向 sockaddr_in 的指针,这就是它提示“无效参数”的原因。

事实上,您对这种情况的处理通常都是错误的。使用 getaddrinfo() 时,由于它返回可能包含多个套接字地址的链表,因此您需要遍历该列表以尝试 connect() 到每个地址,直到其中一个他们是成功的。如果您想要升级代码以同时支持 IPv4 和 IPv6(通过设置 hints.ai_family = AF_UNSPEC;),这一点尤其重要。

尝试更像这样的东西:

int main(int argc, char *argv[])
{
    if (argc != 4)
    {
        printf("should receive 3 arguments Received %d args\n", argc);
        exit(1);
    }

    struct addrinfo hints, *servinfo, *p;
    int sockfd = -1;

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_INET; // or AF_UNSPEC
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    int rv = getaddrinfo(argv[1], argv[2], &hints, &servinfo);
    if (rv != 0)
    {
        perror("getaddrinfo error\n");
        return 1;
    }

    for (p = servinfo; p != NULL; p = p->ai_next) {
        //Initialize socket
        sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
        if (sockfd < 0) continue;
        //Initialize connection
        rv = connect(sockfd, p->ai_addr, (socklen_t) p->ai_addrlen);
        if (rv == 0) break;
        close(sockfd);
        sockfd = -1;
    }

    freeaddrinfo(servinfo);

    if (sockfd < 0) //Error creating/connecting socket
    {
        perror("Error creating/connecting socket \n");
        exit(1);
    }

    printf("connect successful\n");

    ...

    close(sockfd);
    exit(0);
}

关于C套接字编程: Invalid argument error on connect(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48348858/

有关C套接字编程: Invalid argument error on connect()的更多相关文章

  1. ruby - 寻找通过阅读代码确定编程语言的ruby gem? - 2

    几个月前,我读了一篇关于ruby​​gem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:

  2. 网络编程套接字 - 2

    网络编程套接字网络编程基础知识理解源`IP`地址和目的`IP`地址理解源MAC地址和目的MAC地址认识端口号理解端口号和进程ID理解源端口号和目的端口号认识`TCP`协议认识`UDP`协议网络字节序socket编程接口`sockaddr``UDP`网络程序服务器端代码逻辑:需要用到的接口服务器端代码`udp`客户端代码逻辑`udp`客户端代码`TCP`网络程序服务器代码逻辑多个版本服务器单进程版本多进程版本多线程版本线程池版本服务器端代码客户端代码逻辑客户端代码TCP协议通讯流程TCP协议的客户端/服务器程序流程三次握手(建立连接)数据传输四次挥手(断开连接)TCP和UDP对比网络编程基础知识

  3. ruby - 是否可以在不实际发送或读取数据的情况下查明 ruby​​ 套接字是否处于 ESTABLISHED 或 CLOSE_WAIT 状态? - 2

    s=Socket.new(Socket::AF_INET,Socket::SOCK_STREAM,0)s.connect(Socket.pack_sockaddr_in('port','hostname'))ssl=OpenSSL::SSL::SSLSocket.new(s,sslcert)ssl.connect从这里开始,如果ssl连接和底层套接字仍然是ESTABLISHED,或者它是否在默认值7200之后进入CLOSE_WAIT,我想检查一个线程几秒钟甚至更糟的是在实际上不需要.write()或.read()的情况下关闭。是用select()、IO.select()还是其他方法完成

  4. ruby - 我正在学习编程并选择了 Ruby。我应该升级到 Ruby 1.9 吗? - 2

    我完全不是程序员,正在学习使用Ruby和Rails框架进行编程。我目前正在使用Ruby1.8.7和Rails3.0.3,但我想知道我是否应该升级到Ruby1.9,因为我真的没有任何升级的“遗留”成本。缺点是什么?我是否会遇到与普通gem的兼容性问题,或者甚至其他我不太了解甚至无法预料的问题? 最佳答案 你应该升级。不要坚持从1.8.7开始。如果您发现不支持1.9.2的gem,请避免使用它们(因为它们很可能不被维护)。如果您对gem是否兼容1.9.2有任何疑问,您可以在以下位置查看:http://www.railsplugins.or

  5. ruby-on-rails - Ruby 的 'open_uri' 是否在读取或失败后可靠地关闭套接字? - 2

    一段时间以来,我一直在使用open_uri下拉ftp路径作为数据源,但突然发现我几乎连续不断地收到“530抱歉,允许的最大客户端数(95)已经连接。”我不确定我的代码是否有问题,或者是否是其他人在访问服务器,不幸的是,我无法真正确定谁有问题。本质上,我正在读取FTPURI:defself.read_uri(uri)beginuri=open(uri).readuri=="Error"?nil:urirescueOpenURI::HTTPErrornilendend我猜我需要在这里添加一些额外的错误处理代码...我想确保我采取一切预防措施来关闭所有连接,这样我的连接就不是问题所在,但是我

  6. ruby - Faye WebSocket,关闭处理程序被触发后重新连接到套接字 - 2

    我有一个super简单的脚本,它几乎包含了FayeWebSocketGitHub页面上用于处理关闭连接的内容:ws=Faye::WebSocket::Client.new(url,nil,:headers=>headers)ws.on:opendo|event|p[:open]#sendpingcommand#sendtestcommand#ws.send({command:'test'}.to_json)endws.on:messagedo|event|#hereistheentrypointfordatacomingfromtheserver.pJSON.parse(event.d

  7. ruby - 如何以编程方式删除实例上的 "singleton information"以使其编码(marshal)? - 2

    我创建了一个由于“在运行时执行的单例元类定义”而无法编码的对象(这段代码的描述是否正确?)。这是通过以下代码执行的:#defineclassXthatmyusesingletonclassmetaprogrammingfeatures#throughcallofmethod:break_marshalling!classXdefbreak_marshalling!meta_class=class我该怎么做才能使对象编码正确?是否可以从对象instance_of_x的classX中“移除”单例组件?我真的需要一个建议,因为我们的一些对象需要通过Marshal.dump序列化机制进行缓存。

  8. Ruby 元编程问题 - 2

    我正在查看Ruby日志记录库Logging.logger方法并从sourceatgithub提出问题与这段代码有关:logger=::Logging::Logger.new(name)logger.add_appendersappenderlogger.additive=falseclass我知道类 最佳答案 这实际上删除了方法(当它实际被执行时)。这是确保close不会被调用两次的保障措施。看起来好像有嵌套的“class 关于Ruby元编程问题,我们在StackOverflow上找到一

  9. ruby - Paperclip:以编程方式分配图像并设置其名称 - 2

    使用Paperclip,我想从这样的URL抓取图像:require'open-uri'user.photo=open(url)问题是我最后得到一个像“open-uri20110915-4852-1o7k5uw”这样的文件名。有什么方法可以更改user.photo上的文件名?作为一个额外的变化,Paperclip将我的文件存储在S3上,所以如果我可以在初始分配中设置我想要的文件名就更好了,这样图像就会上传到正确的S3key。像这样:user.photo=open(url),:filename=>URI.parse(url).path 最佳答案

  10. ruby - 如何以编程方式检查证书是否已被吊销? - 2

    我正在开发一个xcode自动构建系统。在执行一些预构建验证时,我想检查指定的证书文件是否已被撤销。我了解securityverify-cert验证其他证书属性但不验证吊销。我如何检查撤销?我正在用Ruby编写构建系统,但我对任何语言的想法都持开放态度。我阅读了这个答案(Openssl-Howtocheckifacertificateisrevokedornot),但指向底部的链接(DoesOpenSSLautomaticallyhandleCRLs(CertificateRevocationLists)now?)进入的Material对我的目的来说有点过于复杂(用户上传已撤销的证书是一

随机推荐