CocosCreator ユニバーサルフレームワークデザインネットワーク

CocosCreator ユニバーサルフレームワークデザインネットワーク

序文

Cocos Creator で http リクエストを開始するのは比較的簡単ですが、多くのゲームでは、常にクライアントがリクエストを開始するのではなく、サーバーがクライアントにメッセージをアクティブにプッシュできるように、サーバーとの長い接続を維持することを望んでいます。これは、リアルタイム要件が高いゲームに特に当てはまります。ここでは、プロジェクトに簡単に適用できる一般的なネットワーク フレームワークを設計します。

Websocketの使用

このネットワーク フレームワークを実装する前に、まず Websocket について理解しましょう。 Websocket は、Web ページが永続的な接続を作成し、双方向通信を実行できるようにする TCP ベースの全二重ネットワーク プロトコルです。 Cocos Creator で websocket を使用すると、H5 Web ゲームで使用でき、ネイティブ プラットフォームの Android および iOS もサポートされます。

Websocketオブジェクトの構築

Websocket を使用する場合、最初のステップは Websocket オブジェクトを作成することです。 Websocket オブジェクトのコンストラクターは 2 つのパラメーターを渡すことができます。1 つ目は URL 文字列、2 つ目は受け入れ可能なサブプロトコルを指定するプロトコル文字列または文字列配列です。サーバーは接続を確立する前にそれらのうちの 1 つを選択して返す必要がありますが、通常は使用しません。

url パラメータは非常に重要であり、主にプロトコル、アドレス、ポート、リソースの 4 つの部分に分かれています。

たとえば、ws://echo.websocket.org:

  • プロトコル: 必須。デフォルトのプロトコルは ws です。安全な暗号化が必要な場合は、wss を使用します。
  • アドレス: 必須。IP またはドメイン名を指定できますが、もちろんドメイン名を使用することをお勧めします。
  • ポート: オプション。指定しない場合、ws のデフォルト ポートは 80、wss のデフォルト ポートは 443 になります。
  • リソース: オプション。通常はドメイン名に続くリソース パスですが、基本的には必要ありません。

Websocket ステータス

Websocket には 4 つの状態があり、readyState プロパティを通じて照会できます。

  • 0 CONNECTING 接続が確立されていません。
  • 1 OPEN WebSocket接続が確立され、通信が可能になります。
  • 2 CLOSING 接続が終了ハンドシェイク中であるか、close() メソッドが呼び出されました。
  • 3 CLOSED 接続が閉じられました。

WebSocket API

Websocket には、データを送信するための void send( data ) と接続を閉じるための void close( code, reason ) の 2 つの API しかありません。

send メソッドは、送信するデータという 1 つのパラメータのみを受け取ります。送信するデータは、string | ArrayBufferLike | Blob | ArrayBufferView の 4 つのタイプのいずれかになります。

送信するデータがバイナリの場合、Websocket オブジェクトの binaryType プロパティを使用してバイナリ タイプを指定できます。binaryType は「blob」または「arraybuffer」にのみ設定でき、デフォルトは「blob」です。ディスクに書き込むファイルなどの比較的固定されたデータを転送する場合は、blob を使用します。メモリ内で処理されるオブジェクトを転送する場合は、より柔軟な arraybuffer を使用します。他の非 BLOB オブジェクトやデータから BLOB を構築する場合は、BLOB コンストラクターを使用する必要があります。

データを送信する場合、担当者は 2 つの提案をしています。

  • Websocket オブジェクトの readyState が OPEN かどうかを確認し、OPEN の場合のみ送信します。
  • Websocket オブジェクトの bufferedAmount が 0 かどうかを確認し、0 の場合のみ送信します (メッセージの蓄積を回避するために、このプロパティは、send を呼び出した後に Websocket バッファーに蓄積されたが実際には送信されていないデータの長さを示します)。

close メソッドは、2 つのオプション パラメータを受け入れます。Code はエラー コードを表します。1000 または 3000 から 4999 までの整数を渡す必要があります。Reason は、閉じる理由を示すために使用できます。長さは 123 バイトを超えることはできません。

