分布式数据库中间件–(2) Cobar与客户端的握手认证
Cobar启动完成,监听特定端口。整个认证的流程图: NIOAcceptor类继承自Thread类,该类的对象会以线程的方式运行,进行连接的监听。NIOAcceptor启动的初始化过程如下:1 、打开一个selector,获取一个ServerSocketChannel对象,对该对象的socket绑定特定的监
Cobar启动完成,监听特定端口。整个认证的流程图:
public NIOAcceptor(String name, int port, FrontendConnectionFactory factory) throws IOException { super.setName(name); this.port = port; this.selector = Selector.open(); this.serverChannel = ServerSocketChannel.open(); //ServerSocket使用TCP this.serverChannel.socket().bind(new InetSocketAddress(port)); this.serverChannel.configureBlocking(false); this.serverChannel.register(selector, SelectionKey.OP_ACCEPT); this.factory = factory; }
public void run() { final Selector selector = this.selector; //线程一直循环 for (;;) { ++acceptCount; try { selector.select(1000L); Set<SelectionKey> keys = selector.selectedKeys(); try { for (SelectionKey key : keys) { if (key.isValid() && key.isAcceptable()) { //接受来自客户端的连接 accept(); } else { key.cancel(); } } } finally { keys.clear(); } } catch (Throwable e) { LOGGER.warn(getName(), e); } } }
- interest集合(使用&操作SelectionKey.OP_ACCEPT和key.interestOps())
- ready集合(key.readyOps(),可以使用&操作检测该集合,也可以使用is方法)
- Channel(key.channel())
- Selector(key.selector())
- 附加对象(key.attach(obj) ? Object obj = key.attachment())
private void accept() { SocketChannel channel = null; try { //从服务器端获取管道,为一个新的连接返回channel channel = serverChannel.accept(); //配置管道为非阻塞 channel.configureBlocking(false); //前端连接工厂对管道进行配置,设置socket的收发缓冲区大小,TCP延迟等 //然后由成员变量factory的类型生产对于的类型的连接 //比如ServerConnectionFactory会返回ServerConnection实例,并对其属性进行设置 FrontendConnection c = factory.make(channel); //设置连接属性 c.setAccepted(true); c.setId(ID_GENERATOR.getId()); //从processors中选择一个NIOProcessor,将其和该连接绑定 NIOProcessor processor = nextProcessor(); c.setProcessor(processor); //向读反应堆注册该连接,加入待处理队列 //select选择到感兴趣的事件后,会进行调用connection的read函数 processor.postRegister(c); } catch (Throwable e) { closeChannel(channel); LOGGER.warn(getName(), e); } }

public void run() { final Selector selector = this.selector; for (;;) { ++reactCount; try { int res = selector.select(); LOGGER.debug(reactCount + ">>NIOReactor接受连接数:" + res); register(selector); Set<SelectionKey> keys = selector.selectedKeys(); try { for (SelectionKey key : keys) { Object att = key.attachment(); if (att != null && key.isValid()) { int readyOps = key.readyOps(); if ((readyOps & SelectionKey.OP_READ) != 0) { LOGGER.debug("select读事件"); read((NIOConnection) att); } else if ((readyOps & SelectionKey.OP_WRITE) != 0) { LOGGER.debug("select写事件"); write((NIOConnection) att); } else { key.cancel(); } } else { key.cancel(); } } } finally { keys.clear(); } } catch (Throwable e) { LOGGER.warn(name, e); } } }
?channel.register(selector, SelectionKey.OP_READ, this);注意最后一个this指针参数,表示将该连接作为附件,注册到selector,当有感兴趣的时间发生时,函数selector.selectedKeys()返回的SelectionKey集合中的对象中使用key.attachment()即可获取到上面注册时绑定的connection对象指针附件。目的就是为了通过该附件对象调用该连接类中定义的read函数来完成功能。如下所示:
private void read(NIOConnection c) { try { c.read(); } catch (Throwable e) { c.error(ErrorCode.ERR_READ, e); } }
public void handle(final byte[] data) { // 从线程池获取一个线程,异步处理前端数据 // 从processor中的线程池中获取一个可以执行的线程,执行Runnable任务 processor.getHandler().execute(new Runnable() { @Override public void run() { try { //调用具体NIOHandler子类的handle函数 handler.handle(data); } catch (Throwable t) { error(ErrorCode.ERR_HANDLE_DATA, t); } } }); }
public FrontendConnection(SocketChannel channel) { super(channel); ..................... //前端认证处理器 this.handler = new FrontendAuthenticator(this); }


- 读取信息到认证包对象
- 核对用户
- 核对密码
- 检查schema
public void handle(byte[] data) { // check quit packet if (data.length == QuitPacket.QUIT.length && data[4] == MySQLPacket.COM_QUIT) { source.close(); return; } //新建认证包对象 AuthPacket auth = new AuthPacket(); //读取认证包到对象 auth.read(data); // check user if (!checkUser(auth.user, source.getHost())) { failure(ErrorCode.ER_ACCESS_DENIED_ERROR, "Access denied for user '" + auth.user + "'"); return; } // check password if (!checkPassword(auth.password, auth.user)) { failure(ErrorCode.ER_ACCESS_DENIED_ERROR, "Access denied for user '" + auth.user + "'"); return; } // check schema switch (checkSchema(auth.database, auth.user)) { case ErrorCode.ER_BAD_DB_ERROR: failure(ErrorCode.ER_BAD_DB_ERROR, "Unknown database '" + auth.database + "'"); break; case ErrorCode.ER_DBACCESS_DENIED_ERROR: String s = "Access denied for user '" + auth.user + "' to database '" + auth.database + "'"; failure(ErrorCode.ER_DBACCESS_DENIED_ERROR, s); break; default: //认证成功,向客户端发送认证结果消息 success(auth); } }
protected void success(AuthPacket auth) { //认证通过,设置连接属性:已认证\用户\数据库\处理器 source.setAuthenticated(true); source.setUser(auth.user); source.setSchema(auth.database); source.setCharsetIndex(auth.charsetIndex); //设置该连接的连接处理器为前端命令处理器 source.setHandler(new FrontendCommandHandler(source)); ....... ByteBuffer buffer = source.allocate(); source.write(source.writeToBuffer(AUTH_OK, buffer)); }
16:59:19,388 INFO =============================================== 16:59:19,389 INFO Cobar is ready to startup ... 16:59:19,389 INFO Startup processors ... 16:59:19,455 INFO Startup connector ... 16:59:19,460 INFO Initialize dataNodes ... 16:59:19,506 INFO dnTest1:0 init success 16:59:19,514 INFO dnTest3:0 init success 16:59:19,517 INFO dnTest2:0 init success 16:59:19,527 INFO CobarServer is started and listening on 8066 16:59:19,527 INFO =============================================== 16:59:23,459 DEBUG 1>>NIOReactor接受连接数:0 16:59:23,464 DEBUG 2>>NIOReactor接受连接数:1 16:59:23,465 DEBUG select读事件 16:59:23,465 INFO com.alibaba.cobar.net.handler.FrontendAuthenticator接收的请求长度:62 58 0 0 1 5 166 15 0 0 0 0 1 33 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 114 111 111 116 0 20 169 171 247 102 133 96 158 224 121 22 226 229 88 244 119 238 185 61 124 219 16:59:23,468 INFO [thread=Processor1-H0,class=ServerConnection,host=192.168.137.8,port=46101,schema=null]'root' login success
yan@yan-Z400:~$ mysql -uroot -p** -P8066 -h192.168.137.8 Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1 Server version: 5.1.48-cobar-1.2.7 Cobar Server (ALIBABA) Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
本文出自:http://blog.geekcome.com, 原文地址:http://blog.geekcome.com/%e5%88%86%e5%b8%83%e5%bc%8f%e6%95%b0%e6%8d%ae%e5%ba%93%e4%b8%ad%e9%97%b4%e4%bb%b6-2-cobar%e4%b8%8e%e5%ae%a2%e6%88%b7%e7%ab%af%e7%9a%84%e6%8f%a1%e6%89%8b%e8%ae%a4%e8%af%81, 感谢原作者分享。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











Go 言語は、効率的かつ簡潔で習得が容易なプログラミング言語であり、同時プログラミングやネットワーク プログラミングに優れているため、開発者に好まれています。実際の開発ではデータベースの操作が欠かせませんが、今回はGo言語を使ってデータベースの追加・削除・変更・クエリ操作を実装する方法を紹介します。 Go 言語では、データベースを操作するために通常、よく使用される SQL パッケージや gorm などのサードパーティ ライブラリを使用します。ここでは SQL パッケージを例として、データベースの追加、削除、変更、クエリ操作を実装する方法を紹介します。 MySQL データベースを使用していると仮定します。

MQTT (MessageQueuingTelemetryTransport) は、IoT デバイス間の通信に一般的に使用される軽量のメッセージ送信プロトコルです。 PHP は、MQTT クライアントの開発に使用できる、一般的に使用されるサーバー側プログラミング言語です。この記事では、PHP を使用して MQTT クライアントを開発する方法を紹介します。以下の内容が含まれます。 MQTT プロトコルの基本概念 PHPMQTT クライアント ライブラリの選択と使用例: PHPMQTT クライアントを使用した公開と使用

MySQLi を使用して PHP でデータベース接続を確立する方法: MySQLi 拡張機能を含める (require_once) 接続関数を作成する (functionconnect_to_db) 接続関数を呼び出す ($conn=connect_to_db()) クエリを実行する ($result=$conn->query()) 閉じる接続 ( $conn->close())

Hibernate ポリモーフィック マッピングは、継承されたクラスをデータベースにマップでき、次のマッピング タイプを提供します。 join-subclass: 親クラスのすべての列を含む、サブクラス用の別個のテーブルを作成します。 table-per-class: サブクラス固有の列のみを含む、サブクラス用の別個のテーブルを作成します。 Union-subclass: join-subclass と似ていますが、親クラス テーブルがすべてのサブクラス列を結合します。

Apple の最新リリースの iOS18、iPadOS18、および macOS Sequoia システムでは、さまざまな理由で紛失または破損した写真やビデオをユーザーが簡単に回復できるように設計された重要な機能が写真アプリケーションに追加されました。この新機能では、写真アプリのツール セクションに「Recovered」というアルバムが導入され、ユーザーがデバイス上に写真ライブラリに含まれていない写真やビデオがある場合に自動的に表示されます。 「Recovered」アルバムの登場により、データベースの破損、カメラ アプリケーションが写真ライブラリに正しく保存されない、または写真ライブラリを管理するサードパーティ アプリケーションによって失われた写真やビデオに対する解決策が提供されます。ユーザーはいくつかの簡単な手順を実行するだけで済みます

HTML はデータベースを直接読み取ることはできませんが、JavaScript と AJAX を通じて実現できます。この手順には、データベース接続の確立、クエリの送信、応答の処理、ページの更新が含まれます。この記事では、JavaScript、AJAX、および PHP を使用して MySQL データベースからデータを読み取る実践的な例を示し、クエリ結果を HTML ページに動的に表示する方法を示します。この例では、XMLHttpRequest を使用してデータベース接続を確立し、クエリを送信して応答を処理することで、ページ要素にデータを埋め込み、データベースを読み取る HTML の機能を実現します。

Java フレームワークは、次の戦略を含むミドルウェアの再利用とリソース共有をサポートします。 接続プールによる事前に確立されたミドルウェア接続の管理。スレッドローカルストレージを利用して、ミドルウェア接続を現在のスレッドに関連付けます。スレッド プールを使用して、再利用可能なスレッドを管理します。頻繁にアクセスされるデータのコピーをローカルまたは分散キャッシュ経由で保存します。

GoWebSocket をデータベースと統合する方法: データベース接続をセットアップする: データベースに接続するには、database/sql パッケージを使用します。 WebSocket メッセージをデータベースに保存する: INSERT ステートメントを使用して、メッセージをデータベースに挿入します。データベースから WebSocket メッセージを取得する: データベースからメッセージを取得するには、SELECT ステートメントを使用します。
