基于阿里云Aliddns动态域名解析的客户端PHP实现与服务器端(包含C与PHP)实现

18 篇文章 1 订阅
7 篇文章 0 订阅

       很多朋友的公司或家里有一台上网的机器,这些上网的机器有些能够获得公网IP,但是这些IP通常不固定。

       大家都想充分利用这些上网设备的网络能力来搭建服务器环境,但由于IP地址老是变化,因此,即使是给这些机器分配了域名,也时常无法访问。于是,很多人想到了动态域名解析,即域名不变,IP地址变化,域名解析记录能够跟随IP地址变化,目前市场上有几种商业的解析方案实现,例如花生壳,更多的就不举例了,避免给他们做免费广告。这些都要收费,而且可能要通过CNAME(将您的域名解析成别人的域名)方式来解决,解析效率略有降低。

       好在阿里云的开放精神,他们将域名解析的接口提供了给大家,经过笔者测试非常好用。

       本文将实现自己的免费动态域名解析实现分享出来,实现思路如下:

      1)首先有一台公网的固定域名的服务器,运行一个助手程序(getipd),来帮助获得动态IP主机的当前IP地址(一般几天变化一次);

      2)在动态IP的机器上(或者跨越该路由器的内部网络主机)运行PHP编写的客户端,PHP编写的客户端定期与公网那个运行getipd的服务器通信,一般10秒一次,获得自己的公网IP;

      3)客户端程序判断,如果自己的公网IP发生变化,则调用阿里云的接口来更改域名(A记录),阿里云的DNS动态解析真的非常快,一般是实时生效的。

一、PHP客户端的实现所有源代码如下(完整实现 dnsupdater.php,不依赖任何第三方库):

<?php
date_default_timezone_set('UTC');

set_time_limit(0);
$iphelper_addr = 'www.iavcast.com';
$iphelper_port = '8198';
$AccessKeyId     = 'your AccessKeyId';
$AccessKeySecret = 'your AccessKeySecret';
$domain_list = Array('video.yourdomain.com','www.yourdomain.com','video.yourdomain.net','file.yourdomain.net');//

$show_log = False;
$old_gateway_ip = '';

$options = getopt("d:h:");
if (count($options) > 0) {
	if (!empty($options['d']))
		$show_log = True;
}


if (!function_exists('random_int')) {
	//php 5.x compatible
	function random_int($min,$max) {
		return mt_rand($min,$max);
	}
}

/**
 * Class AlicloudDNSUpdater
 */
class AlicloudDNSUpdater {
    /**
     * @var string
     */
    public $domainName;

    /**
     * @var string
     */
    public $rR;

    /**
     * @var string
     */
    public $type;

    /**
     * @var string
     */
    public $value;

    /**
     * @var string
     */
    public $accessKeyId;

    /**
     * @var string
     */
    public $accessKeySecret;

    /**
     * AlicloudUpdateRecord constructor.
     *
     * @param string $accessKeyId
     * @param string $accessKeySecret
     */
    function __construct(
        $accessKeyId,
        $accessKeySecret
    ) {
        $this->accessKeyId     = $accessKeyId;
        $this->accessKeySecret = $accessKeySecret;
    }

    /**
     * @param string $CanonicalQueryString
     * @return string
     */
    public function getSignature($CanonicalQueryString)
    {
        $HTTPMethod                  = 'GET';
        $slash                       = urlencode('/');
        $EncodedCanonicalQueryString = urlencode($CanonicalQueryString);
        $StringToSign                = "{$HTTPMethod}&{$slash}&{$EncodedCanonicalQueryString}";
        $StringToSign                = str_replace('%40', '%2540', $StringToSign);
        $HMAC                        = hash_hmac('sha1', $StringToSign, "{$this->accessKeySecret}&", true);

        return base64_encode($HMAC);
    }

    /**
     * @return string
     */
    public function getDate()
    {
        $timestamp = date('U');
        $date      = date('Y-m-d', $timestamp);
        $H         = date('H', $timestamp);
        $i         = date('i', $timestamp);
        $s         = date('s', $timestamp);

        return "{$date}T{$H}%3A{$i}%3A{$s}";
    }