Websocketコールバック

Websocket は、バインドするための 4 つのコールバック関数を提供します。

  • onopen: 接続が成功した後に呼び出されます。
  • onmessage: メッセージが到着したときに呼び出されます。渡されたオブジェクトにはデータ属性があり、文字列、BLOB、または配列バッファーのいずれかになります。
  • onerror: ネットワーク エラーが発生したときに呼び出されます。渡されたオブジェクトにはデータ属性があり、通常はエラーを説明する文字列です。
  • onclose: 接続が閉じられたときに呼び出されます。渡されるオブジェクトには、code、reason、wasClean などの属性があります。

注意: ネットワーク エラーが発生すると、最初に onerror が呼び出され、次に onclose が呼び出されます。接続が閉じられる理由が何であれ、onclose が呼び出されます。

エコーの例

以下は、Websocket 公式サイトの echo デモのコードです。これを html ファイルに記述して、ブラウザで開くことができます。開くと、Websocket 接続が自動的に作成されます。接続が確立されると、「WebSocket rocks」というメッセージがアクティブに送信されます。サーバーはメッセージを返し、onMessage をトリガーして、情報を画面に出力してから、接続を閉じます。詳細については、http://www.websocket.org/echo.html17 を参照してください。

デフォルトの URL プレフィックスは wss です。wss が故障しているため、ws を使用してのみ接続できます。ws も故障している場合は、中国の無料の Websocket テスト URL であるこのアドレス ws://121.40.165.18:8800 に接続してみてください。

デザインフレームワーク

一般的なネットワーク フレームワークは、普遍性を前提として、さまざまなプロジェクトのさまざまな要件をサポートできる必要があります。経験によると、共通の要件は次のとおりです。

  • ユーザー プロトコルの違いにより、ゲームは json、protobuf、flatbuffer、またはカスタム バイナリ プロトコルを送信する場合があります。
  • 基盤となるプロトコルの違いにより、 WeChat ゲームでは websocket または wx.websocket を使用することがあります。また、ネイティブ プラットフォームでも tcp/udp/kcp などのプロトコルを使用する予定です。
  • ログイン認証プロセス:長時間接続を使用する前にログイン認証を実行する必要があります。ゲームによってログイン認証方法が異なります。
  • ネットワーク例外処理。タイムアウトの長さ、タイムアウト後のパフォーマンス、サーバーの応答を要求して待機しているときに UI をブロックするかどうか、ネットワークが切断された後のパフォーマンス、自動的に再接続されるか、プレーヤーが再接続ボタンをクリックして再接続するか、ネットワーク切断期間中のメッセージが再接続後に再送信されるかどうかなど。等々。
  • 複数接続の処理: 一部のゲームでは、複数の異なる接続 (通常は 2 つ以下) をサポートする必要がある場合があります。たとえば、メイン接続はロビーなどのビジネス メッセージの処理を担当し、バトル接続はバトル サーバーに直接接続されるか、チャット サーバーに接続されます。

上記の要件に基づいて、モジュール間の高い凝集性と低い結合性を確保するために機能モジュールを分割します。

ProtocolHelper プロトコル処理モジュール - バッファを取得するときに、このバッファに対応するプロトコルまたは ID を知る必要がある場合があります。たとえば、リクエスト中に応答処理コールバックを渡す場合、自動増分 ID を使用して各リクエストを区別するか、プロトコル番号を使用して異なるリクエストを区別するのが一般的です。これらは、開発者が実装する必要があるものです。バッファからパケットの長さも取得する必要がありますか?パッケージの長さの妥当な範囲はどれくらいですか?ハートビート パケットはどのようなものか、など。

ソケット モジュール- 最も基本的な通信機能を実装します。まず、ソケット インターフェイス クラス ISocket を定義し、接続、クローズ、データの受信と送信などのインターフェイスを定義し、サブクラスがこれらのインターフェイスを継承して実装します。

