学習ノート - 分散型デジタル華容路(第2部)

学習ノート - 分散型デジタル華容路(第2部)

[[427573]]

詳細については、以下をご覧ください。

51CTOとHuaweiが共同で構築したHongmengテクノロジーコミュニティ

https://harmonyos..com

序文

また来ましたよ。最近かなり忙しかったので、長い間この記事を書いていませんでした。国慶節の休暇中にしか時間を取って書くことができません。前回の2つの記事の準備に続き、この記事では分散型デジタル華龍島の2人用モードを実装します。以前のものについては、学習ノート「分散型デジタル華容路(中)」を参照してください。

今日から勉強を始めましょう。

[[427574]]

文章

したがって、2人プレイモードでは、どのように同期するかが最も重要な問題になります。私たちのゲームでは、分散データベースを使用して 2 つのデバイス間でデータを同期します。

分散データベースを実装する場合は、まずいくつかの変数を定義する必要があります。

  1. プライベート静的最終 HiLogLabel TAG = new HiLogLabel(HiLog.LOG_APP,0x12345, "signal" );
  2. プライベートスタティック  int難易度 = 3;
  3. プライベート DirectionalLayout レイアウト;
  4. プライベートスタティック 整数長さ;
  5. プライベート静的最終int間隔 = 5;
  6. プライベート静的最終int  = 32;
  7. プライベート静的最終int  トップ= 300;
  8. プライベート静的最終intマージン = 15;
  9. プライベートスタティック 整数長さ1;
  10. プライベート静的最終int left1 = 32;
  11. プライベート静的最終int top1 = 1350;
  12. プライベート静的最終int margin1 = 10;
  13. プライベートスタティック 整数row_a0;
  14. プライベートスタティック a0の整数値。
  15. プライベートスタティック 整数row_b0;
  16. プライベートスタティック b0の整数値。
  17. プライベートフロートstartX;
  18. プライベートフロートstartY;
  19. プライベート静的タイマータイマー;
  20. プライベート静的タイマー updatetimer;
  21. プライベート静的タイマー restarttimer;
  22. プライベート静的タイマーバックタイマー;
  23. プライベート静的テキストtimetext;
  24. プライベート静的テキストmaxtext;
  25. プライベート静的テキスト wintext;
  26. プライベートスタティック 整数 時間;
  27. プライベートスタティック 整数 ;
  28. プライベートスタティック 整数秒;
  29. プライベートスタティック 整数ミリ秒;
  30. プライベートスタティック 起動 = 0;
  31. プライベートスタティック  int戻る = 0;
  32. プライベートスタティック 最大時間 = 23;
  33. プライベートスタティック 整数最大値 = 59;
  34. プライベートスタティック 整数最大秒 = 59;
  35. プライベートスタティック 整数最大ミリ秒 = 99;
  36. プライベートスタティック  int [][] グリッドa;
  37. プライベートスタティック  int [][] グリッドb;
  38. プライベート静的最終文字列STROE_ID = "data" ;
  39. プライベート静的文字列 randomstr = "" ;
  40. プライベート静的文字列の勝者 = "" ;
  41. プライベート静的KvManager kvManager;
  42. プライベート静的文字列 strhour = "" ;
  43. プライベート静的文字列 strmin = "" ;
  44. プライベート静的文字列 strsec = "" ;
  45. プライベート静的文字列 strmsec = "" ;
  46. プライベート静的文字列テキスト = "一時停止" ;
  47. プライベート SingleKvStore シングルKvストア;
  48. プライベート静的ボタン button_moveback;
  49. プライベート静的ブール値 isLocal;

