【问题标题】:Can I use C sockets without including <sys/socket.h>?我可以在不包含 <sys/socket.h> 的情况下使用 C 套接字吗?
【发布时间】:2019-07-04 00:26:43
【问题描述】:

我正在开发一个简单的 C++ 程序并希望使用 C 套接字。是否可以通过在 extern "C" 内部声明而不包括 来使用它们?

我们可以使用 extern "C" 来声明 libc 绑定,例如 write:

extern "C" {
    int write(int fd, const char *buf, int count);
};

但是,当声明所需的套接字函数时,结果是不可靠的。我发现我可以创建套接字和设置选项,但是 connect() 总是超时。

这里是一个使用纯 extern "C" 声明的例子

gcc extern.cpp -o extern ; ./extern
extern "C" {
    struct  hostent {
        char *  h_name;
        char ** h_aliases;
        int     h_addrtype;
        int     h_length;
        char ** h_addr_list;
    };
    #define h_addr  h_addr_list[0]
    struct in_addr {
        unsigned long s_addr;
    };
    struct sockaddr {
        unsigned short  sa_family;
        char            sa_data[14];
    };
    struct sockaddr_in {
        short            sin_family;
        unsigned short   sin_port;
        struct in_addr   sin_addr;
        char             sin_zero[8];
    };
    void* memset(void*, int, long unsigned int);
    void* memcpy(void*, const void*, long unsigned int);
    int write(int, const char*, int);
    int close(int);
    hostent* gethostbyname(const char*);
    int socket(int, int, int);
    int connect(int, sockaddr*, int);
    int send(int, const char*, int, int);
    int recv(int, char*, int, int);
    int getsockopt(int, int, int, void*, unsigned int*);
    int setsockopt(int, int, int, const void*, unsigned int);
    unsigned short htons(unsigned short);
    void perror(const char*);
    void exit(int);
    #define AF_INET 2
    #define SOCK_STREAM 1
    #define TCP_NODELAY 1
    #define TCP_SYNCNT  7
    #define IPPROTO_TCP 6
};

void error(const char *s) {
    perror(s);
    exit(1);
}

int main() {
    hostent *hp;
    int nodelay = 1;
    int sockfd;
    struct sockaddr_in serv_addr;

    if ((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
        error("socket");
    }
    setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (const char *)&nodelay, sizeof(int));

    memset(&serv_addr, '0', sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(80);
    if((hp = gethostbyname("stackoverflow.com")) == 0) {
        error("gethostbyname");
    }
    memcpy(&serv_addr.sin_addr, hp->h_addr, hp->h_length);

    // Reduce sock timeout
    int synRetries = 2;
    setsockopt(sockfd, IPPROTO_TCP, TCP_SYNCNT, &synRetries, sizeof(synRetries));

    // When using extern "C" this seems to timeout
    if (connect(sockfd, (sockaddr*)(&serv_addr), sizeof(struct sockaddr_in)) < 0) {
        close(sockfd);
        error("connect");
    }

    send(sockfd, "GET / HTTP/1.1\r\n\r\n\0", 19, 0);
    char buf[1024];
    recv(sockfd, buf, 1024, 0);
    write(0, buf, 1024);
    close(sockfd);

    return 0;
}

我希望 connect() 函数能够解决;但是,除非我包含 &lt;sys/socket.h&gt; connect() 否则会超时。

有什么办法可以解决这个问题,我很想看看是否可以使用纯 extern "C" 来处理套接字。

【问题讨论】:

  • 您可以在extern "C" { ... } 中包含#include
  • 原则上是的,你可以直接声明所有需要的函数和常量,前者用C链接,而不是包括sys/socket.h,但为什么要这样做呢?使用标题既安全又容易(实际上不止一个,涵盖了您列出的所有功能)。将其包含在 extern "C" 块中。
  • 你从哪里得到int connect(int, sockaddr*, int);?这根本不匹配standard。你为什么希望它起作用?
  • POSIX specification 定义了sys/socket.h 的(最小)内容,明确表示可以从 C++ 中包含此标头(以及它定义的所有其他标头)。因此,您不需要 这样做。你为什么要这样做?
  • @zwol: 练习为另一种语言制作绑定库做准备?这是他应该能够做到的。

标签: c++ c sockets


【解决方案1】:

您似乎从 gethostbyname 获得了一个 IPv6 地址并将其写入 sockaddr,导致缓冲区溢出并丢弃了一些东西。然后,您尝试将 IPv6 地址的前导部分作为 IPv4 地址连接,而该 IP 不想与您通信。

这条线也很疯狂,但我不明白为什么它会失败:

memset(&serv_addr, '0', sizeof(serv_addr))

应该是

memset(&serv_addr, 0, sizeof(serv_addr))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-21
    • 2017-11-20
    • 1970-01-01
    • 2014-05-23
    • 1970-01-01
    • 2011-02-23
    • 2011-06-10
    • 1970-01-01
    相关资源
    最近更新 更多