NetworkTips ネットワーク表示モジュール- 接続中、再接続中、読み込み中、ネットワーク切断などのステータスの表示と UI のシールドを実現します。

NetNode ネットワーク ノード- いわゆるネットワーク ノードですが、実際には、その主な役割は上記の機能を直列に接続し、ユーザーに使いやすいインターフェイスを提供することです。

NetManager はネットワーク ノードのシングルトンを管理します。ネットワーク ノードは複数 (複数接続) になる可能性があるため、ここでは管理にシングルトンが使用されます。ネットワーク ノードの操作にもシングルトンを使用する方が便利です。

プロトコルヘルパー

ここでは、単純な IProtocolHelper インターフェイスが次のように定義されています。

export type NetData = (string | ArrayBufferLike | Blob | ArrayBufferView); // プロトコルヘルパーインターフェース export interface IProtocolHelper
{    
    getHeadlen(): number; // パケット ヘッダーの長さを返します getHearbeat(): NetData; // ハートビート パケットを返します getPackageLen(msg: NetData): number; // パケット全体の長さを返します checkPackage(msg: NetData): boolean; // パケット データが正当かどうかを確認します getPackageId(msg: NetData): number; // パケット ID またはプロトコル タイプを返します }

ソケット

ここでは、次に示すように、単純な ISocket インターフェイスが定義されています。

//ソケットインターフェースエクスポートインターフェースISocket{    
    onConnected: (event) => void; //接続 callbackonMessage: (msg: NetData) => void; //メッセージ callbackonError: (event) => void; //エラー callbackonClosed: (event) => void; //閉じる callbackconnect(ip: string, port: number); //接続 interfaceend(buffer: NetData); //データ送信 interfaceclose(code?: number, reason?: string); //インターフェイスを閉じる}

次に、ISocket から継承する WebSock を実装します。実装する必要があるのは、connect、send、close の各インターフェースだけです。 Send と Close はどちらも Websocket の単純なカプセル化ですが、connect では渡された IP、ポート、その他のパラメータに従って URL を構築し、Websocket を作成して Websocket のコールバックをバインドする必要があります。

エクスポートクラスWebSockはISocketを実装します{    
    private _ws: WebSocket = null; // websocket オブジェクト onConnected: (event) => void = null;    
    onMessage: (メッセージ) => void = null;    
    onError: (イベント) => void = null;    
    onClosed: (イベント) => void = null;   
    接続(オプション: 任意) {        
    if (this._ws) {            
        this._ws.readyState が WebSocket.CONNECTING の場合 {                
            console.log("Websocket に接続しています。しばらくお待ちください...")                
            false を返します。
        }
    }
    url = null とします。        
    if(options.url) {           
        url = オプション.url;        
    } それ以外 {            
        ip = options.ip とします。            
        port = options.port とします。            
        プロトコル = options.protocol とします。            
        url = `${プロトコル}://${ip}:${ポート}`;           
    }        
        this._ws = 新しい WebSocket(url);       
        this._ws.binaryType = options.binaryType ? options.binaryType : "arraybuffer";        
        this._ws.onmessage = (イベント) => {           
        this.onMessage(イベントデータ);        
    };        
        this._ws.onopen = this.onConnected;        
        this._ws.onerror = this.onError;        
        this._ws.onclose = this.onClosed;       
        true を返します。    
    }    
    送信(バッファ: NetData) {        
    this._ws.readyState が WebSocket.OPEN の場合 {           
        this._ws.send(バッファ);           
        true を返します。       
    }       
    false を返します。    
    }    
    閉じる(コード?: 数値、理由?: 文字列) {        
    this._ws.close();    
    }
}

ネットワークのヒント

INetworkTips は、非常に便利なインターフェイス、再接続、および要求スイッチを提供します。フレームワークは適切なタイミングでそれらを呼び出します。INetworkTips を継承して、ネットワーク関連のプロンプト情報をカスタマイズできます。これらのインターフェイスは **複数回** 呼び出される可能性があることに注意してください。

// ネットワークヒントインターフェースエクスポートインターフェースINetworkTips {    
    connectTips(isShow: boolean): void;    
    再接続ヒント(isShow: boolean): void;    
    リクエストヒント(isShow: boolean): void;
}