次のステップは分散データベースを書くことです

  1. private KvManager createManger(){//補助クラス
  2. KvManager マネージャー = null ;
  3. 試す{
  4. KvManagerConfig config = 新しい KvManagerConfig(this);
  5. マネージャー = KvManagerFactory.getInstance().createKvManager(config);
  6. } キャッチ (KvStoreException 例外) {
  7. HiLog.info(タグ、 「エラー」 );
  8. }
  9. リターンマネージャー;
  10. }
  11.  
  12. プライベート SingleKvStore createDb(KvManager kvManager) // データベース
  13. SingleKvStore kvStore = null ;
  14. 試す{
  15. オプション options = new Options();
  16. options.setCreateIfMissing( true ).setEncrypt( false ).setKvStoreType(KvStoreType.SINGLE_VERSION);
  17. kvStore = kvManager.getKvStore(オプション、STROE_ID);
  18. } キャッチ (KvStoreException 例外) {
  19. HiLog.info(タグ、 「エラー」 );
  20. }
  21. kvStoreを返します
  22. }
  23. private void subscribeDb(SingleKvStore singleKvStore) サブスクライブ
  24. クラス KvStoreObserveClient は KvStoreObserver を実装します {
  25. @オーバーライド
  26. パブリックvoid onChange(ChangeNotification通知) {
  27.               
  28. }
  29. }
  30. KvStoreObserver kvStoreObserverClient = 新しい KvStoreObserveClient();
  31. 単一のKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_ALL、kvStoreObserverClient);
  32. }
  33.  
  34. プライベートvoid initDbManager() {
  35. kvManager = createManger();
  36. 単一のKvStore = createDb(kvManager);
  37. subscribeDb(シングルKvStore);
  38. }

データベースに書き込むための関数を 2 つと、データベースから読み取るための関数を 1 つ追加で記述します。

  1. プライベートint queryContact_int(文字列キー) {
  2. 試す {
  3. singleKvStore.getInt(キー)を返します
  4. } キャッチ (KvStoreException 例外) {
  5. HiLog.info(TAG, "int error" + exception.getMessage());
  6. -1 を返します
  7. }
  8. }
  9. プライベート文字列queryContact_String(文字列キー) {
  10. 試す {
  11. singleKvStore.getString(キー)を返します
  12. } キャッチ (KvStoreException 例外) {
  13. HiLog.info(TAG, "文字列エラー" + exception.getMessage());
  14. 戻る ヌル;
  15. }
  16. }
  17.  
  18. プライベートvoid writeData_String(文字列キー、文字列値) {
  19. if (キー== null ||キー.isEmpty() || 値 == null || 値.isEmpty())
  20. 戻る;
  21. singleKvStore.putString(キー、値 );
  22. }
  23. プライベートvoid writeData_int(文字列キー int値) {
  24. if (キー== null ||キー.isEmpty()) {
  25. 戻る;
  26. }
  27. singleKvStore.putInt(キー, 値);
  28. }

次に、データベースからレコードを読み取る関数を記述します。ゲームが開始すると、その順序で最も速い記録が読み取られます。

  1. パブリックボイドgetrecord() {
  2. if (queryContact_int( "時間" + 難易度) != -1)
  3. maxhour = queryContact_int( "時間" + 難易度);
  4. それ以外 
  5. 最大時間 = 23;
  6. if (queryContact_int( "min" + 難易度) != -1)
  7. maxmin = queryContact_int( "min" + 難易度);
  8. それ以外 
  9. 最大最小 = 59;
  10. if (queryContact_int( "sec" + 難易度) != -1)
  11. maxsec = queryContact_int( "秒" + 難易度);
  12. それ以外 
  13. 最大秒数 = 59;
  14. if (queryContact_int( "msec" + 難易度) != -1)
  15. maxmsec = queryContact_int( "msec" + 難易度);
  16. それ以外 
  17. 最大ミリ秒 = 99;
  18. }

