检查C中的端口是否可达

时间:2012-06-02 08:46:31

标签: c networking tcp ip-address hostname

我有一个C函数来检查主机及其端口,当我使用FQDN主机名时,函数返回错误如:connect()失败:连接超时,但如果我改用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;
}

2 个答案:

答案 0 :(得分: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));
    }
}

答案 1 :(得分:0)

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

如果ping工作正常,请尝试telnet <machinename> <portnumber> - 如果两者都有效,那么您的代码可能会出现问题(我没有深入研究,太困了)。

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

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