ネットノード

NetNode は、ネットワーク フレームワーク全体の中で最も重要な部分です。NetNode インスタンスは、完全な接続オブジェクトを表します。NetNode に基づいて、簡単に拡張できます。主な役割は次のとおりです。

接続の維持

  • 接続の確立と認証(認証するかどうかと認証方法はユーザーのコールバックによって決定されます)
  • 切断および再接続後のデータ再送信
  • ハートビート メカニズムは、接続が有効であることを保証します (ハートビート パケット間隔が設定され、ハートビート パケットの内容は ProtocolHelper によって定義されます)
  • 接続を閉じる

データ転送

  • 切断再送とタイムアウト再送をサポート
  • 一意の送信をサポート(同時に繰り返し送信しないようにする)

データ受信

  • 継続的な監視をサポート
  • リクエストレスポンスモードをサポート

インターフェース表示

  • カスタマイズ可能なネットワーク遅延、短期再接続、その他のステータスパフォーマンス
  • まず、NetNode が使用するための 2 つの列挙体 (NetTipsType と NetNodeState) と NetConnectOptions 構造体を定義します。
  • 次は NetNode のメンバー変数です。NetNode 変数は次のカテゴリに分類できます。
  • ISocket オブジェクト、現在の状態、接続パラメータなどの NetNode 独自の状態変数
  • 接続、切断、プロトコル処理、ネットワークプロンプトなどを含むさまざまなコールバック
  • ハートビートや再接続関連のタイマーなど、さまざまなタイマー。
  • 受信したメッセージを処理するために、リクエスト リストとリッスン リストの両方が使用されます。

次に、ネットワーク関連のメンバー関数を紹介します。まず、初期化を見てみましょう。

  • init メソッドは NetNode を初期化するために使用され、主にソケットやプロトコルなどの処理オブジェクトを指定します。
  • connect メソッドはサーバーに接続するために使用されます。
  • initSocket メソッドは、 Socket コールバックを NetNode にバインドするために使用されます。
  • updateNetTips メソッドは、ネットワーク ヒントを更新するために使用されます。

onConnected メソッドは、ネットワーク接続が成功した後に呼び出され、認証プロセスが自動的に開始されます (_connectedCallback が設定されている場合)。認証が完了したら、onChecked メソッドを呼び出して NetNode を通信可能な状態にする必要があります。認証されていない場合は、ビジネス リクエストを送信しないでください。ただし、ログイン検証などのリクエストはサーバーに送信する必要があります。このようなリクエストは、force パラメーターを使用してサーバーに強制的に送信できます。

何らかのメッセージを受信すると、onMessage がトリガーされます。まず、データ パケットが検証されます。検証ルールは、独自の ProtocolHelper に実装できます。正当なデータ パケットである場合は、ハートビート タイマーとタイムアウト タイマー (re-time) を更新し、最後に _requests と _listener でメッセージの処理関数を見つけます。ここでは、rspCmd を検索します。rspCmd は、ProtocolHelper の getPackageId から取得されます。プロトコルのコマンドまたはシーケンス番号を返すことができ、リクエストと応答がどのように対応するかを決定できます。

onError と onClosed はネットワークが失敗して閉じられたときに呼び出されます。エラーの有無に関わらず、最終的には onClosed が呼び出されます。ここでは切断コールバックを実行し、自動再接続処理を行います。もちろん、close を呼び出してソケットを閉じることもできます。 close と closeSocket の違いは、closeSocket はソケットを閉じるだけであることです。私は引き続き現在の NetNode を使用し、次の接続でネットワークを復元したいと考えています。そして、close はすべての状態をクリアします。

ネットワーク要求を開始するには3 つの方法があります。

