私はC#で小さなtcpベースのアプリケーションを実装しようとしています。私はTCPプログラミングに不慣れです。
アプリは本当にシンプルです。これは、最大2つのクライアントをサポートするクライアント/サーバーシナリオです。1つのクライアントは「外部」IPになり、もう1つはホスト自体になります。
クライアントがサーバーに接続するたびに、サーバーとの間でパケットの送受信を開始します。
TCPサーバー側コードとTCPクライアントコードの両方を実装する小さなコンソールアプリをセットアップしました。
サーバーは、特定のポートにバインドされたリスナーを使用して、クライアント接続を待ちます。クライアントが接続されると、クライアントとの通信を処理するための新しいスレッドが生成されます。
クライアントはサーバーに接続するだけで、接続が安定すると、パケットの送受信を開始します。
前にも言ったように、「ホストはそれ自体のクライアントでもあります」が、これは問題につながります。クライアントがサーバーにパケットを送信した場合、サーバーとクライアントの両方がパケットを受信したと主張します。正常ですか?私は何かが足りないのですか?
UPDATE 2(問題の修正)
私は問題を見つけたと思います。クライアントが送信操作を行ったら、バッファを「リセット」する必要があります
case SocketAsyncOperation.Send:
// Put in listen mode
// Buffer reset AFTER send and BEFORE receive
_receiver.SetBuffer(new byte[4096], 0, 4096);
_client.ReceiveAsync(_receiver);
break;
UPDATE 1(コードの追加)
サーバ
public void Host()
{
_listener = new TcpListener(new IPEndPoint(IPAddress.Any, this.ConnectionPort));
_listener.Start();
this.IsListening = true;
ThreadPool.QueueUserWorkItem((state) =>
{
while (true)
{
// Blocks until a client connections occours
// If continue with no client then stop listening
try
{
TcpClient client = _listener.AcceptTcpClient();
// Add client to peer list
long assignedID = DateTime.UtcNow.Ticks;
_clients.Add(assignedID, client);
HandleClient(assignedID);
if (this.ConnectedClients == this.MaxClients)
{
_listener.Stop();
this.IsListening = false;
break;
}
}
catch
{
// Server has stop listening
_stopListen.Set();
break;
}
}
});
}
private void HandleClient(long assignedID)
{
ThreadPool.QueueUserWorkItem((state) =>
{
long clientID = (long)state;
TcpClient client = _clients[clientID];
try
{
byte[] message = new byte[4096];
byte[] buffer = new byte[4096];
int readed = 0;
int index = 0;
NetworkStream clientStream = client.GetStream();
while (true)
{
readed = clientStream.Read(message, 0, message.Length);
if (readed == 0)
{
// Client disconnected, thorw exception
throw new SocketException();
}
Array.Copy(message, 0, buffer, index, readed);
index += readed;
if (readed == 4096
&& !_packetHub.IsValidBufferData(buffer))
{
Array.Clear(buffer, 0, buffer.Length);
readed = 0;
index = 0;
continue;
}
if (_packetHub.IsValidBufferData(buffer))
{
NetPacket receivedPacket = _packetHub.DeserializePacket(buffer);
NetPacket answerPacket = null;
// Assign sender ID in case of unknown sender ID
if (receivedPacket.SenderID == NetPacket.UnknownID)
receivedPacket.SenderID = clientID;
// Handle received packet and forward answer packet
// to the client or to all other connected peers
answerPacket = HandlePacket(receivedPacket);
if (answerPacket != null)
{
if (answerPacket.RecipientID == clientID)
{
// Send answer packet to the client
SendPacket(client, answerPacket);
}
else
{
// Broadcast packet to all clients
foreach (TcpClient peer in _clients.Values)
SendPacket(peer, answerPacket);
}
}
// Reset receive packet buffer
Array.Clear(buffer, 0, buffer.Length);
readed = 0;
index = 0;
}
}
}
catch
{
System.Diagnostics.Debug.WriteLine("Network error occours!");
}
finally
{
// Close client connection
client.Close();
// Remove the client from the list
_clients.Remove(clientID);
// Raise client disconnected event
OnClientDisconnected();
}
}, assignedID);
}
クライアント
public void Connect()
{
if (this.ConnectionAddress == null)
throw new InvalidOperationException("Unable to connect. No server IP specified.");
_receiver = new SocketAsyncEventArgs();
_receiver.RemoteEndPoint = new IPEndPoint(this.ConnectionAddress, this.ConnectionPort);
_receiver.SetBuffer(new byte[4096], 0, 4096);
_receiver.Completed += new EventHandler<SocketAsyncEventArgs>(Socket_OperationComplete);
_client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_client.ConnectAsync(_receiver);
}
private void Socket_OperationComplete(object sender, SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
switch (e.LastOperation)
{
case SocketAsyncOperation.Connect:
_readyToSend = true;
this.IsConnected = true;
// Once connection is estabilished, send a join packet to
// retrive server side assigned informations
JoinPacket joinPacket = (JoinPacket)NetPacket.CreatePacket(this.ClientID, NetPacket.ToHost, NetPacket.JoinPacket);
joinPacket.ClientName = this.ClientName;
joinPacket.ClientAddress = this.LocalAddress.ToString();
SendPacket(joinPacket);
break;
case SocketAsyncOperation.Receive:
_readyToSend = true;
byte[] buffer = _receiver.Buffer;
System.Diagnostics.Debug.WriteLine("Client received packet (" + _packetHub.GetBufferDataType(buffer) + ") with length of: " + buffer.Length);
if (_packetHub.IsValidBufferData(buffer))
{
NetPacket receivedPacket = _packetHub.DeserializePacket(buffer);
NetPacket answerPacket = null;
// Handle received packet and forward answer packet
// to the server
answerPacket = HandlePacket(receivedPacket);
if (answerPacket != null)
SendPacket(answerPacket);
}
else
{
_client.ReceiveAsync(_receiver);
}
break;
case SocketAsyncOperation.Send:
// Put in listen mode
_client.ReceiveAsync(_receiver);
break;
}
}
else
{
OnClientDisconnected();
System.Diagnostics.Debug.WriteLine(String.Format("Network error: {0}", e.SocketError.ToString()));
}
}