Jitstartupでは、JITはstdoutのファイル記述子を作成し、失敗をチェックせずに無条件にsetmodeに渡します。 これはで起こります。 無効な記述子の確認に失敗すると、setmodeがフェイルファストをトリガーする可能性があります。
このエラーのため、64ビット1Cクライアントで静的.Netメソッドが呼び出されたときに例外がスローされました。
1cv8.exeの0x00007FFD76FB8528(ucrtbase.dll)で未処理の例外:無効なパラメーターが致命的なエラーの原因となる関数に無効なパラメーターが渡されました。
これで修復され、8.3.9の64ビットクライアントでコードが正常に実行されます。 例では、.NET Coreライブラリを1.0.1に置き換えました。 SignalRについて書きたかったのですが、今のところ.Net Coreにしかサーバーを書くことができません-Windows 10 UWPアプリ用ASP.NET Core SignalR
aspnet / SignalR-Server
まだ顧客がいません。 WCFでは、これまでのところ、Webサービスのクライアントのみ。 ServiceHost番号 サードパーティのソリューションがあります。NETコアクロスプラットフォームリモートサービス呼び出し
しかし、私は8年前の経験から、Win CE上のTSDと1Cの間でTCP / IPデータを交換して、さらに7試合の解決策を書くことにしました。 もちろん、1CはWebサービスを介して交換できますが、データの選択、クライアントで準備されたデータの取得、モバイルプリンターへの印刷のためにオペレーターとのやり取りが必要なタスクがあります。
主な問題は、倉庫内の接続不良のネットワークに関連しています。 そのため、データ圧縮によるトラフィックを削減する必要がありました。 そのため、ターミナルセッションで作業する場合、低速ネットワークでのポート転送に問題がありました。RDPを介した会計レジストラへの小切手の印刷が遅くなります。
2次元バーコードの読み取りにも問題がありました。 ターミナルサーバーからの印刷が遅い。 これらの問題を解決するために、ローカルの1Cがクライアントマシンにインストールされ、クライアントとサーバーとして機能しました。 スキャナーからのデータは、ターミナルサーバーに送信され、そこで処理されました。 会計レジストラに印刷するために、サーバーからTCP / IP経由でデータが送信され、ローカル1Cからチェックが印刷されました。 サーバーからラベルを印刷するとき、データが送信され、それに基づいてローカル1Cでドキュメントが形成され、印刷に送信されました。
さらに、多くのLinuxハードウェア用のドライバーはありません。 仮想化を使用すると、LinuxとWindowsを同じマシンに保持し、Windowsでデータを読み取り、TCP / IPを介してLinuxと通信できます。
現在、多くの人がWinCe、WinMoの下にTSDを持っています(最近、彼らのために交換をセットアップする作業を提供しました)。 さらに、UWPとXamarinを使用して、他の軸でTSDを使用できます。
さらに、チャットなど、1Cクライアント間でメッセージを交換できます。
大規模な.Netでは、TCp / IP共有をよく使用します
1C 7.xb 8.xでの.NETアセンブリの使用。 外部コンポーネントの作成。
1Cからデータを受信するワイヤレススキャナーとしてWM 6のTSDを使用する
そのため、同じ交換を記述しますが、.Net Coreで新しいアプローチを追加することにしました。
純粋な1Cニックネームは、敵のコードをスキップして、このコンポーネントの使用方法の記事の最後にあるネイティブコードに移動できます。
圧縮データを使用したメッセージング用のクラスを作成する必要がありました。 データを送信するために、メソッドが使用されました:
// // // string // string // bool public TCP (string , int , string , string , bool )
1C側では、このクラスが受け入れられます
// 1 public class 1 { public bool ; public string ; public string ; TcpClient ; public 1( , TcpClient ) { this. = .; this. = .; this. = .; if () this. = ; else // { .Dispose(); this. = null; } } // // , 1 // public void (string ) { Task.Run(() => { var strim = .GetStream(); .WriteCompressedString(strim, ); // strim.Dispose(); .Dispose(); }); } public override string ToString() { return $"={}, ={}, ={}"; } }
8年前に小さな変更を加えて作成されたメッセージを生成するためのモジュール。
それでも、私はRuslishを力強くメインで使用しました。
たくさんのコード
ExchangePTSPのパブリッククラス
{
public static readonly Encoding CurrentEncoder; // = Encoding.GetEncoding(1251);
static for ExchangePTSP()
{
//ここに.Net Coreの機能があります
//プロバイダーを登録する必要があります
//そして、依存関係「System.Text.Encoding.CodePages」に書き込みます
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
// CurrentEncoder = Encoding.GetEncoding( "windows-1251");
// Ruslishを使用するため、エンコーディング1251を使用します
CurrentEncoder = Encoding.GetEncoding(1251);
}
public static byte [] Unload Data(byte [] Commandのデータ配列)
{
var memStream = new MemoryStream(コマンドのデータ配列);
var DecompressStream = new MemoryStream();
使用(GZipStream gzipStream = new GZipStream(memStream、CompressionMode.Decompress、false))
{
バイト[]バッファー=新しいバイト[1 << 16];
int h;
while((h = gzipStream.Read(buffer、0、buffer.Length))> 0)
{
DecompressStream.Write(buffer、0、h);
}
}
return DecompressStream.ToArray();
}
//
public static byte [] CompressData(バイト[]値)
{
var memStream = new MemoryStream();
memStream.Position = 0;
使用(GZipStream gzipStream = new GZipStream(memStream、CompressionMode.Compress))
{
gzipStream.Write(Value、0、Value.Length);
gzipStream.Flush();
}
return memStream.ToArray();
}
//受信したデータのサイズを知っているNetworkStreamからの古典的な読み取り
private static byte [] Byte Array FromStream(NetworkStreamストリーム、int配列サイズ)
{
バイト[]結果=新しいバイト[配列サイズ];
カウントされた文字のint数= 0;
while(配列サイズ>カウントされる文字の数)
{
カウントされたシンボルの数+ = stream.Read(結果、カウントされたシンボルの数、配列のサイズ-カウントされたシンボルの数);
}
結果を返す;
}
public static voidバイトの配列をストリームに書き込みます(NetworkStreamストリーム、バイト[]配列)
{
stream.Write(Array、0、Array.Length);
}
//ストリームから1バイトを読み取り、boolに変換します
public static bool ReadBool(NetworkStreamストリーム)
{
return BitConverter.ToBoolean(ストリームからのバイトの配列(ストリーム、1)、0);
}
// boolを1バイトに変換し、ストリームに書き込みます
public static void Write(NetworkStreamストリーム、bool値)
{
バイトの配列をストリームに書き込む(ストリーム、BitConverter.GetBytes(値));
}
//ストリームから4バイトを読み取り、intに変換します
public static Int32 ReadInt32(NetworkStreamストリーム)
{
return BitConverter.ToInt32(ストリームからのバイトの配列(ストリーム、4)、0);
}
// intを4バイトに変換してストリームに書き込みます
public static void Write(NetworkStreamストリーム、Int32値)
{
バイトの配列をストリームに書き込む(ストリーム、BitConverter.GetBytes(値));
}
//行を読み取ります。 まず、intデータのサイズがあります
//次に、データを読み取り、エンコーディング1251を使用して文字列を取得します
public static string ReadString(NetworkStreamストリーム)
{
intデータサイズ= ReadInt32(ストリーム);
if(Data Size == 0)return "";
return CurrentEncoder.GetString(ストリームからのバイト配列(ストリーム、データサイズ));
}
//行を書きます。 最初に、文字列のサイズを書き込み、次にエンコーディング1251を使用してバイト[]に変換します
public static void Write(NetworkStreamストリーム、文字列値)
{
if(Value.Length == 0)
{
書き込み(ストリーム、0);
帰る
}
バイト[]結果= CurrentEncoder.GetBytes(値);
Write(stream、result.Length);
ストリーム(ストリーム、結果)にバイトの配列を書き込みます。
}
// WriteCompressedStringは逆の操作である
public static string ReadCompressedString(NetworkStreamストリーム)
{
// intData Size = ReadInt32(ストリーム);
// CurrentEncoder.GetString(ストリームからのバイト配列(ストリーム、データサイズ))を返します;
boolこれは、圧縮文字列= ReadBool(ストリーム)です。
if(!これは圧縮された文字列です)return ReadString(stream);
コマンドのintデータサイズ= BitConverter.ToInt32(ストリームからのバイト配列(ストリーム、4)、0);
byte []コマンドのデータ配列=ストリームのバイト配列(ストリーム、コマンドのデータサイズ)。
コマンドのデータ配列=データのアンロード(コマンドのデータ配列);
return CurrentEncoder.GetString(チームのデータ配列);
}
// GZIP文字列を圧縮しようとしています。 圧縮データのサイズが元のサイズよりも小さい場合は、圧縮データを書き込みます
//それ以外の場合は元の
//次の順序でデータを書き込みます
// boolデータ圧縮フラグ
// intデータサイズ
//バイト[]データ
public static void WriteCompressedString(NetworkStreamストリーム、文字列値)
{
if(Value.Length == 0)
{
書き込み(ストリーム、false);
書き込み(ストリーム、0);
帰る
}
バイト[]結果= CurrentEncoder.GetBytes(値);
var CompressedData = CompressData(結果);
if(result.Length> Compressed Data.Length)
{
書き込み(ストリーム、true);
書き込み(ストリーム、圧縮されたData.Length);
バイト配列をストリームに書き込む(ストリーム、圧縮データ);
}
他に
{
書き込み(ストリーム、false);
Write(stream、result.Length);
ストリーム(ストリーム、結果)にバイトの配列を書き込みます。
}
}
//サーバーにデータを送信します
//文字列コマンドは、データを処理するメソッドの名前です
//文字列DataFor a Command、これは文字列としてシリアル化されたデータです
// bool Is応答は、データを処理するメソッドの関数またはプロシージャのサインです
public static void Send to Team(NetworkStream strim、string Command、string Data For Team、boolはい
{
書きます(ストリム、答えがあります)。
書き込み(ストリム、コマンド);
WriteCompressedString(ストリーム、コマンドのデータ);
}
//クライアントからデータを読み取ります
パブリックスタティック構造メッセージ受け入れチーム(NetworkStream strim)
{
bool IsAnswer = ReadBool(ストリム);
string Command = ReadString(ストリム);
string DataFor Command = ReadCompressedString(strim);
新しいメッセージ構造(コマンド、コマンドのデータ、返信があります)を返します。
}
}
{
public static readonly Encoding CurrentEncoder; // = Encoding.GetEncoding(1251);
static for ExchangePTSP()
{
//ここに.Net Coreの機能があります
//プロバイダーを登録する必要があります
//そして、依存関係「System.Text.Encoding.CodePages」に書き込みます
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
// CurrentEncoder = Encoding.GetEncoding( "windows-1251");
// Ruslishを使用するため、エンコーディング1251を使用します
CurrentEncoder = Encoding.GetEncoding(1251);
}
public static byte [] Unload Data(byte [] Commandのデータ配列)
{
var memStream = new MemoryStream(コマンドのデータ配列);
var DecompressStream = new MemoryStream();
使用(GZipStream gzipStream = new GZipStream(memStream、CompressionMode.Decompress、false))
{
バイト[]バッファー=新しいバイト[1 << 16];
int h;
while((h = gzipStream.Read(buffer、0、buffer.Length))> 0)
{
DecompressStream.Write(buffer、0、h);
}
}
return DecompressStream.ToArray();
}
//
public static byte [] CompressData(バイト[]値)
{
var memStream = new MemoryStream();
memStream.Position = 0;
使用(GZipStream gzipStream = new GZipStream(memStream、CompressionMode.Compress))
{
gzipStream.Write(Value、0、Value.Length);
gzipStream.Flush();
}
return memStream.ToArray();
}
//受信したデータのサイズを知っているNetworkStreamからの古典的な読み取り
private static byte [] Byte Array FromStream(NetworkStreamストリーム、int配列サイズ)
{
バイト[]結果=新しいバイト[配列サイズ];
カウントされた文字のint数= 0;
while(配列サイズ>カウントされる文字の数)
{
カウントされたシンボルの数+ = stream.Read(結果、カウントされたシンボルの数、配列のサイズ-カウントされたシンボルの数);
}
結果を返す;
}
public static voidバイトの配列をストリームに書き込みます(NetworkStreamストリーム、バイト[]配列)
{
stream.Write(Array、0、Array.Length);
}
//ストリームから1バイトを読み取り、boolに変換します
public static bool ReadBool(NetworkStreamストリーム)
{
return BitConverter.ToBoolean(ストリームからのバイトの配列(ストリーム、1)、0);
}
// boolを1バイトに変換し、ストリームに書き込みます
public static void Write(NetworkStreamストリーム、bool値)
{
バイトの配列をストリームに書き込む(ストリーム、BitConverter.GetBytes(値));
}
//ストリームから4バイトを読み取り、intに変換します
public static Int32 ReadInt32(NetworkStreamストリーム)
{
return BitConverter.ToInt32(ストリームからのバイトの配列(ストリーム、4)、0);
}
// intを4バイトに変換してストリームに書き込みます
public static void Write(NetworkStreamストリーム、Int32値)
{
バイトの配列をストリームに書き込む(ストリーム、BitConverter.GetBytes(値));
}
//行を読み取ります。 まず、intデータのサイズがあります
//次に、データを読み取り、エンコーディング1251を使用して文字列を取得します
public static string ReadString(NetworkStreamストリーム)
{
intデータサイズ= ReadInt32(ストリーム);
if(Data Size == 0)return "";
return CurrentEncoder.GetString(ストリームからのバイト配列(ストリーム、データサイズ));
}
//行を書きます。 最初に、文字列のサイズを書き込み、次にエンコーディング1251を使用してバイト[]に変換します
public static void Write(NetworkStreamストリーム、文字列値)
{
if(Value.Length == 0)
{
書き込み(ストリーム、0);
帰る
}
バイト[]結果= CurrentEncoder.GetBytes(値);
Write(stream、result.Length);
ストリーム(ストリーム、結果)にバイトの配列を書き込みます。
}
// WriteCompressedStringは逆の操作である
public static string ReadCompressedString(NetworkStreamストリーム)
{
// intData Size = ReadInt32(ストリーム);
// CurrentEncoder.GetString(ストリームからのバイト配列(ストリーム、データサイズ))を返します;
boolこれは、圧縮文字列= ReadBool(ストリーム)です。
if(!これは圧縮された文字列です)return ReadString(stream);
コマンドのintデータサイズ= BitConverter.ToInt32(ストリームからのバイト配列(ストリーム、4)、0);
byte []コマンドのデータ配列=ストリームのバイト配列(ストリーム、コマンドのデータサイズ)。
コマンドのデータ配列=データのアンロード(コマンドのデータ配列);
return CurrentEncoder.GetString(チームのデータ配列);
}
// GZIP文字列を圧縮しようとしています。 圧縮データのサイズが元のサイズよりも小さい場合は、圧縮データを書き込みます
//それ以外の場合は元の
//次の順序でデータを書き込みます
// boolデータ圧縮フラグ
// intデータサイズ
//バイト[]データ
public static void WriteCompressedString(NetworkStreamストリーム、文字列値)
{
if(Value.Length == 0)
{
書き込み(ストリーム、false);
書き込み(ストリーム、0);
帰る
}
バイト[]結果= CurrentEncoder.GetBytes(値);
var CompressedData = CompressData(結果);
if(result.Length> Compressed Data.Length)
{
書き込み(ストリーム、true);
書き込み(ストリーム、圧縮されたData.Length);
バイト配列をストリームに書き込む(ストリーム、圧縮データ);
}
他に
{
書き込み(ストリーム、false);
Write(stream、result.Length);
ストリーム(ストリーム、結果)にバイトの配列を書き込みます。
}
}
//サーバーにデータを送信します
//文字列コマンドは、データを処理するメソッドの名前です
//文字列DataFor a Command、これは文字列としてシリアル化されたデータです
// bool Is応答は、データを処理するメソッドの関数またはプロシージャのサインです
public static void Send to Team(NetworkStream strim、string Command、string Data For Team、boolはい
{
書きます(ストリム、答えがあります)。
書き込み(ストリム、コマンド);
WriteCompressedString(ストリーム、コマンドのデータ);
}
//クライアントからデータを読み取ります
パブリックスタティック構造メッセージ受け入れチーム(NetworkStream strim)
{
bool IsAnswer = ReadBool(ストリム);
string Command = ReadString(ストリム);
string DataFor Command = ReadCompressedString(strim);
新しいメッセージ構造(コマンド、コマンドのデータ、返信があります)を返します。
}
}
サーバー上でリスニング用のクラスが作成されます。
// public class TCPConnector { TcpListener Server; // // "System.Diagnostics.TextWriterTraceListener" // DLL TextWriterTraceListener myTextListener; // bool = false; // Socket ; // 1 // 1 public Action<string, string, object> 1; // public Action<string> 1; // string AssemblyDirectory { get { string codeBase = typeof(TCPConnector).GetTypeInfo().Assembly.Location; UriBuilder uri = new UriBuilder(codeBase); string path = Uri.UnescapeDataString(uri.Path); return Path.GetDirectoryName(path) + @"\"; } } public TCPConnector() { myTextListener = null; } // a 1 void (string ) { if (myTextListener == null) { try { FileStream fs = new FileStream(AssemblyDirectory + @"", FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite); StreamWriter myOutputWriter = new StreamWriter(fs, Encoding.GetEncoding(1251)); myTextListener = new TextWriterTraceListener(myOutputWriter); Trace.Listeners.Add(myTextListener); } catch (Exception) { // } } Trace.WriteLine(); Trace.Flush(); 1?.DynamicInvoke(); } // // , 1 public void (int = 6891, int = 1) { = false; IPEndPoint ipEndpoint = new IPEndPoint(IPAddress.Any, ); Server = new TcpListener(ipEndpoint); Server.Start(); // // // https://github.com/imatitya/netcorersi/blob/master/src/NETCoreRemoveServices.Core/Hosting/TcpServerListener.cs for (int i = 0; i < ; i++) Server.AcceptTcpClientAsync().ContinueWith(); } // private void (Task<TcpClient> task) { if (task.IsFaulted || task.IsCanceled) { // Server.Stop(); return; } // TcpClient client = task.Result; // // (client); // Server if (!) Server.AcceptTcpClientAsync().ContinueWith(); } private void (TcpClient client) { NetworkStream = client.GetStream(); try { // // 1 //TcpClient var = new 1(.(), client); // 1 // 1?.DynamicInvoke("TCPConnector", ., ); } catch (Exception e) { (DateTime.Now.ToString() + e.ToString()); } } // public void () { if (Server != null) { = true; Server.Stop(); Server = null; } if (myTextListener != null) { Trace.Listeners.Remove(myTextListener); myTextListener.Dispose(); } }
すべてが非常に簡単です。 接続するとき、データを読み取り、1Cで送信するためのオブジェクトを作成します。 新しいリスナーを起動します。
ベアソケットで行われた送信は、ソースにあります。
簡略化すると、次のようになります。
IPEndPoint ipEndpoint = new IPEndPoint(IPAddress.Parse(), ); //6891 = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); .Connect(ipEndpoint); var = new NetworkStream(); .(, , , ); // if () result = .ReadCompressedString(strim); .Dispose(); .Dispose();
1Cでの処理方法は次のとおりです。
// Net core NetStandard System.Threading.Tasks Task=("System.Threading.Tasks.Task","System.Threading.Tasks"); TCP() TCP<> ; TCPConnector=("TCPConnectTo1C.TCPConnector","TCPIPCore.dll"); TCP=(TCPConnector.()); =TCP.(); .(,"1"); .(,"1"); // TCP() TCPConnect() // // // , 1 // // // (.(3*2)); (.(3*2)); TCP(); TCP.(6891,3); ..=; ..=; ..=; ( ) // (Task.Delay(1000)).Wait(); =" "+.+" | "+.+" |="+Xml(()); .(); ( ) // (Task.Delay(1000)).Wait(); // TCP( ) ("="+.); ("="+.); ("="+.); (Task.Delay(1000)).Wait(); . =" "+.+" | "+.+" |="+Xml(()); .(); ; (, , ) ="TCPConnector" // =(); ("="+.(.())); // NetObjectToIDispatch =" " TCP() // (+"()"); ; ; ( TCP,ServerAdress,,,,) =(TCP.(ServerAdress,,,,)); (.(.())); . =" |"+.; (); ; () TCP(); TCP=TCP; ServerAdress="127.0.0.1"; =6891; =" "; =Xml(()); =; =; =false; =1 3 (TCP,ServerAdress,,,,); (TCP,ServerAdress,,"",,); (TCP,ServerAdress,,"","12345678901",); ; () // . TCP<> TCP.(); TCP=; ; GC=("System.GC"); GC.Collect(); GC.WaitForPendingFinalizers(); =;
応答は、受信したオブジェクトを介して送信されます。
.();
デフォルトでは、1Cのイベントのキューは1です。したがって、1つのタスクを実行し、別のタスクをキューで待機できます。
複数のデバイスで作業できるため、次の方法で目的のキューサイズを設定する必要があります。
.( ));
現在のキューサイズを返します。
もちろん、複数の1Cアプリケーションを実行し、異なるポートでTCP / IPサーバーを実行できます。 しかし実際には、オペレーターは混乱しています。 それらが単純であればあるほど良い。
メソッドを使用して、必要なデリゲートを設定します。
.(,"1"); .(,"1");
デリゲートのタイプに応じて、必要なデリゲートが設定されます。
if (ReturnType == typeof(Action<string, string, object>)) return new Action<string, string, object>(); if (ReturnType == typeof(Action<string, string, string>)) return new Action<string, string, string>(AutoWrap.1);
もちろん、イベントと動的コンパイルを使用できます。出版物「開発→1C、.Net Core」を参照してください。 1Cの.Netオブジェクトのイベントを受信するためのラッパークラスの動的コンパイル 。
ただし、1Cで記述しているため、目的のタイプのデリゲートを宣言し、1Cからインストールする方が簡単です。
テストでは、3つの1Cクライアントを使用し、TCPIP.epfでTestExchangeを呼び出して、1Cのイベントのキューを確認する必要があります。
ソースはここからダウンロードできます 。