send メソッドは単にデータを送信します。ネットワークが現在切断されているか検証が進行中の場合は、_request キューに入ります。

リクエストメソッドは、リクエストを行う際に、クロージャの形式でコールバックを渡します。コールバックは、リクエストに対する応答が返ってきたときに実行されます。同時に複数の同一リクエストがある場合、これらの N 個のリクエストの応答が順番にクライアントに返され、応答コールバックも順番に実行されます (一度に実行されるコールバックは 1 つだけです)。

requestUniqueメソッドでは、複数の同一リクエストを発行したくない場合は、requestUnique を使用して、各タイプのリクエストが同時に 1 つだけになるようにすることができます。

ここで重複がないようにトラバーサル _requests を使用する理由は、_requests に大量のリクエストが蓄積されることがなく、タイムアウトや異常な再送信によって _requests のバックログが発生しないためです。再送信ロジックは NetNode によって制御され、ネットワークが切断されたときに、ユーザーがリクエストを開始するのをブロックする必要があります。このとき、通常はフルスクリーン マスク (ネットワークの変動などのプロンプト) が表示されます。

コールバックには 2 種類あります。1 つは、前述のリクエスト コールバックです。このコールバックは一時的なもので、通常はリクエスト レスポンス実行ですぐにクリーンアップされます。_listener コールバックは永続的なもので、特定のインターフェイスを開くときにリッスンしたり、終了するときに閉じたり、ゲームの開始時にリッスンしたりするなど、手動で管理する必要があります。サーバーからのアクティブなプッシュ メッセージを処理するのに適しています。

最後に、ハートビートとタイムアウトに関連するタイマーがあります。_heartTimeごとにハートビートパケットを送信し、_receiveTimeごとにサーバーから返されたパケットを受信しない場合は、ネットワークが切断されていると判断します。

完全なコードについては、ソースコードを入力して表示できます。

ネットマネージャー

NetManager は NetNode を管理するために使用されます。複数の異なる接続オブジェクトをサポートする必要がある可能性があるため、NetNode を管理するには NetManager が必要です。同時に、シングルトンとして、NetManager はネットワークの呼び出しも容易にします。

エクスポートクラスNetManager{
	プライベート静的_instance: NetManager = null;
	保護された_channels: {
		[キー: 数字]: ネットノード
	} = {};
	パブリック静的getInstance(): NetManager {
		if (this._instance == null) {
			this._instance = 新しい NetManager();
		}
		this._instance を返します。
	} // ノードを追加し、ChannelID を返す    
	パブリックsetNetNode(newNode: NetNode, チャネルID: 数値 = 0) {
		this._channels[チャンネルID] = newNode;
	} // ノードを削除    
	パブリックremoveNetNode(チャネルID: 数値) {
		this._channels[channelId]を削除します。
	} // ノード接続を呼び出す public connect(options: NetConnectOptions, channelId: number = 0): boolean {
		if (this._channels[チャンネルID]) {
			this._channels[channelId].connect(options) を返します。
		}
		false を返します。
	} // Node を呼び出して送信します public send(buf: NetData, force: boolean = false, channelId: number = 0): boolean {
		ノードを this._channels[channelId] とします。
		if (ノード) {
			node.send(buf, force) を返します。
		}
		false を返します。
	} // リクエストを開始し、結果が返されたときに指定されたコールバック関数を呼び出します public request(buf: NetData, rspCmd: number, rspObject: CallbackObject, showTips: boolean = true, force: boolean =
		false、チャネルID: 番号 = 0) {
		ノードを this._channels[channelId] とします。
		if (ノード) {
			node.request(buf、rspCmd、rspObject、showTips、force);
		}
	} // request と同じですが、リクエストする前に、まずキューに rspCmd がすでに存在するかどうかを判断します。重複がある場合は、直接返されます public requestUnique(buf: NetData, rspCmd: number, rspObject: CallbackObject, showTips: boolean = true, force:
		ブール値 = false、チャネルID: 数値 = 0): ブール値 {
		ノードを this._channels[channelId] とします。
		if (ノード) {
			node.requestUnique(buf、rspCmd、rspObject、showTips、force) を返します。
		}
		false を返します。
	} // Node を呼び出して閉じる public close(code ? : number, reason ? : string, channelId: number = 0) {
		if (this._channels[チャンネルID]) {
			this._channels[channelId].closeSocket(code, reason); を返します。
		}
	}