次に、配列の初期化を開始し、あるデバイスの初期化された配列をデータベースに書き込み、別のデバイスにデータベース内のデータを読み取らせ、それを使用してデバイスの配列を初期化します。

  1. パブリックボイドcreateGrids() {
  2. ランダム文字列 = "" ;
  3. if (isLocal) {
  4. 整数ランダム;
  5. 整数i = 0;
  6. while(i < 難易度 * 難易度 * 5) {
  7. ランダム = ( int )Math.floor(Math.random() *4);
  8. ランダムstr += ランダム;
  9.  
  10. temp_row を row_a0 にセットします
  11. 列a0term_columnを追加します。
  12.  
  13. if(ランダム == 0){
  14. グリッドを変更します(行_a0 - 1、列_a0);
  15. }そうでない場合(ランダム == 1){
  16. グリッドを変更します(行_a0 + 1、列_a0);
  17. }そうでない場合(ランダム == 2){
  18. グリッドを変更します(行_a0、列_a0 - 1);
  19. }そうでない場合(ランダム == 3){
  20. グリッドを変更します(行_a0、列_a0 + 1);
  21. }
  22. if(temp_row != row_a0 || tem_column != column_a0){
  23. 私は++;
  24. }
  25. }
  26. HiLog.info(タグ、ランダム文字列);
  27. writeData_String( "ランダム文字列"​​ ,ランダム文字列);
  28. }それ以外{
  29. )の間{
  30. if (queryContact_String( "randomstr" ) != null && !queryContact_String( "randomstr" ).isEmpty()) {
  31. 壊す;
  32. }
  33. }
  34. ランダム文字列 = queryContact_String( "ランダム文字列"​​ );
  35. HiLog.info(タグ、 "ランダム文字列: " +ランダム文字列);
  36. 整数ランダム;
  37. 整数i = 0;
  38. while(i < randomstr.length()) {
  39. ランダム = ランダムstr.charAt(i) - '0' ;
  40. if(ランダム == 0){
  41. グリッドを変更します(行_a0 - 1、列_a0);
  42. }そうでない場合(ランダム == 1){
  43. グリッドを変更します(行_a0 + 1、列_a0);
  44. }そうでない場合(ランダム == 2){
  45. グリッドを変更します(行_a0、列_a0 - 1);
  46. }そうでない場合(ランダム == 3){
  47. グリッドを変更します(行_a0、列_a0 + 1);
  48. }
  49. 私は++;
  50. }
  51. singleKvStore.putString( "randomstr" , "" );
  52. }
  53. for ( int row = 0; row < 難易度; row++) {
  54. int  = 0;<難易度;++) {
  55. grids_b[行][] = grids_a[行][];
  56. }
  57. }
  58. 行b0 = 行a0;
  59. 列b0 = 列a0;
  60. HiLog.info(タグ、 "row_a0: " + row_a0 + " column_a0: " + column_a0);
  61. }

次のステップは、配列内の数字を描画することです。

  1. パブリックvoid drawGrids() {
  2. ComponentContainer の LayoutConfig を新しい LayoutConfig に追加します。
  3.  
  4. Component.DrawTask タスク = 新しい Component.DrawTask() {
  5. @オーバーライド
  6. public void onDraw(Component コンポーネント、Canvas キャンバス) {
  7. ペイント paint = new Paint();
  8.  
  9. カラーバックカラー = new Color(Color.rgb(151,75,49));
  10. 背景色を設定します。
  11. RectFloat rect = new RectFloat(- 余白、- 余白、長さ * 難易度 + 間隔 * (難易度 - 1) ++ 余白、長さ * 難易度 + 間隔 * (難易度 - 1) ++ 余白);
  12. キャンバスに矩形を描画します。
  13.  
  14. for ( int row = 0; row < 難易度; row++) {
  15. int  = 0;< 難易度;++) {
  16. 色の背景色 = new Color(Color.rgb(229,188,132));
  17. 背景色を設定します。
  18. RectFloat rectFloat = new RectFloat(+* (長さ + 間隔)、+ 行 * (長さ + 間隔)、+ 長さ +* (長さ + 間隔)、+ 長さ + 行 * (長さ + 間隔));
  19. キャンバスに矩形を描画します。
  20.  
  21. 色番号color = new Color(Color.rgb(140,85,47));
  22. paint.setColor(数値色);
  23. paint.setTextSize(長さ / 2);
  24. if(grids_a[行][] != 0){
  25. if(grids_a[行][] < 10){
  26. canvas.drawText(paint, Integer .toString(grids_a[row][ column ]), left + column * (length + interval) + length / 12 * 5, top + row * (length + interval) + length / 3 * 2);
  27. }それ以外{
  28. canvas.drawText(paint, Integer .toString(grids_a[row][ column ]), left + column * (length + interval) + length / 12 * 3, top + row * (length + interval) + length / 3 * 2);
  29. }
  30. }
  31. }
  32. }
  33.  
  34. 背景色を設定します。
  35. 長さ1 = 600 / 難易度 - 間隔;
  36. RectFloat rect1= new RectFloat(left1 - margin1, top1 - margin1, length1 * 難易度 + 間隔 * (難易度 - 1) + left1 + margin1, length1 * 難易度 + 間隔 * (難易度 - 1) + top1 + margin1);
  37. キャンバスに矩形を描画します。
  38. for ( int row = 0; row < 難易度; row++) {
  39. int  = 0;< 難易度;++) {
  40. 色 backgroundcolor1 = new Color(Color.rgb(229,188,132));
  41. 背景色1を設定します。
  42. RectFloat rectFloat = new RectFloat(left1 + column * (length1 + interval), top1 + row * (length1 + interval), left1 + length1 + column * (length1 + interval), top1 + length1 + row * (length1 + interval));
  43. キャンバスに矩形を描画します。
  44.  
  45. 色番号color1 = new Color(Color.rgb(140,85,47));
  46. paint.setColor(数値色1);
  47. ペイント.setTextSize(長さ1 / 2);
  48. if(grids_b[行][] != 0){
  49. if(grids_b[行][] < 10){
  50. canvas.drawText(paint, Integer .toString(grids_b[row][ column ]),left1 + column * (length1 + interval) + length1 / 12 * 5,top1 + row * (length1 + interval) + length1 / 3 * 2);
  51. }それ以外{
  52. canvas.drawText(paint, Integer .toString(grids_b[row][ column ]),left1 + column * (length1 + interval) + length1 / 12 * 3,top1 + row * (length1 + interval) + length1 / 3 * 2);
  53. }
  54. }
  55. }
  56. }
  57. }
  58. };
  59.  
  60. レイアウトにタスクを追加します。
  61. UIContent を設定します。
  62. }