    /**
     * @return string
     * @throws Exception
     */
    public function getRecordId()
    {
        $queries = [
            'AccessKeyId' => $this->accessKeyId,
            'Action' => 'DescribeDomainRecords',
            'DomainName' => $this->domainName,
            'Format' => 'json',
            'SignatureMethod' => 'HMAC-SHA1',
            'SignatureNonce' => random_int(1000000000, 9999999999),
            'SignatureVersion' => '1.0',
            'Timestamp' => $this->getDate(),
            'Version' => '2015-01-09'
        ];

        $response = $this->doRequest($queries);

		if (!isset($response['DomainRecords'])) {
			return '';
		}
		
        $recordList = $response['DomainRecords']['Record'];

        $RR = null;
        foreach ($recordList as $key => $record) {
            if ($this->rR === $record['RR']) {
                $RR = $record;
            }
        }

        if ($RR === null) {
            //die('RR ' . $this->rR . ' not found.');
			return '';
        }

        return $RR['RecordId'];
    }

    /**
     * @param string $domainName
     */
    public function setDomainName($domainName)
    {
        $this->domainName = $domainName;
    }

    /**
     * @param string $value
     */
    public function setValue($value)
    {
        $this->value = $value;
    }

    /**
     * @param string $rR
     */
    public function setRR($rR)
    {
        $this->rR = $rR;
    }

    /**
     * @param string $recordId
     */
    public function setRecordId($recordId)
    {
        $this->recordId = $recordId;
    }

    /**
     * @param string $type
     */
    public function setRecordType($type)
    {
        $this->type = $type;
    }

    /**
     * @param array $queries
     * @return array
     */
    public function doRequest($queries)
    {
        $CanonicalQueryString = '';
        $i                    = 0;
        foreach ($queries as $param => $query) {
            $CanonicalQueryString .= $i === 0 ? null : '&';
            $CanonicalQueryString .= "{$param}={$query}";
            $i++;
        }

        $signature  = $this->getSignature($CanonicalQueryString);
        $requestUrl = "http://dns.aliyuncs.com/?{$CanonicalQueryString}&Signature=" . urlencode($signature);
        $response   = file_get_contents($requestUrl, false, stream_context_create([
            'http' => [
                'ignore_errors' => true
            ]
        ]));

        return json_decode($response, true);
    }

    /**
     * @return array
     * @throws \Exception
     */
    public function sendRequest()
    {
		$RecordId = $this->getRecordId();
		if (empty($RecordId)) {
			return Array(
				'Code'=>'Error',
				'Message'=>$this->domainName .' record not found'
			);
		}
		
        $queries = [
            'AccessKeyId' => $this->accessKeyId,
            'Action' => 'UpdateDomainRecord',
            'Format' => 'json',
            'RR' => $this->rR,
            'RecordId' => $RecordId,
            'SignatureMethod' => 'HMAC-SHA1',
            'SignatureNonce' => random_int(1000000000, 9999999999),
            'SignatureVersion' => '1.0',
            'Timestamp' => $this->getDate(),
            'Type' => $this->type,
            'Value' => $this->value,
            'Version' => '2015-01-09'
        ];

        return $this->doRequest($queries);
    }
	
	public function sendAddRequest()
    {
        $queries = [
            'AccessKeyId' => $this->accessKeyId,
            'Action' => 'AddDomainRecord',
            'Format' => 'json',
            'RR' => $this->rR,
			'Type' => $this->type,
            'Value' => $this->value,
            'DomainName' => $this->domainName,
            'SignatureMethod' => 'HMAC-SHA1',
            'SignatureNonce' => random_int(1000000000, 9999999999),
            'SignatureVersion' => '1.0',
            'Timestamp' => $this->getDate(),
            'Version' => '2015-01-09'
        ];

        return $this->doRequest($queries);
    }
}

while(true) {
	$client = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

	$result = @socket_connect($client, $iphelper_addr, $iphelper_port);
	if (!$result) {
		if ($show_log) {
			echo "socket_connect() failed: reason: " . socket_strerror(socket_last_error($client)) . "\n";
		}
		socket_close($client);
	}
	else {
		$login_info = Array(
			'server'=>'server 1',
			'time'=>time()
		);
		
		socket_write($client, json_encode($login_info));
		
		$response = @socket_read($client, 1024);
		
		if ($response !== False && !empty($response) ) {
			$info = json_decode($response,True);
			if (is_array($info) && isset($info['ip'])) {
				if ($old_gateway_ip != $info['ip']) {
					if ($show_log) {
						echo date('Y-m-d H:i:s'). " do refresh dns ip :".$info['ip']."\n";
					}

					$updater         = new AlicloudDNSUpdater($AccessKeyId, $AccessKeySecret);
																	
					foreach($domain_list as $domain) {
						$dotpos = strpos($domain,'.');
						
						if ($dotpos !== False) {
							$recoreName = substr($domain,0,$dotpos);
							$domainName = substr($domain,$dotpos + 1);
							if ($show_log) {
								echo 'Update DNS Record:'.$recoreName.'.'.$domainName .' -> '. $info['ip'] ."...\n";
							}
							
							$updater->setDomainName($domainName);
							$updater->setRecordType('A');
							$updater->setRR($recoreName);
							$updater->setValue($info['ip']);

							$result = $updater->sendRequest();
							if ($show_log) {
								print_r($result);
								
								echo "\n";
							}
						}
					}
										
					$old_gateway_ip = $info['ip'];
				}
				else {
					if ($show_log) {
						echo "IP:{$old_gateway_ip} keep!\n";
					}
				}
			}
		}
			
		socket_close($client);
	}
		
	Sleep(10);
}