テスト例

次に、簡単な例を使用して、ネットワーク フレームワークの基本的な使用方法を説明します。まず、次の図に示すように、表示用の簡単なインターフェイス、3 つのボタン (接続、送信、閉じる)、2 つの入力ボックス (URL を入力、送信するコンテンツを入力)、およびテキスト ボックス (サーバーから受信したデータを表示) を組み立てる必要があります。

この例では、公式の Websocket アドレス echo.websocket.org に接続します。このサーバーは、送信されたすべてのメッセージをそのまま返します。

次に、単純なコンポーネントを実装します。ここで、新しい NetExample.ts ファイルが作成されます。タスクは非常に単純です。初期化中に、NetNode が作成され、デフォルトの受信コールバックがバインドされます。受信コールバックでは、サーバーから返されたテキストが msgLabel に表示されます。次は、接続、送信、終了のためのいくつかのインターフェースの実装です。

// 重要でないコードは省略 @ccclassexport
デフォルトクラス NetExample は cc.Component を拡張します {
	@property(cc.ラベル)
	テキストラベル: cc.Label = null;
	@property(cc.ラベル)
	urlLabel: cc.Label = null;
	@property(cc.リッチテキスト)
	msgLabel: cc.RichText = null;
	プライベートラインカウント: 数値 = 0;
	オンロード() {
		Node = new NetNode();
		Node.init(新しい WebSock()、新しい DefStringProtocol());
		Node.setResponeHandler(0, (cmd: 数値, データ: NetData) => {
			(this.lineCount > 5)の場合{
				idx = this.msgLabel.string.search("\n"); とします。
				this.msgLabel.string = this.msgLabel.string.substr(idx + 1);
			}
			this.msgLabel.string += `${data}\n`;
			++this.lineCount;
		});
		NetManager.getInstance().setNetNode(ノード);
	}
	onConnectClick() {
		NetManager.getInstance().connect({
			url: this.urlLabel.string
		});
	}
	onSendClick() {
		NetManager.getInstance().send(this.textLabel.string);
	}
	onDisconnectClick() {
		NetManager.getInstance().close();
	}
}

コードが完成したら、それをシーンの Canvas ノードの下にマウントし (他のノードでも OK)、シーン内の Label と RichText を NetExample のプロパティ パネルにドラッグします。

実行効果は次のとおりです。

まとめ

ご覧のとおり、Websocket の使用は非常に簡単です。開発プロセスでは、さまざまな要件や問題に遭遇します。適切な設計を実装し、問題を迅速に解決する必要があります。

一方で、使用するテクノロジーを深く理解する必要があります。Websocket の基盤となるプロトコル伝送はどのように実装されているのでしょうか? tcp と http の違いは何ですか? Websocket ベースの送信に UDP を使用できますか? Websocket を使用してデータを送信する場合、データ ストリームを自分でサブパケット化する必要がありますか (Websocket プロトコルはパケットの整合性を保証します)?データ送信時に送信バッファが蓄積されていますか (bufferedAmount を確認してください)?

さらに、使用シナリオとニーズを理解する必要があります。ニーズを徹底的に理解すればするほど、デザインは良くなります。どの要件がプロジェクト固有で、どの要件が汎用的ですか?共通要件は必須ですか、それともオプションですか?さまざまな変更をクラスまたはインターフェースにカプセル化し、ポリモーフィズムを使用して実装する必要がありますか?または構成を提供しますか?コールバックバインディング?イベント通知?

深い経験を積み、効率を向上させるためには、次のプロジェクトに適した適切なフレームワークを設計し、各プロジェクトの反復を最適化する必要があります。

