Ping程序示例

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <libgen.h>
#include <sys/types.h>
#include <sys/time.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <netinet/ip_icmp.h>

#ifndef likely
#define likely(x) __builtin_expect(!!(x), 1)
#endif

#ifndef unlikely
#define unlikely(x) __builtin_expect(!!(x), 0)
#endif

#define PACKETSIZE  64
struct packet_st
{
	struct icmphdr icmph;
	char message[PACKETSIZE-sizeof(struct icmphdr)];
};

static volatile sig_atomic_t isterm = 0;   // 结束信号
static volatile sig_atomic_t isalarm = 0;  // 时钟信号(1秒1次)

// 中断后的信号处理函数
static void signals_handler(int sig, siginfo_t *si, void *context)
{
	switch(sig)
	{
		case SIGINT: case SIGTERM:
			isterm = sig;
			break;
		case SIGALRM: 
			isalarm = sig;
			break;
		default:
			break;
	}
}

// 注册信号中断
static void signals_register()
{
	struct sigaction act;
	struct itimerval interval;

	sigfillset(&act.sa_mask);
	sigdelset(&act.sa_mask, SIGINT);
	sigdelset(&act.sa_mask, SIGTERM);
	sigdelset(&act.sa_mask, SIGALRM);
	sigprocmask(SIG_SETMASK, &act.sa_mask, NULL);

	act.sa_flags = SA_SIGINFO;
	act.sa_sigaction = signals_handler;

	interval.it_interval.tv_sec = 1;
	interval.it_interval.tv_usec = 0;
	interval.it_value.tv_sec = 1;
	interval.it_value.tv_usec = 0;

	sigaction(SIGINT, &act, NULL);
	sigaction(SIGTERM, &act, NULL);
	sigaction(SIGALRM, &act, NULL);
	setitimer(ITIMER_REAL, &interval, NULL);
}

/*
 * in_cksum --
 *      Checksum routine for Internet Protocol family headers (C Version)
 */
unsigned short in_cksum(unsigned short *addr,int len)
{
	register int sum = 0;
	unsigned short answer = 0;
	register unsigned short *w = addr;
	register int nleft = len;

	/*
	 * Our algorithm is simple, using a 32 bit accumulator (sum), we add
	 * sequential 16 bit words to it, and at the end, fold back all the
	 * carry bits from the top 16 bits into the lower 16 bits.
	 */
	while (nleft > 1)  {
		sum += *w++;
		nleft -= 2;
	}

	/* mop up an odd byte, if necessary */
	if (nleft == 1) {
		*(unsigned char *)(&answer) = *(unsigned char *)w ;
		sum += answer;
	}

	/* add back carry outs from top 16 bits to low 16 bits */
	sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
	sum += (sum >> 16);                     /* add carry */
	answer = ~sum;                          /* truncate to 16 bits */
	return(answer);
}

int pinger(char *ip)
{
	int fd = 0;
    static unsigned short count = 0;

	fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
	if(fd == -1)
	{
		fprintf(stderr, "socket(): %s\n", strerror(errno));
		return -1;
	}
	fcntl(fd, F_SETFD, FD_CLOEXEC);
	fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);

	int flag = 1;
	struct timeval tv = {
		.tv_sec = 3,
		.tv_usec = 0
	};
	setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &flag, sizeof(int));
	setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(struct timeval));
	setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval));

	struct packet_st pkt;
	memset(&pkt, 0, sizeof(struct packet_st));
	pkt.icmph.type = ICMP_ECHO;
	pkt.icmph.code = 0;
	pkt.icmph.un.echo.id = (unsigned short)getpid();
	pkt.icmph.un.echo.sequence = ++count;
	pkt.icmph.checksum = in_cksum((unsigned short*)&pkt, sizeof(struct packet_st));

	struct sockaddr_in addr, from;
	memset(&addr, 0, sizeof(struct sockaddr_in));
	memset(&from, 0, sizeof(struct sockaddr_in));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr(ip);
    
    int ret = 0;
    socklen_t len = sizeof(struct sockaddr);
	ret = sendto(fd, &pkt, sizeof(struct packet_st), 0, (struct sockaddr*)&addr, len);
	if(ret == -1 && errno != EINTR)
	{
		fprintf(stderr, "sendto(): %s\n", strerror(errno));
		goto EndP;
	}
	fprintf(stdout, "sendto: %s\n", ip);

	fd_set readfds;
	FD_ZERO(&readfds);
	FD_SET(fd, &readfds);

	while((ret = select(fd+1, &readfds, NULL, NULL, &tv)))
	{
		if(ret == -1 && errno != EINTR)
		{
			fprintf(stderr, "select(): %s\n", strerror(errno));
			continue;
		}

		if(0 <= fd && fd < FD_SETSIZE && FD_ISSET(fd, &readfds))
		{
			ret = recvfrom(fd, &pkt, sizeof(struct packet_st), 0, (struct sockaddr*)&from, &len);
			if(ret == -1 && errno != EINTR)
			{
				fprintf(stderr, "recvfrom(): %s\n", strerror(errno));
				continue;
			}

			fprintf(stdout, "recvfrom: %s\n", inet_ntoa(from.sin_addr));
			break;
		}
	}

	FD_CLR(fd, &readfds);
EndP:
	if(fd) close(fd);
	return ret;
}

int main(int argc, char *argv[])
{
	if(argc != 2)
	{
		fprintf(stderr, "Usage: %s IPADDR\n", argv[0]);
		return -1;
	}

	signals_register();
	while(!isterm)
	{
		if(unlikely(isterm))
		{
			fprintf(stdout, "term signal: %d\n", isterm);
			isterm = 0;
		}

		if(likely(isalarm))
		{
			fprintf(stdout, "alarm signal: %d\n", isalarm);
			isalarm = 0;

			pinger(argv[1] ? argv[1] : "127.0.0.1");
		}

		sleep(-1);
	}

	return 0;
}

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READme.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 、 1资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READmE.文件(md如有),本项目仅用作交流学习参考,请切勿用于商业用途。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值