次のステップは、時間とボタンを描画することです。

  1. パブリックボイド描画() {
  2. maxtext = 新しいテキスト(これ);
  3. テキストの最大サイズを設定します。
  4. テキストサイズを80に設定します。
  5. maxtext.setMarginTop(40);
  6. maxtext.setMarginLeft(140);
  7. レイアウトにコンポーネントを追加します(最大テキスト)。
  8.  
  9. timetext = 新しいテキスト(これ);
  10. timetext.setText( "時間: 00:00:00:00" );
  11. タイムテキスト.setTextSize(80);
  12. 時間テキスト.setMarginTop(10);
  13. 時間テキスト.setMarginLeft(230);
  14. レイアウトにコンポーネントを追加します。
  15.  
  16. ShapeElement の背景 = 新しい ShapeElement();
  17. 背景.setRgbColor(新しいRgbColor(138,70,50));
  18. 背景.setCornerRadius(100);
  19.  
  20. ボタン button_again = new Button(this);
  21. button_again.setText( "再起動" );
  22. button_again.setTextAlignment(TextAlignment.CENTER);
  23. button_again.setTextColor(Color.WHITE);
  24. ボタンをもう一度押します。テキストサイズを100に設定します。
  25. ボタンをもう一度クリックします。
  26. ボタンをもう一度設定します。左余白を設定します(730);
  27. ボタンをもう一度設定します。パディングを 30, 0, 30, 0 に設定します。
  28. button_again.setBackground(背景);
  29. button_again.setClickedListener(新しいComponent.ClickedListener() {
  30. @オーバーライド
  31. パブリックvoid onClick(コンポーネント コンポーネント) {
  32. レコードを取得します。
  33. writeData_int( "再起動" ,1);
  34. }
  35. });
  36. レイアウトにコンポーネントを追加します(ボタンをもう一度)。
  37.  
  38. ボタン button_back = new Button(this);
  39. button_back.setText( "戻る" );
  40. button_back.setTextAlignment(TextAlignment.CENTER);
  41. ボタンを戻すには、テキストの色を白に設定します。
  42. ボタンを戻す。テキストサイズを100に設定する。
  43. ボタンの左余白を設定します(730);
  44. ボタンを戻す。上マージンを90に設定する。
  45. ボタンの後ろのパディングを設定します(30, 0, 30, 0);
  46. button_back.setBackground(背景);
  47. button_back.setClickedListener(新しいComponent.ClickedListener() {
  48. @オーバーライド
  49. パブリックvoid onClick(コンポーネント コンポーネント) {
  50.  
  51. }
  52. });
  53. レイアウトにコンポーネントを追加します(ボタンバック);
  54.  
  55. UIContent を設定します。
  56. }

