1

私は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()));
        }
    }
4

1 に答える 1

0

TCP を使用しているため、送信/リッスンするポートを指定する必要があります (サーバーとクライアントで異なります)。いいえ、それは正常ではありません (ただし、クライアントとサーバーが同じポートで送信/リッスンしている場合)。

于 2012-10-17T10:31:11.767 に答える