zoukankan      html  css  js  c++  java
  • DELPHI版传奇引擎学习菜鸟篇(applem2)02

    每天只学习一个知识点,也是一种进步.

    接着学习GShare.pas的实现部分,其实这个应该叫做GAMECENTER共享单元,我刚开始理解的是错误的,这是根据名字起的.

    在学习实现部分之前,声明部分还有一些变量:

    //虽然光看这些变量不可能全部知道代表什么,但是为了学习,还是注释一下
    var
      //下面4个应该是更新数据(格式)用的,默认为本机更新
      g_sDataListAddrs: string = '127.0.0.1';
      g_wDataListPort: Word = 18888;
      g_sDataListPassWord: string = '123456';
      g_boGetDataListOK: Boolean = False;
      //下面3个是获取更新列表用的,
      g_DataListReadBuffer: PChar;
      g_nDataListReadLength: Integer;
      g_GetDatList: TStringList;
    
      //下面6个很明显,从字面就能看出意思对应启动设置\窗口\按钮状态
      g_nFormIdx: Integer;
      g_IniConf: Tinifile;
      g_sButtonStartGame: string = '启动游戏服务器(&S)';
      g_sButtonStopGame: string = '停止游戏服务器(&T)';
      g_sButtonStopStartGame: string = '中止启动游戏服务器(&T)';
      g_sButtonStopStopGame: string = '中止停止游戏服务器(&T)';
      //下面对应的都是配置变量,主窗口都有对应的控件
      g_sConfFile: string = '.\Config.ini';
      g_sBackListFile: string = '.\BackupList.txt';
      g_sGameName: string = '测试引擎';
      g_sGameDirectory: string = '.\';
      g_sHeroDBName: string = 'HeroDB';
      g_sExtIPaddr: string = '127.0.0.1';
      g_sExtIPaddr2: string = '127.0.0.1';
      g_boAutoRunBak: Boolean = False;
      g_boCloseWuXin: Boolean = False;
      g_boIP2: Boolean = False;
      // 声明并初始化服务端配置结构,也许类似这样的应该定义为类,前边也好多
      g_Config: TConfig = (
          DBServer: (
            MainFormX: 0;
            MainFormY: 373;
            GatePort: 5100;
            ServerPort: 6000;
            GetStart: True;
            ProgramFile: 'DBServer.exe';
          );
          LoginSrv: (
            MainFormX: 252;
            MainFormY: 0;
            GatePort: 5500;
            ServerPort: 5600;
            MonPort: 3000;
            GetStart: True;
            ProgramFile: 'LoginSrv.exe';
          );
          M2Server:(
            MainFormX: 561;
            MainFormY: 0;
            GatePort: 5000;
            MsgSrvPort: 4900;
            GetStart: True;
            ProgramFile: 'M2Server.exe';
            ProgramFile: 'PlugTop.exe';
          );
          LogServer:(
            MainFormX: 252;
            MainFormY: 286;
            Port: 10000;
            GetStart: True;
            ProgramFile: 'LogDataServer.exe';
          );
    
           RunGate:(
            MainFormX: 437;
            MainFormY: 373;
            GetStart: (True, False, False, False, False, False, False, False);
            GatePort: (7200, 7201, 7202, 7203, 7204, 7205, 7206, 7207);
            ProgramFile: 'RunGate.exe';
          );
          SelGate:(
            MainFormX: 0;
            MainFormY: 180;
            GatePort: (7100, 7101);
            GetStart1: True;
            GetStart2: False;
            ProgramFile: 'SelGate.exe';
          );
          LoginGate:(
            MainFormX: 0;
            MainFormY: 0;
            GatePort: 7000;
            GetStart: True;
            ProgramFile: 'LoginGate.exe';
          );
           PlugTop:(
            MainFormX: 525;
            MainFormY:300;
            GetStart: True;
            ProgramFile: 'PlugTop.exe';
          );
        );
      //声明服务程序变量,暂时就这么理解吧
      DBServer: TProgram;
      LoginServer: TProgram;
      LogServer: TProgram;
      M2Server: TProgram;
      RunGate: array[0..MAXRUNGATECOUNT - 1] of TProgram;
      SelGate: TProgram;
      SelGate1: TProgram;
      LoginGate: TProgram;
      LoginGate2: TProgram;
      PlugTop: TProgram;
      //下面是检测程序运行状态的变量,暂时理解为心跳检测吧
      g_dwStopTick: LongWord;
      g_dwStopTimeOut: LongWord = 10000;
      g_dwM2CheckCodeAddr: LongWord;
      g_dwDBCheckCodeAddr: LongWord;
      g_BackUpManager: TBackUpManager;
      m_nBackStartStatus: Integer = 0;

    到此GShare.pas的声明部分结束,觉得还可以优化,接下来是实现部分,实现一共有5个函数\过程:

    procedure LoadConfig();//加载配置
    procedure SaveConfig();//保存配置
    {运行服务}
    function RunProgram(var ProgramInfo: TProgram; sHandle: string; dwWaitTime: LongWord): LongWord;
    {停止服务}
    function StopProgram(var ProgramInfo: TProgram; dwWaitTime: LongWord): Integer;
    {发送消息}
    procedure SendProgramMsg(DesForm: THandle; wIdent: Word; sSendMsg: string);

    加载保存配置就是读取和写入服务端里边的INI和TXT配置文件,启动停止服务发送数据(消息)用的是API:

    //读取配置信息
    procedure LoadConfig();
    begin
      //下面一堆都是读取INI文件,准备后续优化一下
      g_sGameDirectory := g_IniConf.ReadString(BasicSectionName, 'GameDirectory', g_sGameDirectory);
      g_sHeroDBName := g_IniConf.ReadString(BasicSectionName, 'HeroDBName', g_sHeroDBName);
      g_sGameName := g_IniConf.ReadString(BasicSectionName, 'GameName', g_sGameName);
      g_sExtIPaddr := g_IniConf.ReadString(BasicSectionName, 'ExtIPaddr', g_sExtIPaddr);
      g_sExtIPaddr2 := g_IniConf.ReadString(BasicSectionName, 'ExtIPaddr2', g_sExtIPaddr2);
      g_boAutoRunBak := g_IniConf.ReadBool(BasicSectionName, 'AutoRunBak', g_boAutoRunBak);
      g_boIP2 := g_IniConf.ReadBool(BasicSectionName, 'IP2', g_boIP2);
      g_boCloseWuXin := g_IniConf.ReadBool(BasicSectionName, 'CloseWuXin', g_boCloseWuXin);
    
      g_Config.DBServer.MainFormX := g_IniConf.ReadInteger(DBServerSectionName, 'MainFormX', g_Config.DBServer.MainFormX);
      g_Config.DBServer.MainFormY := g_IniConf.ReadInteger(DBServerSectionName, 'MainFormY', g_Config.DBServer.MainFormY);
      g_Config.DBServer.GatePort := g_IniConf.ReadInteger(DBServerSectionName, 'GatePort', g_Config.DBServer.GatePort);
      g_Config.DBServer.ServerPort := g_IniConf.ReadInteger(DBServerSectionName, 'ServerPort', g_Config.DBServer.ServerPort);
      g_Config.DBServer.GetStart := g_IniConf.ReadBool(DBServerSectionName, 'GetStart', g_Config.DBServer.GetStart);
    
      g_Config.LoginSrv.MainFormX := g_IniConf.ReadInteger(LoginSrvSectionName, 'MainFormX', g_Config.LoginSrv.MainFormX);
      g_Config.LoginSrv.MainFormY := g_IniConf.ReadInteger(LoginSrvSectionName, 'MainFormY', g_Config.LoginSrv.MainFormY);
      g_Config.LoginSrv.GatePort := g_IniConf.ReadInteger(LoginSrvSectionName, 'GatePort', g_Config.LoginSrv.GatePort);
      g_Config.LoginSrv.ServerPort := g_IniConf.ReadInteger(LoginSrvSectionName, 'ServerPort', g_Config.LoginSrv.ServerPort);
      g_Config.LoginSrv.MonPort := g_IniConf.ReadInteger(LoginSrvSectionName, 'MonPort', g_Config.LoginSrv.MonPort);
      g_Config.LoginSrv.GetStart := g_IniConf.ReadBool(LoginSrvSectionName, 'GetStart', g_Config.LoginSrv.GetStart);
    
      g_Config.M2Server.MainFormX := g_IniConf.ReadInteger(M2ServerSectionName, 'MainFormX', g_Config.M2Server.MainFormX);
      g_Config.M2Server.MainFormY := g_IniConf.ReadInteger(M2ServerSectionName, 'MainFormY', g_Config.M2Server.MainFormY);
      g_Config.M2Server.GatePort := g_IniConf.ReadInteger(M2ServerSectionName, 'GatePort', g_Config.M2Server.GatePort);
      g_Config.M2Server.MsgSrvPort := g_IniConf.ReadInteger(M2ServerSectionName, 'MsgSrvPort', g_Config.M2Server.MsgSrvPort);
      g_Config.M2Server.GetStart := g_IniConf.ReadBool(M2ServerSectionName, 'GetStart', g_Config.M2Server.GetStart);
    
      g_Config.LogServer.MainFormX := g_IniConf.ReadInteger(LogServerSectionName, 'MainFormX', g_Config.LogServer.MainFormX);
      g_Config.LogServer.MainFormY := g_IniConf.ReadInteger(LogServerSectionName, 'MainFormY', g_Config.LogServer.MainFormY);
      g_Config.LogServer.Port := g_IniConf.ReadInteger(LogServerSectionName, 'Port', g_Config.LogServer.Port);
      g_Config.LogServer.GetStart := g_IniConf.ReadBool(LogServerSectionName, 'GetStart', g_Config.LogServer.GetStart);
    
      g_Config.RunGate.MainFormX := g_IniConf.ReadInteger(RunGateSectionName, 'MainFormX', g_Config.RunGate.MainFormX);
      g_Config.RunGate.MainFormY := g_IniConf.ReadInteger(RunGateSectionName, 'MainFormY', g_Config.RunGate.MainFormY);
      g_Config.RunGate.GetStart[0] := g_IniConf.ReadBool(RunGateSectionName, 'GetStart1', g_Config.RunGate.GetStart[0]);
      g_Config.RunGate.GetStart[1] := g_IniConf.ReadBool(RunGateSectionName, 'GetStart2', g_Config.RunGate.GetStart[1]);
      g_Config.RunGate.GetStart[2] := g_IniConf.ReadBool(RunGateSectionName, 'GetStart3', g_Config.RunGate.GetStart[2]);
      g_Config.RunGate.GetStart[3] := g_IniConf.ReadBool(RunGateSectionName, 'GetStart4', g_Config.RunGate.GetStart[3]);
      g_Config.RunGate.GetStart[4] := g_IniConf.ReadBool(RunGateSectionName, 'GetStart5', g_Config.RunGate.GetStart[4]);
      g_Config.RunGate.GetStart[5] := g_IniConf.ReadBool(RunGateSectionName, 'GetStart6', g_Config.RunGate.GetStart[5]);
      g_Config.RunGate.GetStart[6] := g_IniConf.ReadBool(RunGateSectionName, 'GetStart7', g_Config.RunGate.GetStart[6]);
      g_Config.RunGate.GetStart[7] := g_IniConf.ReadBool(RunGateSectionName, 'GetStart8', g_Config.RunGate.GetStart[7]);
    
      g_Config.RunGate.GatePort[0] := g_IniConf.ReadInteger(RunGateSectionName, 'GatePort1', g_Config.RunGate.GatePort[0]);
      g_Config.RunGate.GatePort[1] := g_IniConf.ReadInteger(RunGateSectionName, 'GatePort2', g_Config.RunGate.GatePort[1]);
      g_Config.RunGate.GatePort[2] := g_IniConf.ReadInteger(RunGateSectionName, 'GatePort3', g_Config.RunGate.GatePort[2]);
      g_Config.RunGate.GatePort[3] := g_IniConf.ReadInteger(RunGateSectionName, 'GatePort4', g_Config.RunGate.GatePort[3]);
      g_Config.RunGate.GatePort[4] := g_IniConf.ReadInteger(RunGateSectionName, 'GatePort5', g_Config.RunGate.GatePort[4]);
      g_Config.RunGate.GatePort[5] := g_IniConf.ReadInteger(RunGateSectionName, 'GatePort6', g_Config.RunGate.GatePort[5]);
      g_Config.RunGate.GatePort[6] := g_IniConf.ReadInteger(RunGateSectionName, 'GatePort7', g_Config.RunGate.GatePort[6]);
      g_Config.RunGate.GatePort[7] := g_IniConf.ReadInteger(RunGateSectionName, 'GatePort8', g_Config.RunGate.GatePort[7]);
    
      g_Config.SelGate.MainFormX := g_IniConf.ReadInteger(SelGateSectionName, 'MainFormX', g_Config.SelGate.MainFormX);
      g_Config.SelGate.MainFormY := g_IniConf.ReadInteger(SelGateSectionName, 'MainFormY', g_Config.SelGate.MainFormY);
      g_Config.SelGate.GatePort[0] := g_IniConf.ReadInteger(SelGateSectionName, 'GatePort1', g_Config.SelGate.GatePort[0]);
      g_Config.SelGate.GatePort[1] := g_IniConf.ReadInteger(SelGateSectionName, 'GatePort2', g_Config.SelGate.GatePort[1]);
      g_Config.SelGate.GetStart1 := g_IniConf.ReadBool(SelGateSectionName, 'GetStart1', g_Config.SelGate.GetStart1);
      g_Config.SelGate.GetStart2 := g_IniConf.ReadBool(SelGateSectionName, 'GetStart2', g_Config.SelGate.GetStart2);
    
      g_Config.LoginGate.MainFormX := g_IniConf.ReadInteger(LoginGateSectionName, 'MainFormX', g_Config.LoginGate.MainFormX);
      g_Config.LoginGate.MainFormY := g_IniConf.ReadInteger(LoginGateSectionName, 'MainFormY', g_Config.LoginGate.MainFormY);
      g_Config.LoginGate.GatePort := g_IniConf.ReadInteger(LoginGateSectionName, 'GatePort', g_Config.LoginGate.GatePort);
      g_Config.LoginGate.GetStart := g_IniConf.ReadBool(LoginGateSectionName, 'GetStart', g_Config.LoginGate.GetStart);
    
      g_Config.PlugTop.MainFormX := g_IniConf.ReadInteger(PlugTopSectionName, 'MainFormX', g_Config.PlugTop.MainFormX);
      g_Config.PlugTop.MainFormY := g_IniConf.ReadInteger(PlugTopSectionName, 'MainFormY', g_Config.PlugTop.MainFormY);
      g_Config.PlugTop.GetStart := g_IniConf.ReadBool(PlugTopSectionName, 'GetStart', g_Config.PlugTop.GetStart);
    end;
    
    procedure SaveConfig();   //保存配置信息
    begin
      //没什么可注释的,写入INI
      g_IniConf.WriteString(BasicSectionName, 'GameDirectory', g_sGameDirectory);
      g_IniConf.WriteString(BasicSectionName, 'HeroDBName', g_sHeroDBName);
      g_IniConf.WriteString(BasicSectionName, 'GameName', g_sGameName);
      g_IniConf.WriteString(BasicSectionName, 'ExtIPaddr', g_sExtIPaddr);
      g_IniConf.WriteString(BasicSectionName, 'ExtIPaddr2', g_sExtIPaddr2);
      g_IniConf.WriteBool(BasicSectionName, 'AutoRunBak', g_boAutoRunBak);
      g_IniConf.WriteBool(BasicSectionName, 'IP2', g_boIP2);
      g_IniConf.WriteBool(BasicSectionName, 'CloseWuXin', g_boCloseWuXin);
    
      g_IniConf.WriteInteger(DBServerSectionName, 'MainFormX', g_Config.DBServer.MainFormX);
      g_IniConf.WriteInteger(DBServerSectionName, 'MainFormY', g_Config.DBServer.MainFormY);
      g_IniConf.WriteInteger(DBServerSectionName, 'GatePort', g_Config.DBServer.GatePort);
      g_IniConf.WriteInteger(DBServerSectionName, 'ServerPort', g_Config.DBServer.ServerPort);
      g_IniConf.WriteBool(DBServerSectionName, 'GetStart', g_Config.DBServer.GetStart);
    
      g_IniConf.WriteInteger(LoginSrvSectionName, 'MainFormX', g_Config.LoginSrv.MainFormX);
      g_IniConf.WriteInteger(LoginSrvSectionName, 'MainFormY', g_Config.LoginSrv.MainFormY);
      g_IniConf.WriteInteger(LoginSrvSectionName, 'GatePort', g_Config.LoginSrv.GatePort);
      g_IniConf.WriteInteger(LoginSrvSectionName, 'ServerPort', g_Config.LoginSrv.ServerPort);
      g_IniConf.WriteInteger(LoginSrvSectionName, 'MonPort', g_Config.LoginSrv.MonPort);
      g_IniConf.WriteBool(LoginSrvSectionName, 'GetStart', g_Config.LoginSrv.GetStart);
    
      g_IniConf.WriteInteger(M2ServerSectionName, 'MainFormX', g_Config.M2Server.MainFormX);
      g_IniConf.WriteInteger(M2ServerSectionName, 'MainFormY', g_Config.M2Server.MainFormY);
      g_IniConf.WriteInteger(M2ServerSectionName, 'GatePort', g_Config.M2Server.GatePort);
      g_IniConf.WriteInteger(M2ServerSectionName, 'MsgSrvPort', g_Config.M2Server.MsgSrvPort);
      g_IniConf.WriteBool(M2ServerSectionName, 'GetStart', g_Config.M2Server.GetStart);
    
      g_IniConf.WriteInteger(LogServerSectionName, 'MainFormX', g_Config.LogServer.MainFormX);
      g_IniConf.WriteInteger(LogServerSectionName, 'MainFormY', g_Config.LogServer.MainFormY);
      g_IniConf.WriteInteger(LogServerSectionName, 'Port', g_Config.LogServer.Port);
      g_IniConf.WriteBool(LogServerSectionName, 'GetStart', g_Config.LogServer.GetStart);
    
      g_IniConf.WriteInteger(RunGateSectionName, 'MainFormX', g_Config.RunGate.MainFormX);
      g_IniConf.WriteInteger(RunGateSectionName, 'MainFormY', g_Config.RunGate.MainFormY);
      g_IniConf.WriteBool(RunGateSectionName, 'GetStart1', g_Config.RunGate.GetStart[0]);
      g_IniConf.WriteBool(RunGateSectionName, 'GetStart2', g_Config.RunGate.GetStart[1]);
      g_IniConf.WriteBool(RunGateSectionName, 'GetStart3', g_Config.RunGate.GetStart[2]);
      g_IniConf.WriteBool(RunGateSectionName, 'GetStart4', g_Config.RunGate.GetStart[3]);
      g_IniConf.WriteBool(RunGateSectionName, 'GetStart5', g_Config.RunGate.GetStart[4]);
      g_IniConf.WriteBool(RunGateSectionName, 'GetStart6', g_Config.RunGate.GetStart[5]);
      g_IniConf.WriteBool(RunGateSectionName, 'GetStart7', g_Config.RunGate.GetStart[6]);
      g_IniConf.WriteBool(RunGateSectionName, 'GetStart8', g_Config.RunGate.GetStart[7]);
    
      g_IniConf.WriteInteger(RunGateSectionName, 'GatePort1', g_Config.RunGate.GatePort[0]);
      g_IniConf.WriteInteger(RunGateSectionName, 'GatePort2', g_Config.RunGate.GatePort[1]);
      g_IniConf.WriteInteger(RunGateSectionName, 'GatePort3', g_Config.RunGate.GatePort[2]);
      g_IniConf.WriteInteger(RunGateSectionName, 'GatePort4', g_Config.RunGate.GatePort[3]);
      g_IniConf.WriteInteger(RunGateSectionName, 'GatePort5', g_Config.RunGate.GatePort[4]);
      g_IniConf.WriteInteger(RunGateSectionName, 'GatePort6', g_Config.RunGate.GatePort[5]);
      g_IniConf.WriteInteger(RunGateSectionName, 'GatePort7', g_Config.RunGate.GatePort[6]);
      g_IniConf.WriteInteger(RunGateSectionName, 'GatePort8', g_Config.RunGate.GatePort[7]);
    
      g_IniConf.WriteInteger(SelGateSectionName, 'MainFormX', g_Config.SelGate.MainFormX);
      g_IniConf.WriteInteger(SelGateSectionName, 'MainFormY', g_Config.SelGate.MainFormY);
      g_IniConf.WriteInteger(SelGateSectionName, 'GatePort1', g_Config.SelGate.GatePort[0]);
      g_IniConf.WriteInteger(SelGateSectionName, 'GatePort2', g_Config.SelGate.GatePort[1]);
      g_IniConf.WriteBool(SelGateSectionName, 'GetStart1', g_Config.SelGate.GetStart1);
      g_IniConf.WriteBool(SelGateSectionName, 'GetStart2', g_Config.SelGate.GetStart2);
    
      g_IniConf.WriteInteger(LoginGateSectionName, 'MainFormX', g_Config.LoginGate.MainFormX);
      g_IniConf.WriteInteger(LoginGateSectionName, 'MainFormY', g_Config.LoginGate.MainFormY);
      g_IniConf.WriteInteger(LoginGateSectionName, 'GatePort', g_Config.LoginGate.GatePort);
      g_IniConf.WriteBool(LoginGateSectionName, 'GetStart', g_Config.LoginGate.GetStart);
    
      g_IniConf.WriteInteger(PlugTopSectionName, 'MainFormX', g_Config.PlugTop.MainFormX);
      g_IniConf.WriteInteger(PlugTopSectionName, 'MainFormY', g_Config.PlugTop.MainFormY);
      g_IniConf.WriteBool(PlugTopSectionName, 'GetStart', g_Config.PlugTop.GetStart);
    end;
    {启动服务,用的大部分是API}
    function RunProgram(var ProgramInfo: TProgram; sHandle: string; dwWaitTime: LongWord): LongWord;
    var
      StartupInfo: TStartupInfo; //获取窗口状态
      sCommandLine: string;      //程序完整路径
      sCurDirectory: string;     //程序目录
    begin
      Result := 0;
      FillChar(StartupInfo, SizeOf(TStartupInfo), #0); //这个虽然查看了API参考,还是不理解,暂时就认为它是初始化吧
      GetStartupInfo(StartupInfo);//获取进程的启动信息
      {格式化程序完整路径字符串}
      sCommandLine := format('%s%s %s %d %d', [ProgramInfo.sDirectory, ProgramInfo.sProgramFile, sHandle, ProgramInfo.nMainFormX, ProgramInfo.nMainFormY]);
      sCurDirectory := ProgramInfo.sDirectory; //取得程序运行目录
      if not CreateProcess(nil,  //如果启动服务失败返回错误代码
        PChar(sCommandLine),
        nil,
        nil,
        True,
        0,
        nil,
        PChar(sCurDirectory),
        StartupInfo,
        ProgramInfo.ProcessInfo) then
      begin
        Result := GetLastError();
      end;
      Sleep(dwWaitTime);  //等待
    end;
    {停止服务,这个函数很简单,不再注释}
    function StopProgram(var ProgramInfo: TProgram; dwWaitTime: LongWord): Integer;
    var
      dwExitCode: LongWord;
    begin
      Result := 0;
      dwExitCode := 0;
      if TerminateProcess(ProgramInfo.ProcessHandle, dwExitCode) then
      begin
        Result := GetLastError();
      end;
      Sleep(dwWaitTime);
    end;
    {这个是向指定程序发送数据}
    procedure SendProgramMsg(DesForm: THandle; wIdent: Word; sSendMsg: string);
    var
      SendData: TCopyDataStruct;
      nParam: Integer;
    begin
      nParam := MakeLong(0, wIdent);
      SendData.cbData := length(sSendMsg) + 1;
      GetMem(SendData.lpData, SendData.cbData);
      StrCopy(SendData.lpData, PChar(sSendMsg));
      SendMessage(DesForm, WM_COPYDATA, nParam, Cardinal(@SendData));
      FreeMem(SendData.lpData);
    end;
    {初始化和反初始化}
    initialization
      begin
        g_IniConf := Tinifile.Create(g_sConfFile);
      end;
    
    finalization
      begin
        g_IniConf.Free;
      end;

    主要是加载和保存配置过程过程重复的事情很多,可以考虑改进.

    整个GShare.pas单元学习完毕,接下来可以开始主单元文件学习了.

    关注过程,不知不觉就发现了结果原来如此...
  • 相关阅读:
    个人阅读作业
    软件工程基础/个人项目1
    个人阅读作业3
    个人阅读作业2
    代码复审
    软件工程:结对编程1
    个人阅读作业
    软工作业1:单词统计
    有关敏捷开发的一点感想[110617班 刘耀先]
    Pair Project: Elevator Scheduler [电梯调度算法的实现和测试][关于电梯调度算法的附加思考]:刘耀先-11061183,罗凡-11061174
  • 原文地址:https://www.cnblogs.com/iicc/p/5046424.html
Copyright © 2011-2022 走看看