これが私たちのレンダリングです。実行して、まったく同じかどうかを確認することもできます。すべてが同じであることを確認した後でのみ、手順を追って続行してください。

比較的重要な問題である初期同期の問題はすでに解決しています。次に、ゲーム機能を完成させていきます。ゲーム機能を完成させる前に、ゲームが成功したかどうかを判断する関数を記述する必要があります。

  1. パブリックブール型ゲーム成功() {
  2. int [][] Grids = new int [難易度][難易度];
  3. for ( int row = 0; row < 難易度; row++){
  4. int  = 0;< 難易度;++){
  5. グリッド[行][] = 難易度 * 行 ++ 1;
  6. }
  7. }
  8. グリッド[難易度 - 1][難易度 - 1] = 0;
  9.  
  10. for ( int row = 0; row < 難易度; row++){
  11. int  = 0;< 難易度;++){
  12. if(grids_a[行][] != Grids[行][]){
  13. 戻る 間違い;
  14. }
  15. }
  16. }
  17.  
  18. 戻る 真実;
  19. }

次に、現在の時刻が最短時刻よりも早いかどうかを判断する関数と、現在の時刻をデータベースに書き込む関数を記述します。

  1. パブリックブール比較() {
  2. int nowtime =時間* 36000 +* 6000 + 秒 * 100 + ミリ秒;
  3. int maxtime = maxhour * 36000 + maxmin * 6000 + maxsec * 100 + maxmsec;
  4.  
  5. nowtime > maxtimeを返します
  6. }
  7.  
  8. パブリックvoid書き込み() {
  9. 比較() の場合
  10. writeData_int( "時間" + 難易度,時間);
  11. writeData_int( "min" + 難易度, min );
  12. writeData_int( "秒" + 難易度,秒);
  13. writeData_int( "msec" + 難易度, msec);
  14. }
  15. }

これでゲーム機能が完成し、このデバイスでゲームをプレイし、データベースにデータを書き込み、別のデバイスにデータを読み取らせ、データの同期を実現する必要があります。

  1. パブリックvoid swipeGrids(){
  2. layout.setTouchEventListener(新しいComponent.TouchEventListener() {
  3. @オーバーライド
  4. パブリックブールonTouchEvent(コンポーネントコンポーネント、TouchEvent touchEvent) {
  5. MmiPoint ポイント = touchEvent.getPointerScreenPosition(0);
  6.  
  7. スイッチ(タッチイベント.getAction()){
  8. TouchEvent.PRIMARY_POINT_DOWNの場合:
  9. startX = point.getX();
  10. ポイントYを取得する
  11.  
  12. 文字列 str_row = String.valueOf(Math.floor((startY - top - 80) / (length + interval)));
  13. 文字列 str2_column = String.valueOf(Math.floor((startX - left ) / (length + interval)));
  14. ゲームが成功した場合
  15. writeData_int( "行" + isLocal 、str_row.charAt(0)- '0' );
  16. writeData_int( "列" + isLocal ,str2_column.charAt(0)- '0' );
  17. グリッドを変更します(str_row.charAt(0)- '0' 、 str2_column.charAt(0)- '0' );
  18. グリッドを描画します。
  19. ゲームが成功した場合(){
  20. レコードを取得します。
  21. 最大テキストを設定します。
  22. HiLog.info(タグ、整数.toString(maxmsec));
  23. タイマーをキャンセルします。
  24. 更新タイマーをキャンセルします。
  25. 比較() の場合
  26. maxhour =時間;
  27. 最大値最小値 =最小値;
  28. 最大秒数 = 秒;
  29. 最大ミリ秒 = ミリ秒;
  30. 書く();
  31. テキストの最大サイズを設定します。
  32. UIContent を設定します。
  33. }
  34. }
  35. }
  36. 壊す;
  37. }
  38. 戻る 真実;
  39. }
  40. });
  41. }

