【问题标题】:Check port reachable in C检查C中可访问的端口
【发布时间】:2012-06-07 07:50:31
【问题描述】:

我有一个 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;
}

【问题讨论】:

标签: c networking tcp ip-address hostname


【解决方案1】:

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

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

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

ntohl 可以在chksock.sin_addr.s_addr 之后使用memcpy 来实现此目的。

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 效果很好,谢谢。一个小问题:编译警告,例如“net.c:38: 警告:函数'close'的隐式声明”,为什么?
    • @timy 你#include &lt;unistd.h&gt;了吗?如果没有,请这样做。在我的系统上,它似乎被其他系统之一自动包含,但这似乎有所不同。
    • 呸,你先说gethostbyname吓到我了。即使在过去的几个月里,我也经常看到它推荐... +1 表示它已经过时了。
    • @glglgl 嗨,我的程序似乎有内存泄漏,也许是 getaddrinfo 引起的?
    • @timy 如果您正确使用freeaddrinfo(),则不会。请记住在原始指针上使用它,而不是在用于迭代的指针上(即这里是res,而不是rp)。
    猜你喜欢
    • 1970-01-01
    • 2011-02-21
    • 2015-07-26
    • 2011-03-04
    • 1970-01-01
    • 2012-10-06
    • 1970-01-01
    • 2014-08-14
    • 1970-01-01
    相关资源
    最近更新 更多