need help to fix sockets problem

lmbdr 20 Reputation points
2023-03-28T10:29:44.7366667+00:00

I have a single program that simulates the game "Battleships", acting as both server and client.

In the menu I choose whether to play as a server (I call the server's Start method, a console opens and I go to the game screen) or as a client (I go to the game screen).

I run the program twice, the first time selecting server and the second time selecting client.

The first interface works fine, the problem I have with the second one is that it doesn't send all the messages to the server correctly and it doesn't receive any replies.

I attach my code here:

SERVER.cs

#region CLASE SERVER
    public class Server
    {
        #region ATTRIBUTES
        public TcpListener tcpListener;

        // Lista de clientes conectados
        static List<TcpClient> clientes = new List<TcpClient>();

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

        #region START
        public void 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("Servidor iniciado y escuchando en el puerto 8080...");

                while (true)
                {
                    TcpClient cliente =  tcpListener.AcceptTcpClient();

                    // Iniciar un hilo para manejar la conexión del cliente
                    Task.Run(() => HandleClient(cliente));
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }
        #endregion

        #region HANDLE CLIENT
        public static void HandleClient(TcpClient client)
        {
            using NetworkStream stream = client.GetStream();

            try
            {
                #region 1
                // Agregar el cliente a la lista de clientes conectados
                clientes.Add(client);
                Console.WriteLine($"Cliente {clientes.Count} añadido.");

                // Leer mensajes del servidor
                byte[] buffer = new byte[1024];
                int bytesRead =  stream.Read(buffer);
                string message = Encoding.ASCII.GetString(buffer, 0, bytesRead);
                Console.WriteLine($"- Cliente {clientes.Count}: {message}");

                // Verificar si hay dos clientes conectados
                if (clientes.Count == 2)
                {
                    Console.WriteLine("Ambos clientes conectados.");
                    Console.WriteLine("Preprados para jugar...");
                }
                else
                {
                    Console.WriteLine("Esperando a que se conecte otro cliente...");
                }

                #endregion
            }
            catch (Exception e)
            {
                Console.WriteLine($"Error en el cliente: {e.Message}");

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

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

        #region LISTO
        public static void Listo()
        {
            try
            {
                while (clientes.Count != 2)
                {
                    Console.WriteLine("No hay otro cliente conectado.");                   
                }
                Console.WriteLine($"El jugador {clientes.Count} está listo.");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
        #endregion

        #region REMOVE
        public void Remove(TcpClient client)
        {
            while (clientes.Count != 0)
            {
                Console.WriteLine($"El cliente{clientes.Count} se ha desconectado");
                clientes.Remove(client);
            }
        }
        #endregion
    }
    #endregion

CLIENT.cs

#region CLASE CLIENTE
    public class Cliente
    {
        #region ATTRIBUTES
        public TcpClient tcpClient;
        private NetworkStream stream;
        #endregion
        #region CONECTAR
        public void Conectar(string name)
        {
            try
            {
                // Conectar al servidor
                tcpClient = new TcpClient();
                tcpClient.Connect(IPAddress.Parse("127.0.0.1"), 8080);
                stream = tcpClient.GetStream();
                // Enviar datos al servidor
                string mensaje = $"Hola, soy {name}";
                byte[] buffer = Encoding.ASCII.GetBytes(mensaje);
                stream.Write(buffer);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }
        #endregion
        #region SEND
        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());
            }
        }
        #endregion
        #region DESCONECTAR
        public void Desconectar()
        {
            try
            {
                Server sv = new Server();
                Task.Run(() => sv.Remove(tcpClient));
                tcpClient.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
        #endregion
    }
    #endregion

MENU.cs

#region CLASE MENU
    public partial class MainMenu : Form
    {
        #region ATTRIBUTES
        private Server s;
        private Form1? form1;
        #endregion
        public MainMenu()
        {
            #region COMPONENTS
            InitializeComponent();
            s = new Server();
            #endregion
        }
        #region BOTÓN SERVIDOR
        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
        }
        #endregion
        #region BOTÓN CLIENTE
        private void btnCliente_Click(object sender, EventArgs e)
        {
            form1 = new Form1();
            form1.ShowDialog(); // muestra el nuevo formulario como cuadro de diálogo modal
            this.Close(); // cierra el formulario actual cuando se cierre el nuevo formulario
        }
        #endregion
    }
    #endregion

Form1.cs

#region CLASE FORM
    public partial class Form1 : Form
    {
        #region ATRIBUTOS
        public Cliente c;
        public Server s;
        private List<Barco> barcos = new List<Barco>();
        private int barcosTotales = 3;
        private int barcosAgregados;
        #endregion
        public Form1()
        {
            #region INICIAL
            InitializeComponent();
            CreateButtons();
            c = new Cliente();
            s = new Server();
            btnReady.Enabled = false;
            btnAdd1.Enabled = false;
            btnAdd2.Enabled = false;
            btnAdd3.Enabled = false;
            btnClear.Enabled = false;
            btnDesconectar.Enabled = false;
            #endregion
        }
        #region CREAR TABLEROS
        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);
                }
            }
        }
        #endregion
        #region READY
        private void btnReady_Click(object sender, EventArgs e)
        {
            // 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;
            Server.Listo();
        }
        #endregion
        #region AÑADIR BARCOS
        #region AÑADIR PORTAAVIONES
        private void btnAdd1_Click(object sender, EventArgs e)
        {
            CoordenadasForm form = new CoordenadasForm();
            Button button1 = (Button)sender;
            if (form.ShowDialog() == DialogResult.OK)
            {
                Point coordenadas = form.Coordenadas;
                // Comprobar que los botones correspondientes al barco elegido no estén ya ocupados por otro barco
                bool libre = true;
                for (int i = 0; i < 5; i++)
                {
                    int row = coordenadas.Y;
                    int col = coordenadas.X + i;
                    Button button = (Button)panel1.Controls.Find(GetRowLabel(row).ToString() + col.ToString(), true)[0];
                    if (button.BackColor != Color.White)
                    {
                        libre = false;
                        break;
                    }
                }
                // Comprobar que el barco no se extienda fuera del tablero
                if (coordenadas.X + 4 >= 10)
                {
                    libre = false;
                    MessageBox.Show("La ubicación elegida no es válida.");
                }
                if (libre)
                {
                    Barco barco = new Barco(5, coordenadas, true);
                    barcos.Add(barco);
                    barcosAgregados++;
                    // Pintar los botones correspondientes al barco en el panel1
                    for (int i = 0; i < barco.Size; i++)
                    {
                        int row = barco.Location.Y;
                        int col = barco.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("La ubicación elegida no es válida.");
                }
            }
            if (barcosAgregados == barcosTotales)
            {
                btnReady.Enabled = true;
            }
        }
        #endregion
        #region AÑADIR YATE 
        private void btnAdd3_Click(object sender, EventArgs e)
        {
            CoordenadasForm form = new CoordenadasForm();
            Button button1 = (Button)sender;
            if (form.ShowDialog() == DialogResult.OK)
            {
                Point coordenadas = form.Coordenadas;
                // Comprobar que los botones correspondientes al barco elegido no estén ya ocupados por otro barco
                bool libre = true;
                for (int i = 0; i < 4; i++)
                {
                    int row = coordenadas.Y;
                    int col = coordenadas.X + i;
                    Button button = (Button)panel1.Controls.Find(GetRowLabel(row).ToString() + col.ToString(), true)[0];
                    if (button.BackColor != Color.White)
                    {
                        libre = false;
                        break;
                    }
                }
                // Comprobar que el barco no se extienda fuera del tablero
                if (coordenadas.X + 3 >= 10)
                {
                    libre = false;
                    MessageBox.Show("La ubicación elegida no es válida.");
                }
                if (libre)
                {
                    Barco barco = new Barco(4, coordenadas, true);
                    barcos.Add(barco);
                    barcosAgregados++;
                    // Pintar los botones correspondientes al barco en el panel1
                    for (int i = 0; i < barco.Size; i++)
                    {
                        int row = barco.Location.Y;
                        int col = barco.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("La ubicación elegida no es válida.");
                }
            }
            if (barcosAgregados == barcosTotales)
            {
                btnReady.Enabled = true;
            }
        }
        #endregion
        #region AÑADIR VELERO
        private void btnAdd2_Click(object sender, EventArgs e)
        {
            CoordenadasForm form = new CoordenadasForm();
            Button button1 = (Button)sender;
            if (form.ShowDialog() == DialogResult.OK)
            {
                Point coordenadas = form.Coordenadas;
                // Comprobar que los botones correspondientes al barco elegido no estén ya ocupados por otro barco
                bool libre = true;
                for (int i = 0; i < 3; i++)
                {
                    int row = coordenadas.Y;
                    int col = coordenadas.X + i;
                    Button button = (Button)panel1.Controls.Find(GetRowLabel(row).ToString() + col.ToString(), true)[0];
                    if (button.BackColor != Color.White)
                    {
                        libre = false;
                        break;
                    }
                }
                // Comprobar que el barco no se extienda fuera del tablero
                if (coordenadas.X + 2 >= 10)
                {
                    libre = false;
                }
                if (libre)
                {
                    Barco barco = new Barco(3, coordenadas, true);
                    barcos.Add(barco);
                    barcosAgregados++;
                    // Pintar los botones correspondientes al barco en el panel1
                    for (int i = 0; i < barco.Size; i++)
                    {
                        int row = barco.Location.Y;
                        int col = barco.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("La ubicación elegida no es válida.");
                }
            }
            if (barcosAgregados == barcosTotales)
            {
                btnReady.Enabled = true;
            }
        }
        #endregion
        #endregion
        #region QUITAR BARCOS
        private void btnClear_Click(object sender, EventArgs e)
        {
            QuitShips();
            btnAdd1.Enabled = true;
            btnAdd2.Enabled = true;
            btnAdd3.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;
                }
            }
        }
        #endregion
        #region ATACAR
        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;
        }
        #endregion
        #region CONECTAR
        private void btnConectar_Click(object sender, EventArgs e)
        {
            if (txtUser.Text != "")
            {
                c.Conectar(txtUser.Text);
                lblMisbarcos.Text = $"Barcos de {txtUser.Text}";
                btnDesconectar.Enabled = true;
                btnAdd1.Enabled = true;
                btnAdd2.Enabled = true;
                btnAdd3.Enabled = true;
                btnClear.Enabled = true;
                btnConectar.Enabled = false;
                txtUser.Enabled = false;
                lblError.Text = "";
            }
            else
            {
                lblError.Text = "Error al conectar, debe introducir un usuario.";
            }
        }
        #endregion
        #region DESCONECTAR
        private void btnDesconectar_Click(object sender, EventArgs e)
        {
            c.Desconectar();
            btnReady.Enabled = false;
            btnAdd1.Enabled = false;
            btnAdd2.Enabled = false;
            btnAdd3.Enabled = false;
            btnClear.Enabled = false;
            barcosAgregados = 0;
            QuitShips();
            btnDesconectar.Enabled = false;
            btnConectar.Enabled = true;
            txtUser.Enabled = true;
            txtUser.Text = "";
            lblMisbarcos.Text = "Mis Barcos";
        }
        #endregion
    }
    #endregion
