c语言检测端口下降沿,C语言实现带自定义超时时间的telnet端口连通性检测功能...

#ifdef _WIN32

#include

#include

#include

#include

#include

#else

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#endif

typedef unsigned char UINT8;

typedef unsigned short UINT16;

typedef unsigned int UINT32;

#ifdef _WIN32

#pragma comment(lib, "ws2_32.lib")

#endif

#ifdef _WIN32

#define EWOULDBLOCKWSAEWOULDBLOCK

#defineEINPROGRESS     WSAEINPROGRESS

#defineETIMEDOUT           WSAETIMEDOUT

#endif

#ifndef _WIN32

typedef intSOCKET;

typedef struct sockaddr_in SOCKADDR_IN;

#define closesocket close

#define INVALID_SOCKET-1

#define SOCKET_ERROR-1

#endif

#ifndef _WIN32

int   GetLastError(void)

{

return errno;

}

#endif

#ifdef _WIN32

BOOL InitTCPIP(void)

{

WSADATA wsaData;

if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0)        //winsock2.2版本

{

printf("Init TCP:WSAStartup failed!\n");

return FALSE;

}

if (wsaData.wVersion != 0x0202)                  //验证版本协商结果

{

WSACleanup();

printf("Init TCP:wsaData.wVersion failed!\n");

return FALSE;

}

return TRUE;

}

#endif

/*

当我们以非阻塞的方式来进行连接的时候,返回的结果如果是 -1,这并不代表这次连接发生了错误,

如果它的返回结果是 EINPROGRESS(windows下返回EWOULDBLOCK),那么就代表连接还在进行中。 后面可以通过poll或者select来

判断socket是否可写,如果可以写,说明连接完成了

步骤1: 设置非阻塞,启动连接

实现非阻塞 connect ,首先把 sockfd 设置成非阻塞的。这样调用 connect 可以立刻返回,根据返回值和 errno 处理三种情况:

(1) 如果返回 0,表示 connect 成功。

(2) 如果返回值小于 0, errno 为 EINPROGRESS, 表示连接建立已经启动但是尚未完成。这是期望的结果,不是真正的错误。

(3) 如果返回值小于0,errno 不是 EINPROGRESS,则连接出错了。

步骤2:判断可读和可写

然后把 sockfd 加入 select 的读写监听集合,通过 select 判断 sockfd

是否可写,处理三种情况:

(1) 如果连接建立好了,对方没有数据到达,那么 sockfd 是可写的

(2) 如果在 select 之前,连接就建立好了,而且对方的数据已到达,那么 sockfd 是可读和可写的。

(3) 如果连接发生错误,sockfd 也是可读和可写的。

判断 connect 是否成功,就得区别 (2) 和 (3),这两种情况下 sockfd 都是

可读和可写的,区分的方法是,调用 getsockopt 检查是否出错。

步骤3:使用 getsockopt 函数检查错误

getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len)

在 sockfd 都是可读和可写的情况下,我们使用 getsockopt 来检查连接

是否出错。但这里有一个可移植性的问题。

如果发生错误,getsockopt 源自 Berkeley 的实现将在变量 error 中

返回错误,getsockopt 本身返回0;然而 Solaris 却让 getsockopt 返回 -1,

并把错误保存在 errno 变量中。所以在判断是否有错误的时候,要处理这两种情况。

*/

int connect_nonb(int sockfd, struct sockaddr *saptr, int salen, int nsec, int *err)

{

fd_set readset, writeset;

struct timeval tm;

int n, error, len;

#ifdef _WIN32

int nonblock = 1;

n = ioctlsocket(sockfd, FIONBIO, &nonblock);

if (n != 0)

{

(* err) = GetLastError();

return SOCKET_ERROR;

}

#else

int flag = fcntl(sockfd, F_GETFL, 0);

fcntl(sockfd, F_SETFL, flag|O_NONBLOCK);

#endif

error = 0;

n = connect(sockfd, saptr, salen);

if (n != 0)

{

(* err) = GetLastError();

if ((* err) != EINPROGRESS && (* err) != EWOULDBLOCK)

{

return SOCKET_ERROR;

}

}

else

goto done;

FD_ZERO(&readset);

FD_ZERO(&writeset);

FD_SET(sockfd, &readset);

FD_SET(sockfd, &writeset);

tm.tv_sec = nsec;

tm.tv_usec = 0;

n = select(sockfd + 1, &readset, &writeset, NULL, &tm);

if (n == 0)

{

(* err) = ETIMEDOUT;

return SOCKET_ERROR;

}

if (FD_ISSET(sockfd, &readset) || FD_ISSET(sockfd, &writeset))

{

len = sizeof(error);

if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *)&error, &len) <0)

{

(* err) = GetLastError();

return SOCKET_ERROR;

}

}

else

printf("select error : sockfd not set");

/*将套接字恢复为默认状态,即阻塞态*/

done:

#ifdef _WIN32

nonblock = 0;

n = ioctlsocket(sockfd, FIONBIO, &nonblock);

if (n != 0)

{

(* err) = GetLastError();

return SOCKET_ERROR;

}

#else

fcntl(sockfd, F_SETFL, flag);

if (error)

{

(* err) = error;

return SOCKET_ERROR;

}

#endif

return 0;

}

int main(int argc, char **argv)

{

char *ipaddr;

SOCKADDR_IN addrSrv;

UINT16 port;

SOCKET sock;

int err;

if (argc != 3)

{

printf("input parameter's number error");

return 1;

}

ipaddr = argv[1];

port = (UINT16)atoi(argv[2]);

printf("%s %d\n", ipaddr, port);

#ifdef _WIN32

if (!InitTCPIP())

{

printf("InitTCPIP error\n");

return 1;

}

#endif

addrSrv.sin_family = AF_INET;

addrSrv.sin_addr.s_addr = inet_addr(ipaddr);

addrSrv.sin_port = htons(port);

if((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)

{

printf("create socket error\n");

return 1;

}

if (connect_nonb(sock, (struct sockaddr *)&addrSrv, sizeof(addrSrv), 3, &err) == SOCKET_ERROR)

{

printf("FAILURE\n");

return 1;

}

closesocket(sock);

printf("SUCCESS\n");

return 0;

}

以下为纯linux下实现:

实现方法二:

#include

#include

int main(int argc, char *argv[])

{

int fd[2];

if(argc <2)

{

printf("param less\n");

return -1;

}

alarm(3);

pipe(fd);

write(fd[1], "\035", 1);      /* ^] */

write(fd[1], "close\n", 6);

close(fd[1]);

dup2(fd[0], STDIN_FILENO);

execlp("telnet", "telnet", argv[1], argv[2], 0);

}

实现方法三:

#include

#include

int main(int argc, char *argv[])

{

int fd[2];

if(argc <2)

{

printf("param less\n");

return -1;

}

alarm(3);

pipe(fd);

close(fd[1]);

dup2(fd[0], STDIN_FILENO);

execlp("telnet", "telnet", argv[1], argv[2], 0);

}

实现方法四:

#include

#include

int main(int argc, char *argv[])

{

int fd[2];

if(argc <2)

{

printf("param less\n");

return -1;

}

alarm(3);

pipe(fd);

execlp("telnet", "telnet", argv[1], argv[2], 0);

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值