
ご挨拶!
プログラミングに専念する一連の投稿を続けます。今回は、.Netアプリケーション間のTCP接続を介したネットワーク通信について説明します。 この記事は、初心者または.Netに関連するネットワークにまだ出会っていない人に役立つかもしれません。 完全に機能する例が添付されています:
http :
//yadi.sk/d/1OxmAFuCN3kmcカットの下の詳細。
なぜこの記事が必要なのですか?
もちろん、現時点では、同じWCFのネットワーク用に多数のさまざまなライブラリを使用できますが、異なるプログラミング言語を含む2つのアプリケーションを接続する機能は有用です。
理論のビット
ネットワーク接続は実際にはストリームであり、クライアントはバイトを書き込み、サーバーは読み取りを行います。
したがって、送信側でシリアル化し、受信側でデシリアライズする必要があるコマンドのメカニズムを実装する必要があります。
私の実装
一般に、コマンドは、「ToBytes」と「FromBytes」の2つのメソッドと、受信側に渡すプロパティのセットを持つオブジェクトです。
シングルコマンドpublic class SingleCommand: BaseCommand { public int IntField { get; set; } public decimal DecimalField { get; set; }
文字列などの可変長プロパティを含むコマンドを送信する必要がある場合、この文字列の長さをプロパティで指定する必要があります。
StringCommand public class StringCommand : BaseCommand {
受信側がどのチームから来たのかを知るためには、コマンドを送信する前に番号を送信するヘッダーを送信する必要があります(この例では、この瞬間は見逃され、受信は1つのコマンドでのみ実行されます)およびコマンドのタイプ:
コマンドヘッダー public struct CommandHeader {
私の場合、サーバーは次のアルゴリズムに従ってクライアントと対話します。
1.クライアントが接続を作成します。
2.コマンドを送信します
3.応答を受け取ります。
4.接続を閉じます。
5.サーバーからの応答が来なかった場合、タイムアウトにより切断されます。
サーバーへのコマンドの送信:
サーバー送信コマンドメソッドの本体 public static void SendCommandToServer(string serverIp, BaseCommand command, CommandTypeEnum typeEnum) {
サーバー側のクライアントからコマンドを受信する public class CommandListener { private readonly TcpListener _tcpListener; private Thread _listenThread; private bool _continueListen = true; public CommandListener() {
受信したコマンドの処理: public static void HandleClientMessage(object client) { var tcpClient = (TcpClient)client;
Javaインタラクション
このコマンドは、1つの値をサーバーに渡します
チーム package com.offviewclient.network.commands; import java.io.*; public class IntCommand implements Serializable { public int IntNumber; public static int GetLenght() { return 4 ; } public static IntCommand FromBytes(byte[] bytes) throws IOException { ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes); DataInputStream ois = new DataInputStream(inputStream); IntCommand commandType = new IntCommand(); commandType.IntNumber = ois.readInt(); return commandType; } public byte[] ToBytes() throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream oos = new DataOutputStream (bos); oos.writeInt(this.IntNumber); byte[] yourBytes = bos.toByteArray(); oos.close(); bos.close(); return yourBytes; } }
コマンドの送信とサーバーからの応答の受信(作業ドラフトのコード): private void SendPacket(byte[] packetBytes) throws IOException { byte[] packetBytesWithEOF = CommandUtils.AddCommandLength(packetBytes); Socket socket = new Socket(serverIP, port); socket.setSoTimeout(5000); OutputStream socketOutputStream = socket.getOutputStream(); socketOutputStream.write(packetBytesWithEOF); byte[] answerBytes = ReadAnswerBytes(socket); socket.close(); Parse(answerBytes); } private byte[] ReadAnswerBytes(Socket socket) throws IOException { InputStream out = socket.getInputStream(); DataInputStream dis = new DataInputStream(out); ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream binaryWriter = new DataOutputStream (bos); int readCount; byte[] message = new byte[10000]; byte[] messageLength = new byte[4]; dis.read(messageLength , 0, 4); int messageLength = CommandUtils.BytesToInt(messageLength); int totalReadMessageBytes = 0; while ((readCount = dis.read(message, 0, 10000)) != 0) { binaryWriter.write(message, 0, readCount); totalReadMessageBytes += readCount; if(totalReadMessageBytes >= messageLength) break; } return bos.toByteArray(); } private void Parse(byte[] messageBytes) throws IOException { if (messageBytes.length >= CommandHeader.GetLenght()) { CommandHeader commandType = CommandHeader.FromBytes(messageBytes); int skipBytes = commandType.GetLenght(); if(commandType.Type == CommandTypeEnum.MESSAGE_ACCEPTED) { RiseMessageAccepted(); } if(commandType.Type == CommandTypeEnum.SLIDE_PAGE_BYTES) { List<byte[]> drawableList = new Vector<byte[]>(); for(int i = 0; i< commandType.Count; i++) { PresentationSlideCommand presentationSlideCommand = PresentationSlideCommand.FromBytes(messageBytes, skipBytes); drawableList.add(presentationSlideCommand.FileBytes); skipBytes += presentationSlideCommand.GetLenght(); } RiseMessageAcceptSlideEvent(drawableList); } } }
Javaと.Netの相互作用における重要なポイント:.Netに関して基本タイプのバイトを保存するjavaは逆です。したがって、.Net側では、
IPAddress.HostToNetworkOrderメソッドを呼び出してすべての数値を展開する必要があります。
使用する
例として、ユーザーを保存するコマンドを受け入れるようサーバーに教えます。 ユーザーデータには姓と名が含まれます。
これを行うには、次のものが必要です。
1.新しいチームをリストに追加します
public enum CommandTypeEnum : int { StringCommand = 1, MessageAccepted = 2, SingleCommand = 3, FileCommand = 4, SaveUserCommand = 5
2.コマンドで送信されたデータを追加します。
public class SaveUserCommand : BaseCommand { private int FirstNameLenght { get; set; } public string FirstName { get; set; }
3. MessageHandlerを新しいケースで補完します。
case CommandTypeEnum.SaveUserCommand: if (OnSingleCommand != null) OnSaveUserCommand((SaveUserCommand)baseCommand, tcpClient); break;
4.デシリアライゼーションデリゲートの新しいマッピングでMessageHandlerを補完します
private static void FillBytesToCommandsDictionary() { BytesToCommands.Add(CommandTypeEnum.StringCommand, StringCommand.FromBytes); BytesToCommands.Add(CommandTypeEnum.SingleCommand, SingleCommand.FromBytes); BytesToCommands.Add(CommandTypeEnum.FileCommand, FileCommand.FromBytes); BytesToCommands.Add(CommandTypeEnum.SaveUserCommand, SaveUserCommand.FromBytes); }
5.クライアント側で新しいコマンドを送信します。
var saveUserCommand = new SaveUserCommand { FirstName = firstNameTextBox.Text, SecondName = secondNameTextBox.Text }; CommandSender.SendCommandToServer(serverIpTextBox.Text, saveUserCommand, CommandTypeEnum.SaveUserCommand);
6.サーバー側で受け入れます。
MessageHandler.OnSaveUserCommand += CommandListener_OnSaveUserCommand; private static void CommandListener_OnSaveUserCommand(SaveUserCommand saveUserCommand, TcpClient tcpClient) { Console.WriteLine("SaveUserCommand accepted, FirstName:{0}, SecondName:{1}", saveUserCommand.FirstName, saveUserCommand.SecondName); CommandSender.SendMessageAcceptedToClient(tcpClient); }
これがすべて誰かに役立つことを願っています。 Yandexドライブのデモプロジェクト:
http :
//yadi.sk/d/1OxmAFuCN3kmcみんなありがとう!