データが同期された後、まだデータの書き込みと提示は行われていません。ここで、配列 b の内容を描画する必要があるため、この関数を実装するために別のタイム スレッドを作成します。

  1. パブリックボイドアップデート(){
  2. updatetimer = 新しいタイマー();
  3. タイマーのスケジュールを更新します(新しいタイマータスク() {
  4. @オーバーライド
  5. パブリックボイド実行(){
  6. getUITaskDispatcher().asyncDispatch(() -> {
  7. グリッドを描画します。
  8. });
  9. }
  10. },0,500);
  11. }

次に、サブスクリプション機能にデータ同期操作も追加する必要があります。

  1. (queryContact_int( "行" + !isLocal)!=-1 && queryContact_int( "列" + !isLocal)!=-1)の場合
  2. changeGrids_b(queryContact_int( "行" + !isLocal),queryContact_int( "列" + !isLocal));

次に、時間を動かす関数を書いてみましょう。

  1. パブリックvoid 実行(){
  2. タイマー = 新しいタイマー();
  3. timer.schedule(new TimerTask() {
  4. @オーバーライド
  5. パブリックボイド実行(){
  6. getUITaskDispatcher().asyncDispatch(()->{
  7. ミリ秒++;
  8. (ミリ秒 >= 100)の場合{
  9. 秒++;
  10. ミリ秒 = ミリ秒 % 100;
  11. (秒> = 60)の場合{
  12. 最小++;
  13. 秒 = 秒 % 60;
  14. 最小値>=60)の場合
  15. 時間++;
  16. 最小=最小% 60;
  17. }
  18. }
  19. }
  20. 文字列 strhour = "" ;
  21. 文字列 strmin = "" ;
  22. 文字列 strsec = "" ;
  23. 文字列 strmsec = "" ;
  24. (ミリ秒<10)の場合{
  25. strmsec = "0" +整数.toString(msec);
  26. }それ以外の場合 (ミリ秒 >= 10) {
  27. strmsec =整数.toString(msec);
  28. }
  29. (秒<10)の場合{
  30. strsec = "0" +整数.toString(sec);
  31. }それ以外の場合 (秒 >= 10) {
  32. strsec =整数.toString(sec);
  33. }
  34. 最小値<10)の場合{
  35. strmin = "0" +整数.toString( min );
  36. }そうでなければ (最小値>= 10) {
  37. strmin =整数.toString( min );
  38. }
  39. (時間< 10 ) の場合 {
  40. strhour = "0" +整数.toString(時間);
  41. }そうでない場合 (時間>= 10) {
  42. strhour = Integer .toString(時間);
  43. }
  44. timetext.setText( "time: " + strhour + ":" +strmin+ ":" +strsec+ ":" +strmsec);
  45. });
  46. }
  47. },0,10);
  48. }

同様に、サブスクリプション機能ではデータ同期を実装する必要がある。

  1. if (queryContact_int( "時間" + 難易度) != -1)
  2. maxhour = queryContact_int( "時間" + 難易度);
  3. if(queryContact_int( "min" + 難易度)!=-1)
  4. maxmin = queryContact_int( "min" +難易度);
  5. if(queryContact_int( "秒" +難易度)!=-1)
  6. maxsec = queryContact_int( "秒" + 難易度);
  7. if (queryContact_int( "msec" + 難易度)!=-1)
  8. maxmsec = queryContact_int( "msec" + 難易度);

これでゲーム機能が完成しました。次に、戻るボタンのクリックイベントを実装しましょう。

  1. タイマーをキャンセルします。
  2. 更新タイマーをキャンセルします。
  3. 終了();

次に、再起動クリックイベントを記述します。両方のデバイスを同時に再起動できるようにするには、再起動ボタンがクリックされたときにデータベースに信号を書き込み、タイムスレッドを使用してこの信号を検出します。検出されると、ゲームが再起動されます。

  1. パブリックvoid再起動() {
  2. タイマーを再起動します。
  3. タイマーを再起動する。スケジュール(新しいタイマータスク() {
  4. @オーバーライド
  5. パブリックボイド実行(){
  6. getUITaskDispatcher().asyncDispatch(() ->{
  7. (再起動 == 1)の場合{
  8. タイマーをキャンセルします。
  9. 更新タイマーをキャンセルします。
  10. 再起動 = 0;
  11. 初期化します。
  12. 実行中();
  13. アップデート();
  14. }
  15. });
  16. }
  17. },0,25);
  18. }

