25.10.14 개발일지
[C# 개인 프로젝트 게임 만들기]
서버-클라이언트 구조 구현
using System.Net;
using System.Net.Sockets;
namespace Server
{
internal class Program
{
static TcpListener? listener;
static readonly List<ClientSession> waiting = new();
static readonly object gate = new();
static readonly Database db = new();
static async Task Main(string[] args)
{
Console.OutputEncoding = System.Text.Encoding.UTF8;
Console.WriteLine("[Penalty Server] starting on :9000 ...");
listener = new TcpListener(IPAddress.Any, 9000);
listener.Start();
_ = Task.Run(MatchMakerLoop);
while (true)
{
var tcp = await listener.AcceptTcpClientAsync();
_ = Task.Run(() => HandleClient(tcp));
}
}
static async Task HandleClient(TcpClient tcp)
{
var session = new ClientSession(tcp);
Console.WriteLine($"[Connect] {session.EndPoint}");
try
{
await session.SendAsync("HELLO");
while (tcp.Connected)
{
var line = await session.ReadLineAsync();
if (line == null) break;
if (line.StartsWith("REGISTER "))
{
var sp = line.Split(' ', StringSplitOptions.RemoveEmptyEntries);
if (sp.Length >= 3 && db.Register(sp[1], sp[2]))
{
session.Username = sp[1];
await session.SendAsync("REGISTER_OK");
}
else await session.SendAsync("REGISTER_FAIL");
}
else if (line.StartsWith("LOGIN "))
{
var sp = line.Split(' ', StringSplitOptions.RemoveEmptyEntries);
if (sp.Length >= 3 && db.Login(sp[1], sp[2]))
{
session.Username = sp[1];
await session.SendAsync("LOGIN_OK");
}
else await session.SendAsync("LOGIN_FAIL");
}
else if (line == "READY")
{
if (string.IsNullOrEmpty(session.Username))
{
await session.SendAsync("NEED_LOGIN");
continue;
}
lock (gate)
{
if (!waiting.Contains(session)) waiting.Add(session);
}
await session.SendAsync("QUEUED");
}
else if (line.StartsWith("SHOOT:") || line.StartsWith("SAVE:"))
{
session.CurrentMatch?.OnPlayerActionAsync(session, line);
}
else if (line == "PING") { await session.SendAsync("PONG"); }
else { await session.SendAsync("ERR"); }
}
}
catch (Exception ex)
{
Console.WriteLine($"[Err] {ex.Message}");
}
finally
{
Console.WriteLine($"[Disconnect] {session.EndPoint}");
lock (gate) waiting.Remove(session);
if (session.CurrentMatch != null) await session.CurrentMatch.AbortAsync(session);
session.Dispose();
}
}
static async Task MatchMakerLoop()
{
while (true)
{
await Task.Delay(200);
ClientSession? a = null, b = null;
lock (gate)
{
if (waiting.Count >= 2)
{
a = waiting[0];
b = waiting[1];
waiting.RemoveRange(0, 2);
}
}
if (a != null && b != null)
{
var match = new Match(a, b, db);
_ = match.RunAsync();
}
}
}
}
}

기존에 1p로만 가능한 페널티킥 게임에서
서버-클라이언트 구조를 만들어서 클라이언트 2명이 키커와 골키퍼를 번갈아가면서 게임할 수 있게 만들었다.

로그인 해서 2명의 클라이언트가 2p로 게임 가능
내일 ui 좀 더 손볼 예정이다.

: 서버 콘솔 화면
DB 연결
CREATE DATABASE IF NOT EXISTS penaltydb CHARACTER SET utf8mb4;
USE penaltydb;
CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
wins INT DEFAULT 0,
losses INT DEFAULT 0,
games_played INT DEFAULT 0,
`rank` VARCHAR(20) DEFAULT 'Bronze'
);
CREATE TABLE IF NOT EXISTS match_history (
match_id INT AUTO_INCREMENT PRIMARY KEY,
player1 VARCHAR(50),
player2 VARCHAR(50),
winner VARCHAR(50),
score VARCHAR(20),
played_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

로그인/회원가입 회원정보와 매치 기록을 DB에 저장한다.
이후 이 매치 기록을 이용해서 랭크 시스템도 만들 예정이다.
'10월 개발일지' 카테고리의 다른 글
| 25.10.16 개발일지(C# 개인 프로젝트 게임 만들기) (0) | 2025.11.17 |
|---|---|
| 25.10.15 개발일지(C# 개인 프로젝트 게임 만들기) (0) | 2025.11.16 |
| 25.10.13 개발일지(이것이 C#이다 chapter 21, 22) (0) | 2025.11.16 |
| 25.10.06 개발일지(이것이 C#이다 chapter 20) (0) | 2025.11.16 |
| 25.10.05 개발일지(이것이 C#이다 chapter 13, 19) (0) | 2025.11.16 |