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