Swing プログラムのビジネス ロジックをサーバーに移行中です。
クライアントとサーバー、サーバーとクライアントを通信する最も効率的な方法は何ですか?
サーバーは認証、データのフェッチと保存を担当するため、プログラムは頻繁に通信する必要があります。
Swing プログラムのビジネス ロジックをサーバーに移行中です。
クライアントとサーバー、サーバーとクライアントを通信する最も効率的な方法は何ですか?
サーバーは認証、データのフェッチと保存を担当するため、プログラムは頻繁に通信する必要があります。
それは多くのことに依存します。本当の答えが必要な場合は、プログラムが何をするのか、何が「効率的」の定義に該当するのかを正確に明確にする必要があります。
迅速な生産性が効率の定義に該当する場合、私が過去に使用した方法には、単純な古い Java オブジェクトをソケットに送信するシリアライゼーションが含まれます。最近、netty api と組み合わせることで、かなり堅牢なクライアント/サーバー通信のプロトタイプを迅速に作成できることがわかりました。
内臓はかなり単純です。クライアントとサーバーの両方が、パイプラインで ObjectDecoder と ObjectEncoder を使用して Netty を実行します。クラスは、データを処理するために設計されたオブジェクトごとに作成されます。たとえば、HandshakeRequest クラスと HandshakeResponse クラスです。
ハンドシェイク リクエストは次のようになります。
public class HandshakeRequest extends Message {
private static final long serialVersionUID = 1L;
}
ハンドシェイク応答は次のようになります。
public class HandshakeResponse extends Message {
private static final long serialVersionUID = 1L;
private final HandshakeResult handshakeResult;
public HandshakeResponse(HandshakeResult handshakeResult) {
this.handshakeResult = handshakeResult;
}
public HandshakeResult getHandshakeResult() {
return handshakeResult;
}
}
netty では、クライアントが次のように接続すると、サーバーはハンドシェイク要求を送信します。
@Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
Channel ch = e.getChannel();
ch.write(new HandshakeRequest();
}
クライアントは HandshakeRequest オブジェクトを受け取りますが、サーバーが送信したばかりのメッセージの種類を伝える方法が必要です。これには aMap<Class<?>, Method>
を使用できます。プログラムが実行されると、リフレクションを使用してクラスのメソッドを反復処理し、それらをマップに配置する必要があります。以下に例を示します。
public HashMap<Class<?>, Method> populateMessageHandler() {
HashMap<Class<?>, Method> temp = new HashMap<Class<?>, Method>();
for (Method method : getClass().getMethods()) {
if (method.getAnnotation(MessageHandler.class) != null) {
Class<?>[] methodParameters = method.getParameterTypes();
temp.put(methodParameters[1], method);
}
}
return temp;
}
このコードは、現在のクラスを反復処理し、@MessageHandler アノテーションでマークされたメソッドを探し、メソッドの最初のパラメーター (パラメーターは などのオブジェクトpublic void handleHandshakeRequest(HandshakeRequest request)
) を調べて、クラスを実際のキーとしてマップに配置します。値としてのメソッド。
このマップを使用すると、メッセージを受信して、メッセージを処理するメソッドにメッセージを直接送信することが非常に簡単になります。
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
try {
Message message = (Message) e.getMessage();
Method method = messageHandlers.get(message.getClass());
if (method == null) {
System.out.println("No handler for message!");
} else {
method.invoke(this, ctx, message);
}
} catch(Exception exception) {
exception.printStackTrace();
}
}
本当に何も残っていません。netty は面倒なことをすべて処理し、シリアル化されたオブジェクトを簡単にやり取りできるようにします。netty を使用したくない場合は、独自のプロトコルを Java のObject Output Streamにラップできます。全体的にもう少し多くの作業を行う必要がありますが、コミュニケーションのシンプルさは損なわれません。
どの方法が何に関して「最も効率的」であるかを言うのは少し難しいです.あなたのユースケースはわかりませんが、ここにいくつかのオプションがあります:
最も基本的な方法は、単に「生の」TCP ソケットを使用することです。利点は、ネットワークを介して移動する余分なものがないことと、自分でプロトコルを作成することです。後者は欠点でもあります。通信用の独自のプロトコルに加えて、サーバー側で複数の接続を処理するための基本的なフレームワークを設計および実装する必要があります (そのような必要がある場合)。
UDP ソケットを使用すると、おそらく遅延と帯域幅を少し節約できます (モバイル データのようなものを使用していない限り、遅延に関して TCP との違いに気付かないでしょう)。ただし、ネットワーク コードは少し難しい作業です。UDP ソケットは「コネクションレス」です。つまり、すべてのクライアント メッセージは同じハンドラーで終了し、互いに区別する必要があります。サーバーがクライアントの状態に追いつく必要がある場合、これを正しく実装するのはやや面倒です。
MadProgrammer はRMI (リモート メソッド呼び出し) を持ち出しました。個人的には使用したことがなく、セットアップが少し面倒に思えますが、長期的には実装に関してはかなり良いかもしれません。
おそらく最も一般的な方法の 1 つは、通信に http を使用することです。たとえば、 Web サービス用のREST インターフェイスを使用します。実装に役立つ複数のフレームワーク (個人的にはSpring MVCが好き) がありますが、新しいフレームワークを学習することは今のところあなたの範囲外かもしれません。また、複雑な http クエリや長い URL は帯域幅をもう少し消費する可能性がありますが、非常に大量の同時クライアントについて話している場合を除き、これは通常問題にはなりません (データセンターでサーバーを実行していると仮定すると) 100/100MBit 接続のようなもの)。Web サーバーで使用できる負荷分散ソリューションが多数あるため、これはおそらくスケーリングが最も簡単なソリューションです。