我有一个模拟游戏“战舰”的程序,同时充当服务器和客户端。
在菜单中,我选择是作为服务器(我调用服务器的启动方法,控制台打开,然后我进入游戏屏幕)还是作为客户端(我进入游戏屏幕)进行游戏。
我运行程序两次,第一次选择服务器,第二次选择客户端。
第一个界面工作正常,我对第二个界面的问题是它没有将所有消息正确发送到服务器并且没有收到任何回复。
我在这里附上我的代码:
服务器.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;
}
}
}
}