これでゲームは完成しました。これらの分散機能を使用して、さらに多くの 2 人用ゲームを作成することもできます。

記事に関連する添付ファイルをダウンロードするには、以下のリンクをクリックしてください。

https://harmonyos..com/resource/1294

詳細については、以下をご覧ください。

51CTOとHuaweiが共同で構築したHongmengテクノロジーコミュニティ

https://harmonyos..com

<<:  MySQL を使用して分散ロックを実装することを聞いたことがありますか?

>>:  「ファーウェイクラウド・東武カップ」大会が終了し、産業インターネットエコロジカルベンチマークの健全な発展を促進

推薦する

Diggの失敗の暴露:ソーシャルメディアの価値はユーザーにある

アトランティック・マンスリーのオンライン版は本日、かつて人気を博したソーシャルニュースサイト「ディグ...

奇妙なスナップショットのせいでサイトをキックオフしますか?ウェブマスターの皆さん、スナップショットについてよくご存知ですか?

多くのウェブマスターはスナップショットについて異なる感想を持っていると思います。百度の公式サイトはス...

オンラインアライアンスプロモーションでターゲット顧客を追跡する方法の簡単な分析

多くの人はオンラインアライアンスプロモーションを理解していません。まずは百度百科事典のオンラインアラ...

UCloud の大規模データセンター ネットワーク管理システム構築への道

大規模データセンターにおけるネットワーク構成の自動配布、運用・保守効率の向上、ハイブリッドクラウドネ...

オンラインショッピングモールのSEOと運営戦略の共有

現在、電子商取引はあらゆる主要産業を席巻しており、新興産業が火薬なしでこの戦争に参戦しただけでなく、...

草の根ウェブマスターは、ウェブサイトを売却して買い戻すという計画を放棄することはできない

私は田舎の負け犬で、非常に失敗した草の根ウェブマスターです。かつては栄華を極め、最も栄えていた時には...

キーワードをターゲットにしたSEOランディングページのコンバージョン率を測定する

ほとんどのオンライン マーケターは、有料メディア キャンペーンの分析という観点からランディング ペー...

エンタープライズクラウド戦略におけるクラウド導入成熟度モデルの重要性

新型コロナウイルス感染症のパンデミックとの戦いにおいて、企業はビジネスの回復力を確保するためにさまざ...

velocihost: 米国のプロフェッショナル GPU サーバー サプライヤー。多数の GPU グラフィック カード モデルから選択可能

velocihost は 2009 年に設立されたアメリカの会社です。主に米国のマイアミとニューヨー...

微博は20.24ドルで取引を終え、新規株式公開から19.06%上昇した。

4月15日、海外メディアの報道によると、新浪微博の株価は取引初日に19%急騰し、終値は20.24ドル...

5ドルでVPSバトル

ホスティング市場は急速に変化しています。過去数年間人気を博した仮想ホストは、現在では VPS に影を...

クラウドネイティブJavaとGolang

Java のかつての有名なモットーである「一度書けばどこでも実行できる」は今では時代遅れになっており...

地域BBSがソーシャルネットワークのトラフィックコンバージョン率を突破

中関村のようなハイテクの敷居を持たず、強力なバックエンドに依存せず、宣伝や展開に多額の資金を必要とせ...

budgetvm: ロサンゼルス サーバー、月額 86 ドル、帯域幅 1Gbps、トラフィック無制限、e3-1230v3/16g メモリ/2T ハード ドライブ

Enzu傘下のブランドであるBudgetvmは、創業から12年近く経ち、主に米国で4つのデータセンタ...

難しい選択: Ramnode 対 Digitalocean

個人的に、VPS を選ぶということは、価格、VPS リソース構成、VPS の安定性、回線を考慮するこ...