zoukankan      html  css  js  c++  java
  • nothing

    // NMTaskInfo.cpp : 定义控制台应用程序的入口点。
    //

    #include "stdafx.h"
    #include "NMTaskInfo.h"
    #ifdef _WINDOWS_
    #include<time.h>
    #undef _WINDOWS_
    #endif
    ///////////////////////////全局变量定义区/////////////////////////////////////

    CThreadMutux thMutux;  //数据库连接池所用到锁
    CDbPool dbPool;    //数据库连接池
    SYS_INFO gSysInfo;   //全局配置变量
    //CHttpSock httpSocket;
    HANDLE handleMutex;

    //typedef CDataQueue<Task_Info> TTaskInfo;
    //TTaskInfo tTaskInfo(1000);
    //TSendInfo *vSendInfo=new TSendInfo();
    typedef CDataQueue<TSendInfo> QueueSendInfo;
    QueueSendInfo m_QueueSendInfo(5);//建立5个队列
    ///////////////////////////END END END //////////////////////////////////////

    /////////////////////////常量定义///////////////////////////////////////////

    #define CFG_FILE "NMTaskInfoCfg.ini"
    #define MAX_THREAD_NUM 256

    /////////////////////////////////////////////////////////////////////////////

    //////////////////////库文件////////////////////////////////////////////////

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

    /////////////////////////////////////////////////////////////////////////////

    int _tmain(int argc, _TCHAR* argv[])
    {
     printf("进入main\n");
     //预处理线程
     //HANDLE   _h_ProDataThread[MAX_THREAD_NUM];
     HANDLE   _h_ProDataThread;
     HANDLE  _h_GetDataThread;

     memset((void*)&gSysInfo,0,sizeof(SYS_INFO));
     gSysInfo.nExitFlag = 0;

     ReadCfgInfo();

     handleMutex =::CreateMutex(NULL,FALSE,(LPCWSTR)gSysInfo.szAppID);
     if(GetLastError()==ERROR_ALREADY_EXISTS){ 
      printf("应用程序已经在运行");
      return 0; 
     }

     //数据库连接
     //dbPool.SetConnInfo("UID=tnm;PWD=tnmadmin;DSN=test15",gSysInfo.nDataConnNum);
     dbPool.SetConnInfo("UID=tnm;PWD=tnmadmin;DSN=test15",10);
     
     if(dbPool.ConnectToPool()<0)
     {
      printf("连接失败!");
      return 0;
     }


     //开始进行处理程序线程,该程序包含一个线程,当我们队列里面的某一个数据时间到了的时候,它就开始执行这个操作
     _h_GetDataThread = CreateThread(NULL,NULL,GetDataThread,(LPVOID)NULL,0,NULL);
     if ( _h_GetDataThread==NULL )
     {
      printf("创建get数据线程失败!\r\n");
      return 0;
     }
     //开始新建读取数据库的线程
     //for(int i=0;i<gSysInfo.nMaxThread;i++)
     //{
     //_h_ProDataThread[i] = CreateThread(NULL,NULL,ProDataThread,(LPVOID)NULL,0,NULL);
     //}
        _h_ProDataThread = CreateThread(NULL,NULL,ProDataThread,(LPVOID)NULL,0,NULL);
     if ( _h_ProDataThread==NULL )
     {
      printf("创建pro数据线程失败!\r\n");
      return 0;
     }
     while(!gSysInfo.nExitFlag)
     {
      dbPool.ReconnectDb();  //重连数据库
      Sleep(1000);
     }

     /*if(_h_GetDataThread!=NULL)
     {
      printf("close getdata \n");
      WaitForSingleObject( _h_GetDataThread, INFINITE);
      CloseHandle(_h_GetDataThread);
     }*/

     /*for(int i=0;i<gSysInfo.nMaxThread;i++)
     {
      if(_h_ProDataThread[i]!=NULL)
      {
       printf("close prodata \n");
       WaitForSingleObject( _h_ProDataThread[i], INFINITE);
       CloseHandle(_h_ProDataThread[i]);
      }
     }*/
     /*if(_h_ProDataThread!=NULL)
      {
       printf("close prodata \n");
       WaitForSingleObject( _h_ProDataThread[i], INFINITE);
       CloseHandle(_h_ProDataThread[i]);
      }*/

     dbPool.DisconnectToPool();
     return 0;
    }


    DWORD WINAPI GetDataThread( LPVOID pdata)
    {

     char sql[1024];
     char szUpdateSql[1024];
     int nPool = -1;
     //Task_Info taskInfo;

     //1.定义两个变量.这两个应该定义得不够
     /*long nLogicID;
     char szSendContent[500];
     char szSendAddr[100];
     int  nLogicType;
     char szExecTime[32];*/

     double  ltmptask_id;    //任务ID
     double ltmpic_id;   //逻辑ID
     //下面几个是配置时间用的
     char tmpSendType[3]; //采集类型 M按月 W按周 D按天
     char tmpSendTime[20]; //确定是某一天(一般是按照星期,比如星期二、星期三)
     char tmpBeginTime[20];   //开始时间,如早上4:00
     char tmpEndTime[20];    //结束时间,如 早上10:00
     //end of time config
     char tmpSendAdd[201]; //发送的地址
     char tmpContent[201]; //发送的内容
     int nLogicDataType;  //数据数据类型 10http   11FTP
     int ntmpIsCheck;   //是否校验
     int ntmpValid;   //是否有效

     while(!gSysInfo.nExitFlag)
     {
      printf("queue tail:%d\t",m_QueueSendInfo.rear);
      TSendInfo *vSendInfo=new TSendInfo();
      printf("进入getData线程\n");
      //数据提取
      /* if(tTaskInfo.GetQueueSize()>900)
      {
      Sleep(1000);
      continue;
      }*/
      if(m_QueueSendInfo.GetQueueSize()>100)
      {
       Sleep(1000);
       continue;
      }
      otl_stream  otl_GetData;
      memset((void*)sql,0,sizeof(sql));
      //sprintf(sql,"select logic_title from tnm_logic_data where rownum<100");

      sprintf(sql,"select tTask.Task_Id,tTask.Logic_Id,tTask.Send_Type,tTask.Send_Time,tTask.Start_Time,tTask.End_Time,tLogic.SEND_ADD,tLogic.Logic_Content,tLogic.LOGIC_DATA_TYPE,tLogic.Is_Check,tLogic.Is_Valid from tnm_logic_data tLogic, tnm_task_info tTask where tLogic.Logic_Id = tTask.logic_id and tLogic.tnm_ne_Id = tTask.ne_id and tLogic.is_valid = 1 and tTask.is_valid = 1 and tLogic.is_check = 1");

      try
      {
       __int64 nLogicID=0;
       nPool = dbPool.GetDbFromPool();
       if(nPool==-1)
       {
        return nPool;
       }

       otl_GetData.open(100,sql,dbPool.tDbInfo[nPool].db);
       while(!otl_GetData.eof())
       {
        TSendInfo *vSendInfo=new TSendInfo();
        memset(tmpSendType,0,sizeof(tmpSendType));
        memset(tmpSendTime,0,sizeof(tmpSendTime));
        memset(tmpBeginTime,0,sizeof(tmpBeginTime));
        memset(tmpEndTime,0,sizeof(tmpEndTime));
        memset(tmpSendAdd,0,sizeof(tmpSendAdd));
        memset(tmpContent,0,sizeof(tmpContent));
        otl_GetData>>ltmptask_id>>ltmpic_id>>tmpSendType>>tmpSendTime>>tmpBeginTime>>tmpEndTime>>tmpSendAdd>>tmpContent>>nLogicDataType>>ntmpIsCheck>>ntmpValid;
        CUtil::trim(tmpSendType);
        CUtil::trim(tmpSendTime);
        CUtil::trim(tmpBeginTime);
        CUtil::trim(tmpEndTime);
        CUtil::trim(tmpSendAdd);
        CUtil::trim(tmpContent);
        vSendInfo->ntask_id=(__int64)ltmptask_id;
        vSendInfo->nlogic_id=(__int64)ltmpic_id;
        sprintf(vSendInfo->szSendType,"%s",tmpSendType);
        sprintf(vSendInfo->szSendTime,"%s",tmpSendTime);
        sprintf(vSendInfo->szBeginTime,"%s",tmpBeginTime);
        sprintf(vSendInfo->szEndtIime,"%s",tmpEndTime);
        sprintf(vSendInfo->szSendAdd,"%s",tmpSendAdd);
        sprintf(vSendInfo->szContent,"%s",tmpContent);
        vSendInfo->nLogicDataType=nLogicDataType;
        vSendInfo->nIsCheck=ntmpIsCheck;
        vSendInfo->nIsValid=ntmpValid;
        printf("执行完取得数据线程!\n");
        //将数据插入到队列中
        if(0==m_QueueSendInfo.WriteDataToQueue(vSendInfo)) //写入成功,则
        {
         printf("...正在将数据读入队列\r\n");
         // delete vSendInfo;
        }
        else
        {
         printf("...数据读入队列出错\r\n");
         return -1;
        }
        //开始执行更新操作
        memset((void*)szUpdateSql,0,sizeof(szUpdateSql));
        nLogicID=vSendInfo->nlogic_id;
        sprintf(szUpdateSql,"update tnm_task_info set is_valid=2 where logic_id=%lld",nLogicID);
        dbPool.ExecSQL(szUpdateSql); //执行更新操作
        delete vSendInfo;
       }
       //执行完成,更新数据库状态
          otl_GetData.close();
           dbPool.FreeDbToPool(nPool);
      }
      catch(otl_exception& p)
      {
       char szErrMsg[1024];
       memset((void*)szErrMsg,0,sizeof(szErrMsg));
       sprintf(szErrMsg,"%s",(char*)p.msg);
       dbPool.tDbInfo[nPool].nConnFlag = 2;
       return (-2);
      }
      Sleep(500);
     }
     return 0;
    }

    DWORD WINAPI ProDataThread( LPVOID pdata)
    {
     //TSendInfo *vSendInfo=new TSendInfo();
     printf("进入proData\n");
     char szUpdateSql[60];
     char szSql[600];
     int nPool=-1;
     char szTime[64];
     char szRecvData[1024];
     char szRetContent[1024]; //比对的信息
     //各个数据段对应的值
     while(!gSysInfo.nExitFlag)
     {
      TSendInfo *pSendInfo=new TSendInfo();
      static int i=0;
      __int64 nLogicId;
      __int64 lcheckId;
      otl_stream otl_ProData;
      int iFindRes;
      memset(szSql,0,sizeof(szSql));
      //线程运行,不断的取出 需要执行的任务
      sprintf(szSql,"select t.task_id as counts from tnm_task_info t where (t.is_valid = 1 and to_date(t.start_time,'yyyy-mm-dd hh24:mi:ss') <= sysdate and t.start_time is not null) and(to_date(t.end_time,'yyyy-mm-dd hh24:mi:ss')  >= sysdate and  t.end_time is not null) and ((t.send_type = 'D' or (t.send_type = 'M' and t.send_time = to_char(sysdate,'DD')) or (t.send_type = 'W' and t.send_time = to_char(to_number(to_char(sysdate,'D'))-1)))) order by t.insert_dt");
      //开始执行
      try
      {
       nPool = dbPool.GetDbFromPool();
       if(nPool==-1)
       {
        return nPool;
       }
       otl_ProData.open(100,szSql,dbPool.tDbInfo[nPool].db);
       while(!otl_ProData.eof())
       {
        //如果取出的数据不为空
        otl_ProData>>nLogicId;
        if(nLogicId>0)
        {
         //开始进行校验
         do
         {
          //m_QueueSendInfo.ReadNextDataFromQueue(pSendInfo,i++);
          iFindRes=m_QueueSendInfo.ReadDataFromQueue(pSendInfo);
         }
         while(pSendInfo->nlogic_id!=nLogicId);
         //{
          //开始执行发送等操作
          //判断
         if(iFindRes==0)
         {
          if(10==(pSendInfo->nLogicDataType))
          {
           /*
           httpSocket.InitEnv(NULL,vSendInfo->szSendAdd,80); //默认为80端口
           httpSocket.SetHttpTimeOut(5000000);
           if(httpSocket.SendPostData(vSendInfo->szContent))
           {
            printf("发送数据失败\n\r");
           }
           else
           {
            //取得返回的数据
            memset(szRecvData,0,sizeof(szRecvData));
            httpSocket.GetHeadData(szRecvData); //此时szRecvData保存服务器返回的数据
            //有数据返回
            if(strlen(szRecvData)>0)
            {
             //搜索数据库 
             otl_stream otl_logicCheck;
             memset((void*)szSql,0,sizeof(szSql));
             //sprintf(szSql,"select ret_content from tnm_logic_check where logic_id=%s and is_valid=1",vSendInfo->nlogic_id);
             sprintf(szSql,"select c1.check_id from tnm_log_check c1 where check_id not in(select c2.check_id from tnm_logic_check c2  where re_content like '%%s%' and  c1.logic_id=c2.logic_id and c2.logic_id=%d and c2.is_vaild=1",szRecvData,pSendInfo->nlogic_id);
             try
             {
              nPool=dbPool.GetDbFromPool();
              if(-1==nPool)
              {
               Sleep(2000);
               return nPool;
              }
              else
              {
               otl_logicCheck.open(100,szSql,dbPool.tDbInfo[nPool].db);
               if(!otl_logicCheck.eof()) //logic_id 一定要是唯一的,不然这里就会有错误
               {
                //说明有出错的情况存在
                otl_logicCheck>>lcheckId;
               }
               else
               {
                printf("检验未出错\n\r");
                break;
               }

               //进行消息校验,校验通过的时候就把任务采集表的数据更新为1
               //将数据插入到 报警接口表当中,暂时未做
               memset(szSql,0,sizeof(szSql));
               //返回的消息与校验库的消息一致
               if(strcmp(szRetContent,szRecvData))
               {
                memset((void*)szUpdateSql,0,sizeof(szUpdateSql));
                sprintf(szUpdateSql,"update tnm_task_info set is_valid=1,LAST_UPDATE_TIME=to_char(sysdate,'yyy-mm-dd hh24:mi:ss') where logic_id=%ld",vSendInfo->nlogic_id);
                dbPool.ExecSQL(szUpdateSql); //执行更新操作
               }
              }
             }
             catch(otl_exception &p)
             {
              char szMsg[1024];
              memset((void*)szMsg,0,sizeof(szMsg));
              sprintf(szMsg,"%s",(char*)p.msg);
              dbPool.tDbInfo[nPool].nConnFlag=2;
              return -2;
             }
            }
           }*/
          }
          else if(11==(int)(pSendInfo->szSendType))
          {
           //进行Ftp的发送操作
            printf("执行FTP操作\n");

          }
         //} //ZHANGXQ
         }
         else
         {
          printf("当前没有任务需要进行\n");
          Sleep(500);
         }
         }
        
       }
       ////TSendInfo *pSendInfo=new TSendInfo();
       ////第一步:取出时间,判断当前某一个时间段该执行操作,如果有,就发送并等待返回。返回的时候再把它和
       //memset(szTime,0,sizeof(szTime));
       ///*szTime=CUtil::getTime();*/
       //strcpy(szTime,CUtil::getTime());
       ////第二步:判断时间是否到了
       //m_QueueSendInfo.ReadDataFromQueue(vSendInfo); //获得队列的首元素
       ////时间到了


       //执行Sql语句判断是否有值
       //if(strcmp(vSendInfo->szExecTime,szTime))
       //{
        //为HTTP处理类型
        if(10==(pSendInfo->nLogicDataType))
        {
         /*
         httpSocket.InitEnv(NULL,vSendInfo->szSendAdd,80); //默认为80端口
         httpSocket.SetHttpTimeOut(5000000);
         if(httpSocket.SendPostData(vSendInfo->szContent))
         {
          printf("发送数据失败\n\r");
         }
         else
         {
          //取得返回的数据
          memset(szRecvData,0,sizeof(szRecvData));
          httpSocket.GetHeadData(szRecvData); //此时szRecvData保存服务器返回的数据
          //有数据返回
          if(strlen(szRecvData)>0)
          {
           //搜索数据库 
           otl_stream otl_logicCheck;
           memset((void*)szSql,0,sizeof(szSql));
           sprintf(szSql,"select ret_content from tnm_logic_check where logic_id=%s and is_valid=1",vSendInfo->nlogic_id);
           try
           {
            nPool=dbPool.GetDbFromPool();
            if(-1==nPool)
            {
             Sleep(2000);
             return nPool;
            }
            else
            {
             otl_logicCheck.open(100,szSql,dbPool.tDbInfo[nPool].db);
             while(!otl_logicCheck.eof()) //logic_id 一定要是唯一的,不然这里就会有错误
             {
              otl_logicCheck>>szRetContent;
             }
             //进行消息校验,校验通过的时候就把任务采集表的数据更新为1
             if(strlen(szRetContent))
             {
              //返回的消息与校验库的消息一致
              if(strcmp(szRetContent,szRecvData))
              {
               memset((void*)szUpdateSql,0,sizeof(szUpdateSql));
               sprintf(szUpdateSql,"update tnm_task_info set is_valid=1 where logic_id=%ld",vSendInfo->nlogic_id);
               dbPool.ExecSQL(szUpdateSql); //执行更新操作
              }
             }
            }
           }
           catch(otl_exception &p)
           {
            char szMsg[1024];
            memset((void*)szMsg,0,sizeof(szMsg));
            sprintf(szMsg,"%s",(char*)p.msg);
            dbPool.tDbInfo[nPool].nConnFlag=2;
            return -2;
           }
          }
         }*/
        }
       //} //zhangxq
       /*Sleep(10);
       otl_stream otl_getTaskData;
       memset((void*)szSql,0,sizeof(szSql));*/  //为何要变成空指针
       //sprintf(szSql,"select task_id,logic_id,ne_id,exec_time,is_valid from tnm_task_info where rownum<2");
       //开始执行
       //1.判断是否有空闲的数据库连接
       /*
       try
       {
       nPool=dbPool.GetDbFromPool();
       if((-1)==nPool)
       {
       Sleep(1000);
       return nPool;
       }
       else
       {
       //2.开始执行数据库操作
       otl_getTaskData.open(100,szSql,dbPool.tDbInfo[nPool].db);   
       //3.获取数据库的值
       while(!otl_getTaskData.eof())
       { //1.取出数据的值,注意数据类型要严格匹配
       long nTmpTaskID,nTmpLogicID,ntmpNeID;
       otl_getTaskData>>nTmpTaskID;
       //otl_getTaskData>>tmpTaskID>>tmpLogicID>>tmpNeID>>tmpExecTime>>nIsValid;
       //将这些数据添加到数据单元中
       int i=0;
       //itoa(nTmpTaskID,tmpTaskID,10); //把整形转为char*
       sprintf(tmpTaskID,"%ld",nTmpTaskID);
       Task_Info *vTaskInfo=new Task_Info;
       memset(vTaskInfo->szTaskID,0,sizeof(vTaskInfo->szTaskID));
       memset(vTaskInfo->szLogicID,0,sizeof(vTaskInfo->szLogicID));
       memset(vTaskInfo->szNeID,0,sizeof(vTaskInfo->szNeID));
       memset(vTaskInfo->)
       memset(vTaskInfo->szExecTime,0,sizeof(vTaskInfo->szExecTime));
       strcpy(vTaskInfo->szTaskID,tmpTaskID);
       strcpy(vTaskInfo->szLogicID,tmpLogicID);
       strcpy(vTaskInfo->szExecTime,tmpExecTime);
       strcpy(vTaskInfo->szNeID,tmpNeID);
       vTaskInfo->nIsValid=nIsValid;

       CUtil::trim(vTaskInfo->szTaskID);
       CUtil::trim(vTaskInfo->szLogicID);
       CUtil::trim(vTaskInfo->szExecTime);
       CUtil::trim(vTaskInfo->szNeID);
       //添加节点
       tTaskInfo.WriteDataToQueue(vTaskInfo);
       delete vTaskInfo;
       }
       //把数据放置到双向队列之后,我们将有处理的那些的标示更为成2
       //printf("操作结果:%s",szTaskData);
       }
       }*/

       otl_ProData.close();
       dbPool.FreeDbToPool(nPool);
       Sleep(100);
      }
      catch(otl_exception &p)
      {
      
      }
      delete pSendInfo;
     }
    return 0;
    }

    int ReadCfgInfo()
    {
     int nRetCode = 0;
     char szTmp[20];
     //DataBase
     nRetCode = ReadConfig(CFG_FILE,"[Database]","connstr",gSysInfo.szConnData);

     //ConnNum
     memset((void*)szTmp,0,sizeof(szTmp));
     nRetCode = ReadConfig(CFG_FILE,"[Database]","ConnNum",szTmp);
     gSysInfo.nDataConnNum = atoi(szTmp);
     if(gSysInfo.nDataConnNum<=0) gSysInfo.nDataConnNum = 1;

     //AppTitle
     nRetCode = ReadConfig(CFG_FILE,"[App]","AppTitle",gSysInfo.szAppTitle);
     nRetCode = ReadConfig(CFG_FILE,"[App]","AppID",gSysInfo.szAppID);

     //
     //ConnTimeOut
     memset((void*)szTmp,0,sizeof(szTmp));
     nRetCode = ReadConfig(CFG_FILE,"[TimeOut]","ConnTimeOut",szTmp);
     gSysInfo.nConnTimeOut = atoi(szTmp);
     if(gSysInfo.nConnTimeOut<=0) gSysInfo.nConnTimeOut = 20;

     //SendTimeOut
     memset((void*)szTmp,0,sizeof(szTmp));
     nRetCode = ReadConfig(CFG_FILE,"[TimeOut]","SendTimeOut",szTmp);
     gSysInfo.nSendTimeOut = atoi(szTmp);
     if(gSysInfo.nSendTimeOut<=0) gSysInfo.nSendTimeOut = 20;

     //SendTimeOut
     memset((void*)szTmp,0,sizeof(szTmp));
     nRetCode = ReadConfig(CFG_FILE,"[TimeOut]","RecvTimeOut",szTmp);
     gSysInfo.nRecvTimeOut = atoi(szTmp);
     if(gSysInfo.nRecvTimeOut<=0) gSysInfo.nRecvTimeOut = 20;

     //Thread
     memset((void*)szTmp,0,sizeof(szTmp));
     nRetCode = ReadConfig(CFG_FILE,"[Thread]","MAX_THREAD_NUM",szTmp);
     gSysInfo.nMaxThread = atoi(szTmp);
     if(gSysInfo.nMaxThread<=0) gSysInfo.nMaxThread = 1;
     if(gSysInfo.nMaxThread>MAX_THREAD_NUM) gSysInfo.nMaxThread = MAX_THREAD_NUM;

     nRetCode = ReadConfig(CFG_FILE,"[Log]","LogPath",gSysInfo.szLogPath);
     //SendTimeOut
     memset((void*)szTmp,0,sizeof(szTmp));
     nRetCode = ReadConfig(CFG_FILE,"[Log]","LogLevel",szTmp);
     gSysInfo.nLogLevel = atoi(szTmp);
     if(gSysInfo.nLogLevel<=0) gSysInfo.nLogLevel = 1;


     return 0;
    }

    int ReadConfig(char *file,char* title, char* token, char* value)
    {
     char  buffer[1024];
     char  *readpoint,*ptr;
     char  tempstr[256];
     FILE  *fp;
     int   i;
     int   length;

     memset(tempstr,0,256);
     memset(buffer, 0,1024);
     if((fp=fopen(file,"r"))==NULL)
     {
      // printf("无法打开客户的配置文件,程序终止!");
      return -1;
     }
     fseek(fp,0l,SEEK_SET);
     i=fread(buffer,1024,1,fp);
     ptr = buffer;
     readpoint=(char*)strstr((const char *)ptr,title);
     if(readpoint!=NULL)
     {
      ptr = readpoint + strlen(title);
      readpoint=(char*)strstr((const char *)ptr,token);
      if(readpoint!=NULL)
      {
       length=strlen(token);
       for(i=0;i<256;i++)
       {
        if (*(readpoint+length+i)!='\n')
        {
         tempstr[i]=*(readpoint+length+i);
        }
        else
        {
         tempstr[i]='\0';
         break;
        }
       }
      }
     }
     strcpy(value,tempstr);
     fclose(fp);
     return 0;
    }

  • 相关阅读:
    DVWA的安装及报错解决
    隐写工具F5-steganography的使用
    python skimage库的安装
    密码学笔记——zip明文攻击
    密码学笔记-一段base64wp
    kali中网卡、ssh、apache的配置与开启
    密码学笔记——希尔密码
    密码学笔记——playfair密码
    使用electron-packager electron-builder electron-updater 打包vue项目,支持在线更新
    搭建vue脚手架,包含Axios、qs、Element-UI、mock等插件的安装配置
  • 原文地址:https://www.cnblogs.com/xianqingzh/p/1561405.html
Copyright © 2011-2022 走看看