其中:$AccessKeyId ,$AccessKeySecret 是阿里云分配给你的,只要您能够登录阿里云的控制台即可获取。获取位置如下:

公网IP地址获取服务的主机地址 $iphelper_addr 可以修改,为了能够快速测试,可以暂时用 www.iavcast.com 网站提供的,请仅作为临时测试使用,正式使用时请搭建自己的服务器端。

$domain_list 为需要刷新的IP地址列表,请先在阿里云的控制台的域名解析操作页面添加初始化解析记录,例如www.domain.com,live.domain.com 等,添加解析记录时的IP地址可以是任何值,以后dnsupdater.php会修改这个值的。

dnsupdater.php 下载下来,并设置好必要的$AccessKeyId ,$AccessKeySecret 变量,假设PHP解释器安装在C:\PHP7\php.exe,运行 如下命令即可:

C:\PHP7\php.exe dnsupdater.php 

请用php5.6以上运行本客户端。PHP需要开启sockets扩展,即去掉php.ini里的如下行的注释(去掉分号)

extension=php_sockets.dll

如果想让dnsupdater.php 在后台运行,请用RunHiddenConsole.exe,这是一个用于隐藏Windows控制台窗口的助手程序,官方网址是:

GitHub - wenshui2008/RunHiddenConsole: Hide console window for windows programs

dnsupdater.php 代码完全可以运行在linux上,在linux系统的shell里输入:

 php dnsupdater.php &

可以作为守护进程长期运行。

二、getipd服务器端程序,这是一个用于帮助获取公网IP地址的极其简单的TCP服务器,笔者用C语言与PHP分别实现了一份,用PHP实现的 getip.php(仅仅一个文件)如下,请用PHP解释器执行:

<?php
date_default_timezone_set('UTC');

$port = 8198;

$sock_srv = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

socket_set_option($sock_srv, SOL_SOCKET, SO_REUSEADDR, 1);

if (!socket_bind($sock_srv, 0, $port)) {
	die('Bind Port '.$port ." Failed\n");
}

if (!socket_listen($sock_srv,5)) {
	die('Socket listen Failed On Port '.$port ."\n");
}

$clients = array($sock_srv);

echo "IPHelper Service running on port ".$port ." ...\n";

while(true) {
	$readSet = $clients;
	$writeSet = null;
	$expectSet = null;
	
	$number = socket_select($readSet, $writeSet, $expectSet, 10);
	
	if($number === False) {
		echo "Select error:".socket_strerror(socket_last_error()) ."\n";
		continue;
	}
	else if($number === 0) {
		//echo "Socket select nothing\n";
		continue;
	}
	//echo count($readSet).':'.count($writeSet).':'.count($expectSet)."\n";
	
	if(in_array($sock_srv, $readSet)) {
		$clients[] = $newsock = socket_accept($sock_srv);
				
		if (! @socket_getpeername($newsock, $ip) ) {
			echo "socket_getpeername Failed\n";
			$ip = '0.0.0.0';
		}
		echo "New client $ip arrived!\n";
		$key = array_search($sock_srv, $readSet);
		unset($readSet[$key]);
	}
	
	foreach ($readSet as $read_sock) {
		$data = @socket_read($read_sock, 1024);
		if($data === false || empty($data) ) {
			$key = array_search($read_sock, $clients);
			if (! @socket_getpeername($clients[$key], $ip)) {
				echo "socket_getpeername Failed\n";
				$ip = '0.0.0.0';
			}
			socket_close($read_sock);
			
			unset($clients[$key]);
			echo "client $ip disconnected\n";
			continue;
		}
		
		if (! @socket_getpeername($read_sock, $clientIp)) {
			//Never arrive here!
			$clientIp = '0.0.0.0';
		}
				
		$response = Array();
		
		$response['ip'] = $clientIp;
		
		$data = trim($data);
		
		if(!empty($data)) {
			echo 'Client:'.$clientIp ." login-data: ". $data."\n";
		}
		else {
			echo "nothing to read\n";
		}
		
		$responseS = json_encode($response,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE);
		
		socket_write($read_sock, $responseS);
		//wait for reponse sending		
		Sleep(1);
		
		$key = array_search($read_sock, $clients);
		socket_close($read_sock);
		unset($clients[$key]);
	}
}

