我在程序中实现套接字时遇到问题

问题描述 投票:0回答:0

我有一个模拟游戏“战舰”的程序,同时充当服务器和客户端。

在菜单中,我选择是作为服务器(我调用服务器的启动方法,控制台打开,然后我进入游戏屏幕)还是作为客户端(我进入游戏屏幕)进行游戏。

我运行程序两次,第一次选择服务器,第二次选择客户端。

第一个界面工作正常,我对第二个界面的问题是它没有将所有消息正确发送到服务器并且没有收到任何回复。

我在这里附上我的代码:

服务器.cs

namespace Battleship_sockets
{
    public class Server
    {        
        #region ATTRIBUTES
        public TcpListener tcpListener;
        public TcpClient tcpClient;
        public bool dcc = false;
        // Lista de clientes conectados
        List<TcpClient> clients = new List<TcpClient>();

        // Instancia de ClientManager
        private ClientManager clientManager;

        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool AllocConsole();
        #endregion

        public Server()
        {
            clientManager = new ClientManager(clients);
        }

        public async Task Start()
        {
            AllocConsole(); // Agregar esta línea para crear una consola en modo Windows Forms
            try
            {
                // Crear el punto de conexión para escuchar
                IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
                IPEndPoint localEndPoint = new(ipAddress, 8080);

                // Crear el socket TCP para escuchar
                tcpListener = new(localEndPoint);

                // Iniciar la escucha del socket
                tcpListener.Start();

                Console.WriteLine("Server started and listening on port 8080...");

                while (true)
                {
                    TcpClient client = await tcpListener.AcceptTcpClientAsync();
                    Add(client);
                    // Iniciar un hilo para manejar la conexión del cliente
                    await HandleClient(client);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }

        public async Task HandleClient(TcpClient client)
        {
            await using NetworkStream stream = client.GetStream();
            try
            {
                #region 1
                // Leer mensajes del servidor
                byte[] buffer = new byte[1024];
                int bytesRead = await stream.ReadAsync(buffer);
                string message = Encoding.ASCII.GetString(buffer, 0, bytesRead);
                Console.WriteLine($"- Client{clientManager.GetClientes().Count}: {message}");

                // Verificar si hay dos clientes conectados
                if (clientManager.GetClientes().Count == 2)
                {
                    Console.WriteLine("Both clients connected.");
                    Console.WriteLine("Ready to play...");
                }
                else
                {
                    Console.WriteLine("Waiting for another client to connect...");
                }

                #endregion
            }
            catch (Exception e)
            {
                Console.WriteLine($"Client error: {e.Message}");

                // Eliminar el cliente de la lista de clientes
                clientManager.RemoveClient(client);

                // Cerrar la conexión con el cliente
                client.Close();
            }
        }

        public void Ready()
        {
            try
            {
                while (clientManager.GetClientes().Count != 2)
                {
                    Console.WriteLine("No other client is connected.");
                    return;
                }
                Console.WriteLine($"The player {clientManager.GetClientes().Count} is ready.");
                dcc = true;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

        public void Add(TcpClient client)
        {
            clientManager.AddClient(client);
            Console.WriteLine($"Connected clients: {clientManager.GetClientes().Count}");
            
        }

        public void Remove(TcpClient client)
        {
            clientManager.RemoveClient(client);
            Console.WriteLine($"Connected clients: {clientManager.GetClientes().Count}");
        }


    }
}

客户端.cs

namespace Battleship_sockets
{
    public class Client
    {
        #region ATTRIBUTES
        public TcpClient tcpClient;
        private NetworkStream stream;
        // Instancia de ClientManager
        private readonly ClientManager clientManager;
        #endregion

        public Client(ClientManager clientManager)
        {
            this.clientManager = clientManager;
        }

        public void Connect(string name)
        {
            try
            {
                Server sv = new Server();
                //Task.Run(() => sv.Add(tcpClient));

                // Conectar al servidor
                tcpClient = new TcpClient();
                tcpClient.Connect(IPAddress.Parse("127.0.0.1"), 8080);
                stream = tcpClient.GetStream();

                // Enviar datos al servidor
                string mensaje = $"Hi, Im {name}";
                byte[] buffer = Encoding.ASCII.GetBytes(mensaje);
                stream.Write(buffer);

                // Leer respuesta del servidor
                byte[] bufferAnswer = new byte[1024];
                int answerLength = stream.Read(bufferAnswer, 0, bufferAnswer.Length);
                string answer = Encoding.ASCII.GetString(bufferAnswer, 0, answerLength);
                Console.WriteLine($"- Server: {answer}");
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());

            }
        }

        public void Send(string mensaje)
        {
            try
            {
                // Enviar datos al servidor 
                byte[] msg = Encoding.ASCII.GetBytes(mensaje);
                stream.Write(msg);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }

        public void Disconnect()
        {
            try
            {
                Server sv = new Server();
                Task.Run(() => sv.Remove(tcpClient));
                tcpClient.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

    }
}

菜单.cs

namespace Battleship_sockets
{
    public partial class MainMenu : Form
    {
        #region ATTRIBUTES
        private Server s;
        private Form1? form1;
        private readonly ClientManager clientManager;
        #endregion
        public MainMenu()
        {
            InitializeComponent();
            s = new Server();
        }

        private void btnServidor_Click(object sender, EventArgs e)
        {
            Task.Run(() => s.Start());
            form1 = new Form1();
            this.Hide(); // oculta el formulario actual
            form1.ShowDialog(); // muestra el nuevo formulario como cuadro de diálogo modal
            this.Close(); // cierra el formulario actual cuando se cierre el nuevo formulario
        }

        
        private void btnCliente_Click(object sender, EventArgs e)
        {
            form1 = new Form1();
            form1.ShowDialog(); 
            this.Close();
        }
    }
    
}

Form1.cs

namespace Battleship_sockets
{
    public partial class Form1 : Form
    {
        #region ATTRIBUTES
        public Client c;
        public Server s;
        private ClientManager clientManager;
        private List<Ship> ships = new List<Ship>();
        private int totalShips = 3;
        private int addedShips;
        #endregion

        public Form1()
        {
            InitializeComponent();
            CreateButtons();
            c = new Client(clientManager);
            s = new Server();
            btnReady.Enabled = false;
            btnAddShip1.Enabled = false;
            btnAddShip2.Enabled = false;
            btnAddShip3.Enabled = false;
            btnClear.Enabled = false;
            btnDisconnect.Enabled = false;            
        }        
        private string GetRowLabel(int rowIndex)
        {
            const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
            return alphabet[rowIndex].ToString();
        }
        private void CreateButtons()
        {
            int labelWidth = 20; // ancho de las etiquetas de fila y columna
            int labelHeight = 20; // altura de las etiquetas de fila y columna
            int buttonWidth = 25; // ancho de los botones
            int buttonHeight = 25; // altura de los botones
            // Agregar etiquetas para las columnas al panel
            for (int col = 0; col < 10; col++)
            {
                Label lblCol = new Label();
                lblCol.Text = col.ToString();
                lblCol.Location = new Point((col + 1) * buttonWidth + labelWidth, 0);
                lblCol.Size = new Size(labelWidth, labelHeight);
                panel1.Controls.Add(lblCol);
                lblCol = new Label();
                lblCol.Text = col.ToString();
                lblCol.Location = new Point((col + 1) * buttonWidth + labelWidth, 0);
                lblCol.Size = new Size(labelWidth, labelHeight);
                panel2.Controls.Add(lblCol);
            }
            // Agregar etiquetas para las filas al panel
            for (int row = 0; row < 10; row++)
            {
                Label lblRow = new Label();
                lblRow.Text = GetRowLabel(row);
                lblRow.Location = new Point(0, (row + 1) * buttonHeight + labelHeight);
                lblRow.Size = new Size(labelWidth, labelHeight);
                panel1.Controls.Add(lblRow);
                lblRow = new Label();
                lblRow.Text = GetRowLabel(row);
                lblRow.Location = new Point(0, (row + 1) * buttonHeight + labelHeight);
                lblRow.Size = new Size(labelWidth, labelHeight);
                panel2.Controls.Add(lblRow);
                // Agregar botones al panel
                for (int col = 0; col < 10; col++)
                {
                    Button button = new Button();
                    button.Name = GetRowLabel(row).ToString() + col.ToString();
                    button.Text = "";
                    button.Location = new Point((col + 1) * buttonWidth + labelWidth, (row + 1) * buttonHeight + labelHeight);
                    button.Size = new Size(buttonWidth, buttonHeight);
                    button.Enabled = false;
                    button.BackColor = Color.White;
                    panel1.Controls.Add(button);

                    button = new Button();
                    button.Name = GetRowLabel(row).ToString() + col.ToString();
                    button.Text = "";
                    button.Location = new Point((col + 1) * buttonWidth + labelWidth, (row + 1) * buttonHeight + labelHeight);
                    button.Size = new Size(buttonWidth, buttonHeight);
                    button.Enabled = false;
                    button.BackColor = SystemColors.ControlDark;
                    button.Click += new EventHandler(panel2_ButtonClick); // Agrega el controlador de eventos al botón
                    panel2.Controls.Add(button);
                }
            }
        }
        private void btnReady_Click(object sender, EventArgs e)
        {
            s.Ready();
            if (s.dcc)
            {
                // Habilitar los botones en el panel del oponente
                foreach (Control control in panel2.Controls)
                {
                    if (control is Button button)
                    {
                        button.Enabled = true;
                        button.BackColor = Color.White;
                    }
                }
                // Deshabilitar el botón "Limpiar"
                btnClear.Enabled = false;
            }
            else
            {
                // Si no hay dos clientes conectados, mostrar un mensaje al usuario
                MessageBox.Show("Waiting for two clients to connect.", "Message",
                    MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
           
            
        }
        private void btnAddShip1_Click(object sender, EventArgs e)
        {
            CoordinatesForm form = new CoordinatesForm();
            Button button1 = (Button)sender;
            if (form.ShowDialog() == DialogResult.OK)
            {
                Point coordinates = form.Coordinates;
                // Comprobar que los botones correspondientes al barco elegido no estén ya ocupados por otro barco
                bool free = true;
                for (int i = 0; i < 5; i++)
                {
                    int row = coordinates.Y;
                    int col = coordinates.X + i;
                    Button button = (Button)panel1.Controls.Find(GetRowLabel(row).ToString() + col.ToString(), true)[0];
                    if (button.BackColor != Color.White)
                    {
                        free = false;
                        break;
                    }
                }
                // Comprobar que el barco no se extienda fuera del tablero
                if (coordinates.X + 4 >= 10)
                {
                    free = false;
                    MessageBox.Show("The chosen location is not valid.");
                }
                if (free)
                {
                    Ship ship = new Ship(5, coordinates, true);
                    ships.Add(ship);
                    addedShips++;
                    // Pintar los botones correspondientes al barco en el panel1
                    for (int i = 0; i < ship.Size; i++)
                    {
                        int row = ship.Location.Y;
                        int col = ship.Location.X + i;
                        Button button = (Button)panel1.Controls.Find(GetRowLabel(row).ToString() + col.ToString(), true)[0];
                        button.BackColor = Color.DarkBlue;
                        button1.Enabled = false;
                    }
                }
                else
                {
                    MessageBox.Show("The chosen location is not valid.");
                }
            }
            if (addedShips == totalShips)
            {
                btnReady.Enabled = true;
            }
        }
        private void btnAddShip2_Click(object sender, EventArgs e)
        {
            CoordinatesForm form = new CoordinatesForm();
            Button button1 = (Button)sender;
            if (form.ShowDialog() == DialogResult.OK)
            {
                Point coordinates = form.Coordinates;
                // Comprobar que los botones correspondientes al barco elegido no estén ya ocupados por otro barco
                bool free = true;
                for (int i = 0; i < 3; i++)
                {
                    int row = coordinates.Y;
                    int col = coordinates.X + i;
                    Button button = (Button)panel1.Controls.Find(GetRowLabel(row).ToString() + col.ToString(), true)[0];
                    if (button.BackColor != Color.White)
                    {
                        free = false;
                        break;
                    }
                }
                // Comprobar que el barco no se extienda fuera del tablero
                if (coordinates.X + 2 >= 10)
                {
                    free = false;
                }
                if (free)
                {
                    Ship ship = new Ship(3, coordinates, true);
                    ships.Add(ship);
                    addedShips++;
                    // Pintar los botones correspondientes al barco en el panel1
                    for (int i = 0; i < ship.Size; i++)
                    {
                        int row = ship.Location.Y;
                        int col = ship.Location.X + i;
                        Button button = (Button)panel1.Controls.Find(GetRowLabel(row).ToString() + col.ToString(), true)[0];
                        button.BackColor = Color.LightGreen;
                        button1.Enabled = false;
                    }
                }
                else
                {
                    MessageBox.Show("The chosen location is not valid.");
                }
            }
            if (addedShips == totalShips)
            {
                btnReady.Enabled = true;
            }
        }
        private void btnAddShip3_Click(object sender, EventArgs e)
        {
            CoordinatesForm form = new CoordinatesForm();
            Button button1 = (Button)sender;
            if (form.ShowDialog() == DialogResult.OK)
            {
                Point coordinates = form.Coordinates;
                // Comprobar que los botones correspondientes al barco elegido no estén ya ocupados por otro barco
                bool free = true;
                for (int i = 0; i < 4; i++)
                {
                    int row = coordinates.Y;
                    int col = coordinates.X + i;
                    Button button = (Button)panel1.Controls.Find(GetRowLabel(row).ToString() + col.ToString(), true)[0];
                    if (button.BackColor != Color.White)
                    {
                        free = false;
                        break;
                    }
                }
                // Comprobar que el barco no se extienda fuera del tablero
                if (coordinates.X + 3 >= 10)
                {
                    free = false;
                    MessageBox.Show("The chosen location is not valid.");
                }
                if (free)
                {
                    Ship ship = new Ship(4, coordinates, true);
                    ships.Add(ship);
                    addedShips++;
                    // Pintar los botones correspondientes al barco en el panel1
                    for (int i = 0; i < ship.Size; i++)
                    {
                        int row = ship.Location.Y;
                        int col = ship.Location.X + i;
                        Button button = (Button)panel1.Controls.Find(GetRowLabel(row).ToString() + col.ToString(), true)[0];
                        button.BackColor = Color.MediumPurple;
                        button1.Enabled = false;
                    }
                }
                else
                {
                    MessageBox.Show("The chosen location is not valid.");
                }
            }
            if (addedShips == totalShips)
            {
                btnReady.Enabled = true;
            }
        }                
        private void btnClear_Click(object sender, EventArgs e)
        {
            QuitShips();
            btnAddShip1.Enabled = true;
            btnAddShip2.Enabled = true;
            btnAddShip3.Enabled = true;
            btnReady.Enabled = false;
        }
        private void QuitShips()
        {
            foreach (Control control in panel1.Controls)
            {
                if (control is Button button)
                {
                    button.BackColor = Color.White;
                }
            }
            foreach (Control control in panel2.Controls)
            {
                if (control is Button button)
                {
                    button.Enabled = false;
                    button.BackColor = SystemColors.ControlDark;
                }
            }
        }
        private void panel2_ButtonClick(object sender, EventArgs e)
        {
            Button button = (Button)sender;
            foreach (Control control in panel2.Controls)
            {
                if (control is Button btn)
                {
                    btn.Enabled = false;
                }
            }
            c.Send(button.Name.ToString());
            button.Enabled = false;
        }        
        private void btnConnect_Click(object sender, EventArgs e)
        {
            if (txtUser.Text != "")
            {
                c.Connect(txtUser.Text);
                lblMyShips.Text = $"{txtUser.Text}'s ships";
                btnDisconnect.Enabled = true;
                btnAddShip1.Enabled = true;
                btnAddShip2.Enabled = true;
                btnAddShip3.Enabled = true;
                btnClear.Enabled = true;
                btnConnect.Enabled = false;
                txtUser.Enabled = false;
                lblError.Text = "";
            }
            else
            {
                lblError.Text = "Error logging in, you must enter a user.";
            }
        }        
        private void btnDisconnect_Click(object sender, EventArgs e)
        {
            c.Disconnect();
            btnReady.Enabled = false;
            btnAddShip1.Enabled = false;
            btnAddShip2.Enabled = false;
            btnAddShip3.Enabled = false;
            btnClear.Enabled = false;
            addedShips = 0;
            QuitShips();
            btnDisconnect.Enabled = false;
            btnConnect.Enabled = true;
            txtUser.Enabled = true;
            txtUser.Text = "";
            lblMyShips.Text = "My ships";
        }
    }
}

客户经理.cs

namespace Battleship_sockets
{
    public class ClientManager
    {
        private readonly List<TcpClient> clients;

        public ClientManager(List<TcpClient> clients)
        {
            this.clients = clients;
        }

        public void AddClient(TcpClient client)
        {
            clients.Add(client);
            Console.WriteLine($"Client{GetClientes().Count} is connected.");
        }

        public void RemoveClient(TcpClient client)
        {
            Console.WriteLine($"Client{GetClientes().Count} it has disconnected..");
            clients.Remove(client);
        }
        public List<TcpClient> GetClientes()
        {
            return clients;
        }

    }
}

SHIP.cs

public class Ship
{
    public int Size { get; set; }
    public Point Location { get; set; }
    public bool Horizontal { get; set; }
    public int Celdas { get; set; }  

    public Ship(int size, Point location, bool horizontal)
    {
        Size = size;
        Location = location;
        Horizontal = horizontal;
    }
}

坐标.cs

namespace Battleship_sockets
{
    public partial class CoordinatesForm : Form
    {
        public CoordinatesForm()
        {
            InitializeComponent();
            txtRow.Select();
        }
        public Point Coordinates { get; set; }
        private void btnAccept_Click(object sender, EventArgs e)
        {
            if (txtRow.Text != "")
            {
                char row = char.ToUpper(txtRow.Text[0]); // convertir la letra introducida en mayúsculas
                int col = (int)numericUpDownColumn.Value;
                Point coordinates = new Point(col, row - 'A');
                this.Coordinates = coordinates;
                DialogResult = DialogResult.OK;
            }
            else
            {
                lblError.Text = "Row field cannot be empty";
            }
        }
        private void btnCancelar_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.Cancel;
        }
        private void txtRow_KeyPress(object sender, KeyPressEventArgs e)
        {
            // Si el texto ya tiene un carácter, cancela la tecla pulsada
            if (txtRow.Text.Length >= 1 && e.KeyChar != (char)Keys.Back)
            {
                e.Handled = true;
            }
            // Si la tecla pulsada no es una letra de la A a la J o la tecla de retroceso, cancela la tecla pulsada
            if (!char.IsLetter(e.KeyChar) || (e.KeyChar < 'A' || e.KeyChar > 'J') && (e.KeyChar < 'a' || e.KeyChar > 'j') && e.KeyChar != (char)Keys.Back)
            {
                e.Handled = true;
            }
        }

    }
}

试了好几种方法都找不到解决办法。 由于公司要求,必须使用TCP并且服务器必须在同一个客户端程序中。 CONSOLE

c# wpf sockets tcpclient tcplistener
© www.soinside.com 2019 - 2024. All rights reserved.