#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <netdb.h>
#include <string.h>

extern int h_errno;

#define ERR_EXIT(m)                        \
            do                             \
            {                              \
                perror(m);                 \
                exit(EXIT_FAILURE);        \
                                           \
            }while(0)

//设置socket非阻塞
void active_nonblock(int fd)
{
    int ret;
    int flags = fcntl(fd, F_GETFL, 0);
    if (flags == -1)
        ERR_EXIT("fcntl");

    flags |= O_NONBLOCK;
    ret = fcntl(fd, F_SETFL, flags);
    if (ret == -1)
        ERR_EXIT("fcntl");
}

//设置socket阻塞
void deactive_nonblock(int fd)
{
    int ret;
    int flags = fcntl(fd, F_GETFL, 0);
    if (flags == -1)
        ERR_EXIT("de-fcntl");

    flags &= ~O_NONBLOCK;
    ret = fcntl(fd, F_SETFL, flags);
    if (ret == -1)
        ERR_EXIT("de-fcntl");
}

//利用select异步IO模型设置connect函数超时,优化扫描时间
int conn_timeout(int fd, struct sockaddr_in *addr, long wait_second)
{

    //socklen_t addrlen = sizeof(struct sockaddr_in);
    active_nonblock(fd);

    int rc = connect(fd, (struct sockaddr*)&(*addr), sizeof(*addr));

    if (rc != 0)
    {
        if (errno == EINPROGRESS)
        {
            //printf("Doing connection.\n");
            /*正在处理连接*/
            fd_set fdr, fdw;

            FD_ZERO(&fdr);
            FD_ZERO(&fdw);
            FD_SET(fd, &fdr);
            FD_SET(fd, &fdw);

            struct timeval timeout;
            timeout.tv_usec = wait_second;
            timeout.tv_sec = 0;

            rc = select(fd + 1, &fdr, &fdw, NULL, &timeout);
            //printf("rc is: %d\n", rc);
            /*select调用失败*/
            if (rc < 0)
            {
                //fprintf(stderr, "connect error:%s\n", strerror(errno));
                deactive_nonblock(fd);
                close(fd);
                return -1;
            }

            /*连接超时*/
            if (rc == 0)
            {
                //fprintf(stderr, "Connect timeout.\n");
                deactive_nonblock(fd);
                close(fd);
                return -1;
            }
            /*[1] 当连接成功建立时,描述符变成可写,rc=1*/
            if (rc == 1 && FD_ISSET(fd, &fdw))
            {
                //printf("Server Port %d Open!\n",port);
                deactive_nonblock(fd);
                close(fd);

                return 0;
            }
            /*[2] 当连接建立遇到错误时,描述符变为即可读,也可写,rc=2 遇到这种情况,可调用getsockopt函数*/
            if (rc == 2)
            {
                int err;
                int errlen = sizeof(err);
                if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1)
                {
                    //fprintf(stderr, "getsockopt(SO_ERROR): %s", strerror(errno));
                    deactive_nonblock(fd);
                    close(fd);
                    return -1;

                }

                if (err)
                {
                    errno = err;
                    //fprintf(stderr, "connect error:%s\n", strerror(errno));
                    deactive_nonblock(fd);
                    close(fd);
                    return -1;

                }
            }

        }
        fprintf(stderr, "connect failed, error:%s.\n", strerror(errno));
        return -1;
    }
    return 0;

    //deactive_nonblock(sockfd);

}

//将域名转化为IP
const char *getIPAddrbyHostname(const char * hostname)
{
    static char  s[128];
    memset(s,0,sizeof(s));
    struct hostent *h;
    h = gethostbyname(hostname);
    if ( h == NULL )
    {
        printf("Unkown Domain: %s\n",strerror(h_errno));
        return NULL;
    }
    strcpy(s, inet_ntoa(*((struct in_addr*)h->h_addr)));
    return s;

}

int main(int argc, char* argv[])
{
    if (argc < 4 )
    {
        printf("Usage:%s [Dst-Ip|Domain] [Start-Port] [End-Port]\n", argv[0]);
        return 1;
    }

    int i;

    const char *ipaddr = getIPAddrbyHostname(argv[1]);

    if( ipaddr == NULL )
    {
       puts("A Error Occured, The Program Quit!\n");
       return 1;
    }

    struct timeval start,end;
    gettimeofday(&start, NULL);

    for (i = atoi(argv[2]); i <= atoi(argv[3]); i++)
    {

        int sockfd = 0;
        //建立socket
        sockfd = socket(AF_INET, SOCK_STREAM, 0);

        if (sockfd  == -1)
        {
            perror("create socket failed");
            return 1;
        }

        //connect 连接server
        struct sockaddr_in serveraddr_in;
        memset(&serveraddr_in, 0, sizeof(serveraddr_in));

        serveraddr_in.sin_family = AF_INET;
        serveraddr_in.sin_port = htons(i);   /* port in network byte order */
        serveraddr_in.sin_addr.s_addr = inet_addr(ipaddr);

        if ( conn_timeout(sockfd, &serveraddr_in, 100000) == 0)
        {
            printf("Host %s Tcp Port \033[33m%5d \033[0mOpening.\n", argv[1], i);
        }

    }

    gettimeofday(&end, NULL);
    int total = (int)(end.tv_sec - start.tv_sec);

    printf("\nScan Cost Time: \033[31;5m %d \033[0m min \033[31;5m%d\033[0m sec\n", total/60, total%60);
    return 0;
}