socket_close($sock_srv);

在linux里输入 php getip.php & 即可执行。

用C语言实现的getip.c代码如下,需要编译成可执行程序

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#ifdef WIN32
#include <WinSock2.h>
#include <WS2tcpip.h>
#else
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/stat.h>

#define closesocket(s) close(s)
#endif


#define MAX_WAIT_TIMEOUT 10  // seconds

#define MYPORT 8198    // the port users will be connecting to

#define BACKLOG 10     // how many pending connections queue will hold

#define BUF_SIZE 512

int fd_A[BACKLOG];    // accepted connection fd
time_t fd_A_time[BACKLOG]; // accepted connection fd time

int conn_amount = 0;    // current connection amount

const char * g_app_dir	= NULL;
const char * g_exe_name = "getipd";

volatile long g_b_exit_server = 0;
int		g_web_root_len = 4;
int		g_app_dir_len = 0;

#ifdef _WIN32
#define PATH_DEL '\\'
#define PTHREAD_INITIALIZED {0,0}
#else
#define PATH_DEL '/'
#define PTHREAD_INITIALIZED 0
#endif


#undef MAX_PATH 
#ifndef MAX_PATH
#define MAX_PATH 1024
#endif

char g_cur_exe_path[MAX_PATH];
char g_log_file[MAX_PATH];

void getExePath()
{
	char * pch;
#ifdef _WIN32
	GetModuleFileNameA(NULL,g_cur_exe_path,ARRAYSIZE(g_cur_exe_path));
	pch = strrchr(g_cur_exe_path,'\\');
	pch ++ ;
	*pch = '\0';
#else
	int cnt = readlink("/proc/self/exe", g_cur_exe_path, MAX_PATH);  
	if (cnt < 0 || cnt >= MAX_PATH) {  
		strcpy(g_cur_exe_path,"/usr/local/");
	}
	pch = strrchr(g_cur_exe_path,'/');
	if (pch) {
		pch ++;
		*pch = 0;
	}
#endif
	g_app_dir = g_cur_exe_path;
	g_app_dir_len = strlen(g_app_dir);
	memcpy(g_log_file, g_app_dir, g_app_dir_len);
	strcpy(g_log_file + g_app_dir_len, "getipd.log");
}

#ifdef _WIN32
void init_daemon() {};
#else

#ifndef NOFILE 
#define NOFILE 3 
#endif

void init_daemon()
{
	int pid;
	int i;
	pid=fork();
	if(pid<0)    
		exit(1);
	else if(pid>0)
		exit(0);

	setsid();
	pid=fork();
	if(pid>0)
		exit(0);
	else if(pid<0)    
		exit(1);

	for(i=0;i<NOFILE;i++)
		close(i);
	chdir(g_cur_exe_path);
	umask(0);
	return;
}
#endif

#ifndef WIN32
#define DAEMON_HINT "\t-d Running as a daemon process.\n"
#else
#define DAEMON_HINT ""
#endif

void Usage() 
{
	const char *progname = "getipd";
	const char *debug = "";
#ifdef WIN32
	debug = "-debug ";
#endif
	fprintf(stderr,"Usage:\n%s %s-r <directory> -p <port> -l <logfile> -t <TemplateFileDir> -c <ConfigurationFile> \n"
		"Parameters:\n"
		"\t-p tcp port,default: [%s]\n" DAEMON_HINT,
		progname,debug,MYPORT
		);

	exit(1);
}

int b_daemon = 0;
int b_listClients = 0;

void showClients()
{
	int i;
	
	if (b_daemon || !b_listClients)
		return;
		
	printf("client amount: %d\n", conn_amount);
	for (i = 0; i < BACKLOG; i++) {
		printf("[%d]:%d  ", i, fd_A[i]);
	}
	printf("\n\n");
}

