C套接字编程:connect()上的参数错误无效

时间:2018-01-19 20:15:51

标签: c sockets tcp client

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

我的代码到达连接部分并抛出一个无效的参数错误,我已经多次查看代码,但我无法找到问题。

代码接收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初始化了   启动连接时出错:参数无效

#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);

}

2 个答案:

答案 0 :(得分:4)

您定义serv_addr

struct sockaddr_in *serv_addr;

然后你用它

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?

但是在代码中这两个地方之间没有任何地方你初始化指针!这意味着serv_addr 未初始化,其值不确定并指向一些看似随机的位置。取消引用指针将导致undefined behavior

简单,自然和事实上的标准解决方案是使serv_addr 不是指针,而是结构对象:

struct sockaddr_in serv_addr;

然后当你需要一个指针时,你使用地址操作符&

在调用&时,实际上使用 connect运算符会使上述问题变得更加复杂。如果serv_addr是指针,则&serv_addr是指针指针。它将是struct sockaddr_in **类型。由于您发送的指针不是指向sockaddr_in结构对象的指针,因此问题,指向指针的指针会导致错误消息。

通过使用如上所示的结构对象也可以解决这个问题。

答案 1 :(得分:4)

您使用serv_addr全部错误。

您已将serv_addr声明为sockaddr_in*指针。成功退出getaddrinfo()后,您循环显示输出列表,指定serv_addr指向列表中的每个ai_addr,然后释放列表,让serv_addr指向无效的记忆。当您尝试使用数据填充serv_addr时,您会丢失内存。然后你甚至根本没有将有效指针传递给sockaddr_inconnect(),你实际上是在向指向sockaddr_in的指针传递指针,这就是为什么它会抱怨&#34;无效的参数&#34;。

事实上,一般来说,这种情况都是错误的。使用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);
}