/**************与本项目无关代码******************/
/*
ssize_t readn(int fd, void *buf, size_t count)
{
    size_t nleft = count;
    ssize_t nread;
    char *bufp = (char*)buf;

    while (nleft > 0)
    {
        if ((nread = read(fd, bufp, nleft)) < 0)
        {
            if (errno == EINTR)
                continue;
            return -1;
        }
        else if (nread == 0) //若对方已关闭
            return count - nleft;

        bufp += nread;
        nleft -= nread;
    }

    return count;
}

ssize_t writen(int fd, const void *buf, size_t count)
{
    size_t nleft = count;
    ssize_t nwritten;
    char *bufp = (char*)buf;

    while (nleft > 0)
    {
        if ((nwritten = write(fd, bufp, nleft)) < 0)
        {
            if (errno == EINTR)
                continue;
            return -1;
        }
        else if (nwritten == 0)
            continue;

        bufp += nwritten;
        nleft -= nwritten;
    }

    return count;

}

ssize_t recv_peek(int sockfd, void *buf, ssize_t len)
{

    while (1)
    {

        int ret = recv(sockfd, buf, len, MSG_PEEK);

        if (ret == -1 && errno == EINTR)
        {

            continue;
        }

        return ret;
    }

}
ssize_t readline(int sockfd, void *buf, size_t maxline)
{
    int ret;
    int nread;
    char *bufp = buf;
    int nleft = maxline;
    while (1)
    {
        ret = recv_peek(sockfd, bufp, nleft);

        if (ret < 0)
            return    ret;
        else if (ret == 0)
            return ret;

        nread = ret;
        int i;
        for (i = 0; i < nread; ++i)
        {
            if (bufp[i] == '\n')
            {
                ret = readn(sockfd, bufp, i + 1);
                if ( ret != (i + 1))
                    exit(EXIT_FAILURE);
                return ret;
            }
        }

        if (nread > nleft)
            exit(EXIT_FAILURE);

        nleft -= nread;
        ret = readn(sockfd, bufp, nread);

        if (ret != nread)
            exit(EXIT_FAILURE);

        bufp += nread;

    }
    return -1;
}

void echo_cli (int conn)
{
    char sendbuf[1024] = {0};
    char recvbuf[1024] = {0};
    while (fgets(sendbuf, sizeof(sendbuf), stdin) != NULL)
    {

        writen(conn, sendbuf, strlen(sendbuf));

        int ret = readline(conn, recvbuf, 1024);
        if (ret == -1)
            ERR_EXIT("readline failed\n");
        if (ret == 0)
        {
            printf("server close\n");
            break;
        }

        fputs(recvbuf, stdout);
        memset(sendbuf, 0, sizeof(sendbuf));
        memset(recvbuf, 0, sizeof(recvbuf));

    }

}

*/
/*--------------------UDP Scan Test-----------------------------*/
/*
    for (i = atoi(argv[2]); i <= atoi(argv[3]); i++)
    {
        int sockfd = 0;
        //建立socket
        sockfd = socket(AF_INET, SOCK_DGRAM, 0);

        if (sockfd  == -1)
        {
            perror("create socket failed");
            return 1;
        }

        struct sockaddr_in serveraddr_in;
        memset(&serveraddr_in, 0, sizeof(serveraddr_in));

        serveraddr_in.sin_family = AF_INET;
        serveraddr_in.sin_port = htons(i);
        serveraddr_in.sin_addr.s_addr = inet_addr(argv[1]);

        //udp也可以使用connect函数,引用来维持一个状态信息
        connect(sockfd, (struct sockaddr*)&serveraddr_in, sizeof(serveraddr_in));

        //①调用了connect指定了地址,sendto可简写:sendto(sockfd,sendbuf,sizeof(sendbuf),0,NULL,0)
        //②一旦调用了connect,可以使用send函数:send(sockfd,sendbuf,sizeof(sendbuf),0)
        sendto(sockfd,"hello",sizeof("hello"),0,
                    (struct sockaddr *)&serveraddr_in,sizeof(serveraddr_in));

        char recvbuf[1024] = {0};
        int rc = recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0, NULL, NULL);
        if (  rc == -1 )
        {
            //printf("Server %s Ucp Port %d opening ...\n", argv[1], i);
            perror("recvfrom:");
        }
    }
*/


这里写图片描述🔗

备份地址: 【基于Linux的Tcp端口扫描器的实现