【问题标题】:TCP both Client and Server on the same PCTCP 客户端和服务器在同一台 PC 上
【发布时间】:2012-10-07 14:08:18
【问题描述】:

我正在尝试在 C# 中实现一个基于 tcp 的小型应用程序。我是 TCP 编程的新手。

该应用程序非常简单。这是一个客户端/服务器方案,最多支持 2 个客户端。一个客户端将是“外部”IP,另一个将是主机本身。

每次客户端连接到服务器时,它都会开始从/向服务器接收和发送数据包。

我设置了一个小型控制台应用程序,它实现了 TCP 服务器端代码和 TCP 客户端代码。

服务器使用绑定到特定端口的侦听器并等待客户端连接。连接客户端后,它会生成一个新线程来处理与客户端的通信。

客户端只需连接到服务器,一旦连接建立,它就会开始接收和发送数据包。

正如我之前所说的“主机也是它自己的客户端”,但这会导致一个问题。如果客户端向服务器发送一个数据包,服务器和客户端都声称收到了一个数据包。这是正常的?我错过了什么吗?

更新 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;

更新 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()));
        }
    }

【问题讨论】:

  • 你能给我们提供任何代码吗?
  • 客户如何“声称”收到包裹?
  • 服务器和客户端是否共享端口?
  • 是的,你是对的,更新了代码
  • 那么,你的错误是什么?

标签: c# networking tcp connection client


【解决方案1】:

由于您使用 TCP,您必须指定一个端口来发送/侦听(服务器和客户端不同)。所以不,这是不正常的(但如果客户端和服务器在同一个端口上发送/监听)。

【讨论】:

  • 服务器开始监听某个端口。建立连接后,我想它会分配一个带有新端口的新套接字。这样对吗?客户端尝试使用侦听器使用的相同端口连接到服务器。一旦建立连接,它应该使用不同的端口来发送和接收吗?我必须指定在哪里收听吗?
  • 通过您的实现,这种方式似乎是正确的。我在想你正在使用不同的套接字。我会看看这个。
猜你喜欢
  • 1970-01-01
  • 2023-03-18
  • 2015-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-19
  • 1970-01-01
相关资源
最近更新 更多