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

基于阿里云Aliddns动态域名解析的客户端PHP实现与服务器端(包含C与PHP)实现很多朋友的公司或家里有一台上网的机器,这些上网的机器有些能够获得公网IP,但是这些IP通常不固定。大家都想充分利用这些上网设备的网络能力来搭建服务器环境,但由于IP地址老是变化,因此,即使是给这些机器分配了域名,也时常无法访问。于是,很多人想到了动态域名解析,即域名不变,IP地址变化,域名解析记录能够跟随IP地址变化,目前市场上有几种商业的解析方案实现,例如花生壳,更多的就不举例了,避免给他们做免费广告。这些都要收费,而且可能要通过CNAME(将您的域名解析成别人的域名)方式…

大家好,又见面了,我是你们的朋友全栈君。

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

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

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

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

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

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

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

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

<?phpdate_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阿里云分配给你的,只要您能够登录阿里云的控制台即可获取。获取位置如下:

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

公网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控制台窗口的助手程序,官方网址是:

https://github.com/wenshui2008/RunHiddenConsole

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

php dnsupdater.php &

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

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

<?phpdate_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>#ifdef WIN32#include <WinSock2.h>#include <WS2tcpip.h>#else#include <unistd.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#define closesocket(s) close(s)#endif  #define MYPORT 8198    // the port users will be connecting to #define BACKLOG 5     // how many pending connections queue will hold #define BUF_SIZE 512 int fd_A[BACKLOG];    // accepted connection fdint conn_amount = 0;    // current connection amount void showclient(){    int i;  printf("client amount: %d\n", conn_amount); for (i = 0; i < BACKLOG; i++) {     printf("[%d]:%d  ", i, fd_A[i]);    }   printf("\n\n");} 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]; 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);} #ifdef _WIN32void 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 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,b_daemon = 0;   char buf[BUF_SIZE]; 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],"-?") || !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);    }   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 = 30;     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) {          printf("timeout\n");            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                  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;                   char ipAddr[128];                   if (ret < BUF_SIZE)                     memset(&buf[ret], '\0', 1);                 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) {                        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;                    }               }           }       }       //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];                  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)) {         new_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &sin_size);           if (new_fd <= 0) {              perror("accept");               continue;           }           // add to fd queue          if (conn_amount < BACKLOG) {                char ipAddr[128];               fd_A[conn_amount++] = new_fd;               printf("new connection client[%d] %s:%d\n", conn_amount,                    inet_ntop(AF_INET, &client_addr.sin_addr, ipAddr, sizeof(ipAddr)), ntohs(client_addr.sin_port));                if (new_fd > maxsock)                   maxsock = new_fd;           }           else {              printf("max connections arrived, exit\n");              send(new_fd, "bye", 3, 0);              closesocket(new_fd);                break;          }       }                       showclient();   }   // 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端口,请注意修改防火墙的规则,打开此端口。

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

所有代码可以在

https://github.com/wenshui2008/dnsupdater

下载。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/137403.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • QTabWidget 控件样式

    QTabWidget 控件样式1、转载一篇当tab页多时,左侧的曲线问题。下面是原文:当tab个数大于一定个数时,会出现如下图左侧白线所示,这个是Qt自带的,作用是点击回到第一个tab隐藏方法:设置qssQTabBar::tear{width:0px;border:none;}原文链接:https://blog.csdn.net/qq411633267/article/details/1056847582、通用样式:…

    2022年10月25日
  • linux局域网不同网段ip互通,linux环境中,两个不同网段的机器互通「建议收藏」

    linux局域网不同网段ip互通,linux环境中,两个不同网段的机器互通「建议收藏」环境如下:host1单网卡eth0172.24.100.15/16host2双网卡eth0172.24.100.14/16eth1192.168.122.214/24host3单网卡eth0192.168.122.215/24整个环境如下图:要求:让host1和host3互通,也就是host1能ping通host3,host3也能ping通host1解决:第一,在hos…

  • ubuntu 20.04中文输入法安装

    ubuntu 20.04中文输入法安装sudoapt-getinstallfcitx-googlepinyin

  • 国内外常用公共NTP网络时间同步服务器地址[通俗易懂]

    国内外常用公共NTP网络时间同步服务器地址[通俗易懂]【腾讯云】热门云产品首单特惠秒杀,1核2G云服务器首年38元目录太长不看NTPPoolProjectNTP.ORG.CNNTP授时快速域名服务HSDN(HomeServerDataNetwork)本地服务器数据网络企业阿里巴巴腾讯微软苹果谷歌FacebookCloudflare高通HurricaneElectric飓风电气MSK-IX(MoscowInterneteXchange)莫斯科网络交换INTERNET…

  • windows环境搭建web服务器(IIS)

    windows环境搭建web服务器(IIS)windows环境下如何搭建web服务器,百度或者谷歌一下都会有很多教程和资源可以参考。这里我也记载一下过程,便于大家参考。至于什么是web服务器,为什么需要web服务器,这里不太明白的也可以百度一下。简单的说就是需要一个能够处理HTTP协议的互联网程序,当做好一个网站后将其放在这个程序包里。如果指定了这个程序所在电脑的IP地址,就可以用浏览器来显示这个网站了。通常这个程序所在的电脑位置我们称之为…

  • 2015年逻辑真题难度(2015年逻辑真题)

    说说你对数据库读写分离的理解读写分离,基本的原理是让主数据库处理事务性增、改、删操作(INSERT、UPDATE、DELETE),而从数据库处理SELECT查询操作。数据库复制被用来把事务性操作导致的变更同步到集群中的从数据库。为什么要分库、分表、读写分?单表的数据量限制,当单表数据量到一定条数之后数据库性能会显著下降。数据多了之后,对数据库的读、写就会很多。分库减少单台数据库的压力。接触过几个分库分表的系统,都是通过主键进行散列分裤分表的。这类数据比较特殊,主键就是唯一的获取该条信息的主要途径。比如

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号