上記は、CocosCreator の一般的なフレームワーク設計のネットワークの詳細な内容です。CocosCreator のフレームワーク設計のネットワークの詳細については、123WORDPRESS.COM の他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • cocoscreatorプレハブの詳しい説明
  • CocosCreator でレイヤー管理に常駐ノードを使用する方法
  • ゲーム開発におけるサウンド処理にCocosCreatorを使用する方法
  • CocosCreator ScrollView 最適化シリーズ: フレーム読み込み
  • CocosCreatorプロジェクト構造の仕組みの詳細な説明
  • CocosCreatorオブジェクトプールの使い方
  • CocosCreatorでスワイプした位置にテクスチャを表示する方法
  • CocosCreatorの共通知識ポイントを整理する
  • CocosCreatorのホットアップデートの包括的な説明
  • CocosCreator クラシック エントリー プロジェクト flappybird
  • CocosCreatorを使ってシューティングゲームを作る方法
  • CocosCreatorでゲームコントローラーを使用する方法

<<:  時間のかかるMySQLレコードのSQL例の詳細な説明

>>:  autoconfを使用してMakefileを生成し、プロジェクトをコンパイルする手順

推薦する

Docker-Composeコマンドの使い方の詳しい説明

Docker コンテナはさまざまな方法で管理およびデプロイできます。 Docker コマンドを直接使...

CSS3 border-radius 丸角の実装方法と使い方の詳しい説明

以前は、角を丸くするのは非常に面倒でしたが、CSS3 では、角を丸くするのは非常に簡単になり、bor...

Vue2.x の応答性の簡単な説明と例

1. Vue レスポンシブの使用法を確認する​ Vue の応答性は、私たち全員がよく知っています。 ...

MySQL 5.6 の「暗黙的な変換」によりインデックスが失敗し、データが不正確になる

背景SQL クエリを実行するときに、where 条件の vachar 型フィールドの単一引用符を削除...

Nginx サーバーで Web クローラーをブロックおよび禁止する方法

通常、すべての Web サイトは、多くの非検索エンジン クローラーに遭遇します。これらのクローラーの...

MySQLテクノロジーにおけるInnoDBロックの詳細な説明

目次序文1. ロックとは何ですか? 2. InnoDBストレージエンジンのロック2.1 ロックの種類...

JavaScript で簡単な計算機を実装する

この記事の例では、参考までに簡単な計算機を実装するためのJavaScriptの具体的なコードを共有し...

Linux QT Kit が見つからない、バージョンが空の問題の解決策

現在このような問題が発生しています 私の状況は、QT が動かなくなってしまったため、仮想マシンを再起...

CSS3はシームレスなスクロールと手ぶれ防止を実現します

質問画像とテキストのシームレスなスクロールは、一般的に携帯電話では良い効果をもたらしますが、一部のモ...

Ubuntu で時刻同期に NTP を使用する

NTP は、ネットワーク上で時間を同期するための TCP/IP プロトコルです。通常、クライアントは...

Linuxファイルの基本属性の知識ポイントのまとめ

Linux システムは典型的なマルチユーザー システムです。異なるユーザーは異なる立場にあり、異なる...

Docker Swarm を使用して分散クローラー クラスターを構築する例

クローラーの開発プロセス中に、クローラーを複数のサーバーに展開する必要がある状況に遭遇したことがある...

Mac でソースコードから MySQL 5.7.17 をコンパイルしてインストールするチュートリアル

1. ダウンロードして解凍します: /Users/xiechunping/Softwares/mys...

Python ベースの Linux システムにおける特定のプロセスのパフォーマンス監視の考え方の詳細な説明

インターネット上には Linux サーバーを監視するためのツール、コンポーネント、プログラムが多数あ...

VMware Workstation 仮想マシンのインストール操作方法

仮想マシンは非常に便利なテストソフトウェアです。ハードウェアに損傷を与えることなく、さまざまなテスト...