void saveOverflowLog(const char * clientIp)
{
	FILE * fp;
	
	fp = fopen(g_log_file, "wb");
	if (fp) {
		time_t t = time(NULL);
		struct tm * local = localtime(&t);
		char buf[1024];
		int len;
		
		len = sprintf(buf, "[%d-%d-%d %d:%d:%d] client IP:%s\n", local->tm_year+1900, local->tm_mon+1, local->tm_mday, 
												 local->tm_hour, local->tm_min, local->tm_sec,
												 clientIp);
		
		fwrite(buf,1, len, fp);
		
		fclose(fp);
	}
}

int main(int argc,char * argv[])
{
	int sock_fd, new_fd;  // listen on sock_fd, new connection on new_fd
	struct sockaddr_in server_addr;    // server address information
	struct sockaddr_in client_addr; // connector's address information
	socklen_t sin_size;
	int yes = 1;
	char buf[BUF_SIZE];
	char ipAddr[128];
	int ret;
	int i;
	
	fd_set fdsr;
	int maxsock,remove_count;
	struct timeval tv;
	unsigned short port = MYPORT;

#ifdef WIN32
	WSADATA wsaData;
	WORD wVersionRequested;

	wVersionRequested =MAKEWORD( 1, 1 );
	ret = WSAStartup( wVersionRequested, &wsaData );
	if ( ret != 0 ) {
		/* Tell the user that we couldn't find a useable */
		/* winsock.dll. */
		exit(1);
	}
#endif

	getExePath();

	g_exe_name = strrchr(argv[0],PATH_DEL);

	if (g_exe_name) {
		g_exe_name ++;
	}
	else {
		g_exe_name = argv[0];
	}
	
	/* Parse command line arguments */
	for (i = 1; i < argc; i++) {
		if (strcmp(argv[i], "-p") == 0) {
			port = atoi(argv[++i]);
		}
		else if (!strcmp(argv[i],"-d")) {
			b_daemon = 1;
			break;
		}
		else if (!strcmp(argv[i],"-l")) {
			b_listClients = 1;
			break;
		}
		else if (!strcmp(argv[i],"-?") || !strcmp(argv[i],"-h")) {
			Usage();
			break;
		}
	}
	
	if (b_daemon) {
		init_daemon();
	}
	
	if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		perror("socket");
		exit(1);
	}

	if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&yes, sizeof(int)) == -1) {
		perror("setsockopt");
		exit(1);
	}

	server_addr.sin_family = AF_INET;         // host byte order
	server_addr.sin_port = htons(MYPORT);     // short, network byte order
	server_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
	memset(server_addr.sin_zero, '\0', sizeof(server_addr.sin_zero));

	if (bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
		perror("bind");
		exit(1);
	}

	if (listen(sock_fd, BACKLOG) == -1) {
		perror("listen");
		exit(1);
	}

	if (!b_daemon) {
		printf("listen port %d\n", MYPORT);
	}
	
	conn_amount = 0;
	sin_size = sizeof(client_addr);
	maxsock = sock_fd;

	memset(fd_A,0,sizeof (fd_A));
	
	while (1) {
		// timeout setting
		tv.tv_sec = MAX_WAIT_TIMEOUT;
		tv.tv_usec = 0;

		// initialize file descriptor set
		FD_ZERO(&fdsr);
		FD_SET(sock_fd, &fdsr);

		// add active connection to fd set
		for (i = 0; i < BACKLOG; i++) {
			if (fd_A[i] != 0) {
				FD_SET(fd_A[i], &fdsr);
			}
		}

		ret = select(maxsock + 1, &fdsr, NULL, NULL, &tv);
		if (ret < 0) {
			perror("select");
			break;
		} else if (ret == 0) {
			if (!b_daemon) {
				printf("select %d sockets timeout\n", conn_amount);
			}
			if (conn_amount == 0)
				continue;
		}

		remove_count = 0;
		
		// check every fd in the set
		for (i = 0; i < conn_amount; i++) {
			if (FD_ISSET(fd_A[i], &fdsr)) {
				ret = recv(fd_A[i], buf, sizeof(buf), 0);
				if (ret <= 0) {        // client close
					if (!b_daemon) {
						printf("client[%d] close\n", i);
					}
					closesocket(fd_A[i]);
					FD_CLR(fd_A[i], &fdsr);
					fd_A[i] = 0;
					remove_count++;
				} else {        // receive data
					int ret2;
					
					if (ret < BUF_SIZE)
						memset(&buf[ret], '\0', 1);
					if (!b_daemon) {
						printf("client[%d] send:%s\n", i, buf);
					}

					sin_size = sizeof(client_addr);

					ret2 = getpeername(fd_A[i],(struct sockaddr *)&client_addr, &sin_size);

					if (ret2 == 0) {
						if (client_addr.sin_family == AF_INET) {
							int len = sprintf(buf,"{\"ip\":\"%s\"}", inet_ntop(AF_INET, &client_addr.sin_addr, ipAddr, sizeof(ipAddr)));

							send(fd_A[i], buf, len, 0);

							remove_count++;

							closesocket(fd_A[i]);

							FD_CLR(fd_A[i], &fdsr);
							fd_A[i] = 0;
						}
					}
					else {
						printf("getpeername failed: %d\n", ret2);
					}
				}
			}
		}
		
		//check client timeout
		if (conn_amount > 0) {
			time_t now = time(NULL);
			
			for (i = 0; i < conn_amount; i++) {
				if (fd_A[i]) {
					time_t time_out = now - fd_A_time[i];
					
					if (time_out > MAX_WAIT_TIMEOUT) {
						
						if (!b_daemon) {
							
							struct tm * local = localtime(&fd_A_time[i]);
							char time_buf[64];
							int len;
							
							len = sprintf(time_buf, "%d-%d-%d %d:%d:%d", local->tm_year+1900, local->tm_mon+1, local->tm_mday, 
																	 local->tm_hour, local->tm_min, local->tm_sec);
												 
							sin_size = sizeof(client_addr);

							getpeername(fd_A[i],(struct sockaddr *)&client_addr, &sin_size);
							inet_ntop(AF_INET, &client_addr.sin_addr, ipAddr, sizeof(ipAddr));
							
					
							printf("client[%d]:%d %s from: %s timeout:%d seconds\n", i, fd_A[i], ipAddr, time_buf, (int) time_out);
						}
						
						send(fd_A[i], "timeout", 7, 0);
						closesocket(fd_A[i]);
						
						fd_A[i] = 0;
						
						remove_count++;
					}
				}
			}
		}
		
		//resort the socket
		if (remove_count > 0) {
			int j=0;
			
			for (i = 0; i < conn_amount; i++) {
				if (fd_A[i]) {
					fd_A[j] = fd_A[i];
					fd_A_time[j] = fd_A_time[i];
					j++;
				}
			}

			for (i = j; i < conn_amount; i++) {
				fd_A[i] = 0;
			}

			conn_amount -= remove_count;
		}

		// check whether a new connection comes
		if (FD_ISSET(sock_fd, &fdsr)) {
			char ipAddr[128];
			const char * sIpAddr;
			
			new_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &sin_size);
			if (new_fd <= 0) {
				perror("accept");
				continue;
			}

			sIpAddr = inet_ntop(AF_INET, &client_addr.sin_addr, ipAddr, sizeof(ipAddr));
			// add to fd queue
			if (conn_amount < BACKLOG) {

				fd_A_time[conn_amount] = time(NULL);
				fd_A[conn_amount++] = new_fd;

				if (!b_daemon) {
					printf("new connection client[%d] %s:%d\n", conn_amount, sIpAddr, ntohs(client_addr.sin_port));
				}
				if (new_fd > maxsock)
					maxsock = new_fd;
			}
			else {
				saveOverflowLog(sIpAddr);
				
				if (!b_daemon) {
					printf("max connections arrived, close the client\n");
				}
				send(new_fd, "bye", 3, 0);
				closesocket(new_fd);
			}
		}
				
		showClients();
	}

	// close other connections
	for (i = 0; i < conn_amount; i++) {
		if (fd_A[i] != 0) {
			closesocket(fd_A[i]);
		}
	}

#ifdef WIN32
	WSACleanup();
#endif
	exit(0);
}

getip.c 如果要在Windows下编译请用VC新建一个简单项目,添加此文件即可;

在linux下编译请用:

 gcc -O2 -o getipd getip.c

在linux下通过以上命令编译后,输入 ./getipd -d 即以守护进程的方式运行。getipd 用到了8198端口,请注意修改防火墙的规则,打开此端口。

至此,一个属于自己的高效的动态域名解析系统就完成了。

所有代码可以在

GitHub - wenshui2008/ddnsUpdater: Aliyun dynamic domain name refresher,with getip(C&PHP) server side source code.

下载。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值