Windows Forms
Windows Forms
A set of .NET Framework managed libraries for developing graphical user interfaces.
1,891 questions
Visual Studio
Visual Studio
A family of Microsoft suites of integrated development tools for building applications for Windows, the web and mobile devices.
5,118 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,924 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Jack J Jun 24,491 Reputation points Microsoft Vendor
    2023-03-29T09:53:41.6533333+00:00

    @lmbdr, Welcome to Microsoft Q&A, based on my test, I reproduced your problem. We need to set the loop for receiving message.

    Please try the following change:

    Start method:

           public TcpClient cliente;
            #region START
            public void 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("Servidor iniciado y escuchando en el puerto 8080...");
                    while(true)
                    {
                        cliente = tcpListener.AcceptTcpClient();
    
                        // Iniciar un hilo para manejar la conexión del cliente
                        //HandleClient(cliente);
                        Task.Run(() => HandleClient(cliente));
                    }
                        
                   
    
    
                    //while (true)
                    //{
                        
                    //}
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                }
            }
    

    Hanldeclient:

            public static void HandleClient(TcpClient client)
            {
                using NetworkStream stream = client.GetStream();
                clientes.Add(client);
                Console.WriteLine($"Cliente {clientes.Count} añadido.");
                try
    
                {
                    while(true)
                    {
                        #region 1
                        // Agregar el cliente a la lista de clientes conectados
                    
    
                        // Leer mensajes del servidor
                        byte[] buffer = new byte[1024];
                        int bytesRead = stream.Read(buffer);
                        string message = Encoding.ASCII.GetString(buffer, 0, bytesRead);
                        Console.WriteLine($"- Cliente {clientes.Count}: {message}");
    
                        // Verificar si hay dos clientes conectados
                        if (clientes.Count == 2)
                        {
                            Console.WriteLine("Ambos clientes conectados.");
                            Console.WriteLine("Preprados para jugar...");
                        }
                        else
                        {
                            Console.WriteLine("Esperando a que se conecte otro cliente...");
                        }
    
                        #endregion
                    }
    
                }
                catch (Exception e)
                {
                    Console.WriteLine($"Error en el cliente: {e.Message}");
    
                    // Eliminar el cliente de la lista de clientes
                    clientes.Remove(client);
    
                    // Cerrar la conexión con el cliente
                    client.Close();
                }
            }
    
    

    Tested result:

    User's image

    Best Regards,

    Jack


    If the answer is the right solution, please click "Accept Answer" and upvote it.If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.