2

我有一个 C 函数来检查主机及其端口,当我使用 FQDN 主机名时,该函数返回错误,例如:connect() failed: connect time out,但如果我使用 IP 地址,似乎没问题,如何解决这个?

谢谢。

#include <unistd.h>
#include <string.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>

int is_network_up(char *chkhost, unsigned short chkport) {
    int sock;
    struct sockaddr_in chksock;
    struct hostent *host = NULL;

    if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
        syslog(LOG_ERR, "socket() creation error: %s", strerror(errno));
        return 0;
    }

    memset(&chksock, 0, sizeof(chksock));
    chksock.sin_family = AF_INET;
    chksock.sin_port = htons(chkport);

    /* get the server address */
    if (inet_pton(AF_INET, chkhost, &(chksock.sin_addr.s_addr)) <= 0) {
        if ((host = gethostbyname(chkhost)) == NULL) {
            syslog(LOG_ERR, "%s", hstrerror(h_errno));
            return 0;
        }

        memcpy(&(chksock.sin_addr.s_addr), &(host->h_addr_list[0]),
               sizeof(struct in_addr));
    }

    /* try to connect */
    if (connect(sock, (struct sockaddr *) &chksock, sizeof(chksock)) < 0) {
        syslog(LOG_ERR, "connect() failed: %s", strerror(errno));
        return 0;
    }

    close(sock);
    return 1;
}
4

2 回答 2

3

inet_pton()是错误的任务。它只接受数字地址。

以前,人们习惯于使用gethostbyname()名称解析。

但正如我们同时拥有 2012 年一样,这种方法已经过时了好几年了,因为它仍然仅限于AF_INET.

使用下面的程序,您应该实现大致相同并保持未来兼容。

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdlib.h>
#include <stdio.h>

int is_network_up(char *chkhost, unsigned short chkport) {
    int sock = -1;
    struct addrinfo * res, *rp;
    int ret = 0;
    char sport[10];
    snprintf(sport, sizeof sport, "%d", chkport);

    struct addrinfo hints = { .ai_socktype=SOCK_STREAM };

    if (getaddrinfo(chkhost, sport, &hints, &res)) {
        perror("gai");
        return 0;
    }

    for (rp = res; rp && !ret; rp = rp->ai_next) {
        sock = socket(rp->ai_family, rp->ai_socktype,
                rp->ai_protocol);
        if (sock == -1) continue;
        if (connect(sock, rp->ai_addr, rp->ai_addrlen) != -1) {
            char node[200], service[100];
            getnameinfo(res->ai_addr, res->ai_addrlen, node, sizeof node, service, sizeof
service, NI_NUMERICHOST);

            printf("Success on %s, %s\n", node, service);
            ret = 1;                  /* Success */
        }
        close(sock);
    }
    freeaddrinfo(res);

    return ret;
}

int main(int argc, char** argv) {
    if (argc > 1) {
        printf("%s: %d\n", argv[1], is_network_up(argv[1], 22));
    }
}
于 2012-06-02T09:39:48.840 回答
0

确保名称解析正常工作。看看您是否可以从代码运行的完全相同的环境中按名称 ping 计算机。

如果 ping 有效,请尝试telnet <machinename> <portnumber> - 如果这两个都有效,则可能是您的代码有问题(我没有深入研究,太困了:)。

确保将操作系统返回的任何内容作为 ip 地址从网络顺序转换为主机顺序。IIRC,gethostbyname 按网络顺序返回二进制 IP 地址。

ntohlchksock.sin_addr.s_addr之后可以使用onmemcpy来实现这个。

于 2012-06-02T09:15:26.533 回答