TCP/IP を介してシリアル化されたコマンドを通信するプロジェクトに取り組んでいます。ローカル ホストにいるときは動作していますが、別のサーバーでリスナーを実行すると、リスナー側でコマンドを逆シリアル化しようとするとランダムに失敗します。スローされる例外は次のとおりです。「空のストリームを逆シリアル化しようとしています。」および「解析が完了する前にストリームの終わりが検出されました。」シリアライザから
一連のコマンドを個別に実行すると正常に動作しますが、スレッドを作成して複数のシーケンスを同時に実行すると失敗します。
リスナーは 4 つの異なるポートでリスナーを作成し、クライアントはポートごとに 1 つのスレッドを実行します。スレッドの 1 つがシーケンスの最後に到達すると、そのスレッドは終了します。
クライアントのシングルトンを作成しようとし、Mutex も試しました。しかし、それでも同じ問題です。
これが私のクライアントです:
public class TcpIpCommunicator : ICommunicator, IDisposable
{
private Dictionary<int,TcpClient> clientSockets = new Dictionary<int,TcpClient>();
public IInverterCommand ReadAsyncCommand { set; get; }
private static TcpIpCommunicator tcpIpCommunicator;
private TcpIpCommunicator()
{
}
public static TcpIpCommunicator GetInstance()
{
if(tcpIpCommunicator == null)
tcpIpCommunicator = new TcpIpCommunicator();
return tcpIpCommunicator;
}
public void Send(IInverterCommand command, int id)
{
var serializer = new Serializer();
MemoryStream stream = serializer.SerializeMultipleObjects(command);
var _bytes = stream.GetBuffer();
var networkStream = clientSockets[id].GetStream();
networkStream.Write(_bytes, 0, _bytes.Length);
networkStream.Flush();
}
public IInverterCommand Read(int id)
{
var memoryStream = new MemoryStream();
byte[] buffer;
var networkStream = clientSockets[id].GetStream();
do
{
buffer = new byte[clientSockets[id].ReceiveBufferSize];
int sizeRead = networkStream.Read(buffer, 0, buffer.Length);
memoryStream.Write(buffer, 0, sizeRead);
} while (networkStream.DataAvailable);
networkStream.Flush();
memoryStream.Position = 0;
var serializer = new Serializer();
return serializer.DeSerializeMultipleObject(memoryStream);
}
public void ReadAsync(object id)
{
ReadAsyncCommand = Read((int)id);
}
public void Dispose()
{
foreach (var tcpClient in clientSockets.Values)
{
tcpClient.Close();
}
}
public int Connect(string ip, int port)
{
var tcpClient = new TcpClient();
tcpClient.ReceiveTimeout = int.MaxValue;
tcpClient.SendTimeout = int.MaxValue;
tcpClient.Connect(ip, port);
int key = findKey();
clientSockets.Add(key, tcpClient);
return key;
}
public void DestroyConnection(int id)
{
clientSockets[id].Close();
clientSockets.Remove(id);
}
private int findKey()
{
int key = 0;
while(clientSockets.ContainsKey(key))
{
key++;
}
return key;
}
}
そして、私のサーバー側のコードはここにあります:
public class TCPListener : IDisposable
{
private readonly TcpListener _serverSocket;
private NetworkStream _networkStream;
private readonly TcpClient _clientSocket = default(TcpClient);
public TCPListener(int port)
{
_serverSocket = new TcpListener(port);
_serverSocket.Server.ReceiveTimeout = int.MaxValue;
_serverSocket.Server.SendTimeout = int.MaxValue;
_serverSocket.Start();
_clientSocket = _serverSocket.AcceptTcpClient();
}
public void Send(IInverterCommand message)
{
_networkStream = _clientSocket.GetStream();
var serialize = new Serializer();
var stream = serialize.SerializeMultipleObjects(message);
var _bytes = stream.GetBuffer();
if (_bytes.Length > _clientSocket.ReceiveBufferSize)
{
byte[] bytes = new byte[_clientSocket.ReceiveBufferSize];
for (int i = 0; i < _bytes.Length; i += _clientSocket.ReceiveBufferSize)
{
for (int j = 0; j < _clientSocket.ReceiveBufferSize && i + j != _bytes.Length; ++j)
{
bytes[j] = _bytes[i + j];
}
_networkStream.Write(bytes, 0, _clientSocket.ReceiveBufferSize);
}
}
else
{
_networkStream.Write(_bytes, 0, _bytes.Length);
}
Thread.Sleep(50);
_networkStream.Flush();
}
public IInverterCommand ReadCommand()
{
_networkStream = _clientSocket.GetStream();
var memoryStream = new MemoryStream();
do
{
var buffer = new byte[_clientSocket.ReceiveBufferSize];
int sizeRead = _networkStream.Read(buffer, 0, buffer.Length);
memoryStream.Write(buffer, 0, sizeRead);
Thread.Sleep(50);
} while (_networkStream.DataAvailable);
_networkStream.Flush();
memoryStream.Position = 0;
var serializer = new Serializer();
return serializer.DeSerializeMultipleObject(memoryStream);
}
public void Dispose()
{
_clientSocket.Close();
_serverSocket.Stop();
}
}
これは通常、クライアント側でコードを呼び出しています。
IInverterCommand command = new SoftwareUpdateInverterCommand();
tcpClient.Send(command, tcpId);
var thread = new Thread(tcpClient.ReadAsync);
thread.Start(tcpId);
if (!thread.Join(timeout))
{
thread.Abort();
tcpClient.DestroyConnection(tcpId);
return;
}
サーバー側の呼び出しコード:
//Recieving CMD on software update
TcpListener = new TCPListener((int)port);
var command = TcpListener.ReadCommand();
//Sending OK back to server
command.Message = "OK";
TcpListener.Send(command);