C# winform 簡單五子棋 200程式碼實現雙人網路匹配對戰
接上次的五子棋案例,此次實現的是在區域網中的簡單匹配對戰,即當一個玩家點選準備對戰時,連線伺服器並開啟一個執行緒監聽伺服器反饋回來的訊息,然後解析訊息,執行對應操作。
伺服器匹配思路:
(1)收到玩家1的準備資訊,把玩家1加入到準備佇列
(2)收到玩家2的準備資訊,把玩家2加入到準備佇列
(3)當準備佇列有兩個人時,把這兩個ip的玩家合成一個在玩局加入到正在遊戲佇列,同時從準備佇列中移除這兩個玩家
(4)當伺服器收到玩家資訊時去查詢正在遊戲佇列中包含收到玩家資訊的ip,把對應訊息給這兩個ip返回
(5)客戶端對伺服器返回的訊息解析,執行不同的操作
伺服器端程式碼:
客戶端實體類Client
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Threading;
namespace Server
{
class Client
{
private Socket clientSocket;
private Thread t;
private byte[]data=new byte[1024];
public string ipaddress;
public Client(Socket s,string ipaddress)
{
clientSocket = s;
this.ipaddress = ipaddress;
t=new Thread(ReceiveMessage);
t.Start();
}
private void ReceiveMessage()
{
while (true)
{
//在接收資料之前 判斷Socket連線是否斷開
if (clientSocket.Poll(10,SelectMode.SelectRead))
{
clientSocket.Close();
break;
}
int length=clientSocket.Receive(data);
string message = Encoding.UTF8.GetString(data, 0, length);
Console.WriteLine(message);
if (message.Contains("|||Ready|||") && !message.Contains(":"))
{
if (!Program.ReadyClientList.Contains(message.Split('|')[0]))
{
Program.ReadyClientList.Add(message.Split('|')[0]);
}
}
if (Program.GameingClientList.Count > 0)
{
foreach (var temp in Program.GameingClientList)
{
if ((message.Contains(temp.ip1) || message.Contains(temp.ip2) ))
{
foreach (var Temp in Program.clientList)
{
if (Temp.ipaddress == temp.ip1 || Temp.ipaddress == temp.ip2)
{
Temp.SendMessage(message);
}
}
if (message.Equals(temp.ip1 + "|||GameOver|||") || message.Equals(temp.ip2 + "|||GameOver|||"))
{
if (!Program.GameingCancelClientList.Contains(temp))
Program.GameingCancelClientList.Add(temp);
}
}
}
}
if (message.Contains("|||Cancel|||") && !message.Contains(":"))
{
if (!Program.ReadyCancelClientList.Contains(message.Split('|')[0]))
Program.ReadyCancelClientList.Add(message.Split('|')[0]);
}
//清除不在準備遊戲列表的對戰組別
if (Program.ReadyCancelClientList.Count > 0)
{
foreach (var temp in Program.ReadyCancelClientList)
{
if (Program.ReadyClientList.Contains(temp))
{
Program.ReadyClientList.Remove(temp);
}
}
Program.ReadyCancelClientList.Clear();
}
//清除不在遊戲列表的對戰組別
if (Program.GameingCancelClientList.Count > 0)
{
foreach (var temp in Program.GameingCancelClientList)
{
if (Program.GameingClientList.Contains(temp))
{
Program.GameingClientList.Remove(temp);
}
}
Program.GameingCancelClientList.Clear();
}
//Console.WriteLine(Program.ReadyClientList.Count);
if (Program.ReadyClientList.Count >= 2)
{
Program.MyStruct myStruct = new Program.MyStruct();
myStruct.ip1 = Program.ReadyClientList[0];
myStruct.ip2 = Program.ReadyClientList[1];
Program.GameingClientList.Add(myStruct);
//Console.WriteLine(myStruct.ip1+" "+myStruct.ip2);
//bool FirstRun = false;
//string FristIp = "";
foreach (var temp in Program.clientList)
{
if (temp.ipaddress == myStruct.ip1)
{
//temp.SendMessage(temp.ipaddress + "||加入房間" + "\n" + "IP為" + temp.ipaddress + "玩家先走!");
//temp.SendMessage("IP為" + temp.ipaddress + "玩家先走!");
//FristIp = temp.ipaddress;
//temp.SendMessage("|||CanDownChess|||");
temp.SendMessage(myStruct.ip2 + "|||CanGame|||" + "|||CanDownChess|||");
//FirstRun = true;
//temp.SendMessage(temp.ipaddress + "加入房間");
// Console.WriteLine(temp.ipaddress);
}
if (temp.ipaddress == myStruct.ip2)
{
//temp.SendMessage(temp.ipaddress + "||加入房間" + "\n" + "IP為" + FristIp + "玩家先走!");
temp.SendMessage(myStruct.ip1 + "|||CanGame|||" );
//temp.SendMessage("IP為" + FristIp + "玩家先走!");
//Console.WriteLine(temp.ipaddress);
}
}
Program.ReadyClientList.Clear();
}
Program.UpdateClientList();
//Console.WriteLine("當前連線人數為:"+Program.clientList.Count);
}
}
public void SendMessage(string s)
{
byte[] _data = Encoding.UTF8.GetBytes(s);
if (clientSocket.Connected)
{
try
{
clientSocket.Send(_data,_data.Length,SocketFlags.None);
}
catch (SocketException)
{
Console.WriteLine("套接字連線異常!");
throw;
}
}
}
public bool Connected
{
get { return clientSocket.Connected; }
}
}
}
主類Program
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Net;
using System.Threading.Tasks;
namespace Server
{
class Program
{
public struct MyStruct
{
public string ip1;
public string ip2;
}
//所有連線過的客戶端
public static List<Client> clientList = new List<Client>();
//所有準備遊戲的客戶端
public static List<string> ReadyClientList = new List<string>();
public static List<string> ReadyCancelClientList = new List<string>();
//所有正在遊戲的客戶端組
public static List<MyStruct> GameingClientList = new List<MyStruct>();
public static List<MyStruct> GameingCancelClientList = new List<MyStruct>();
//檢查從clientList清除沒有連線伺服器的客戶端
public static void UpdateClientList()
{
var notConnectedList=new List<Client>();
foreach (var client in clientList)
{
if(!client.Connected)
notConnectedList.Add(client);
}
//清除不連線的客戶端
foreach (var temp in notConnectedList)
{
clientList.Remove(temp);
}
notConnectedList.Clear();
}
static string ipaddress = "125.217.40.147";
static void Main(string[] args)
{
Socket socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
socket.Bind(new IPEndPoint(IPAddress.Parse(ipaddress),7788));
socket.Listen(100);
Console.WriteLine("伺服器正在執行......");
while (true)
{
Socket clientSocket = socket.Accept();
Console.WriteLine("IP為"+((IPEndPoint)clientSocket.RemoteEndPoint).Address + "的客戶端與伺服器進行了連線!");
Client client = new Client(clientSocket, ((IPEndPoint)clientSocket.RemoteEndPoint).Address.ToString());//把每個客戶端通訊的邏輯放到client類進行處理
client.SendMessage(client.ipaddress + "|||Welcome to the world of Wzq|||");
clientList.Add(client);
}
}
}
}
客戶端連線:
private string ipaddress = "125.217.40.147";
private int port = 7788;
public Socket clientSocket;
private Thread t;
private byte[]data=new byte[1024];
private string message = "";
public string IpAddress;
// 執行緒監聽,自己定義,自己在使用時呼叫
// 解析message並執行操作
void Update (){
}
public void ConnectToServer()
{
clientSocket=new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);
//跟伺服器進行連線
try
{
clientSocket.Connect(new IPEndPoint(IPAddress.Parse(ipaddress), port));
}
catch (Exception)
{
// show "很遺憾你沒有連線上伺服器,請點選準備遊戲重新連線!";
throw;
}
//建立一個新的執行緒用於接收訊息
if (clientSocket.Connected)
{
t = new Thread(Receivemessage);
t.Start();
}
}
void Receivemessage()
{
while (true)
{
if (clientSocket.Connected==false)
{
break;
}
int length = clientSocket.Receive(data);
message = Encoding.UTF8.GetString(data, 0, length);
}
}
public void Sendmessage(string s)
{
byte[] data = Encoding.UTF8.GetBytes(s);
clientSocket.Send(data);
}
準備遊戲呼叫:Sendmessage(your IpAddress + "|||Ready|||");
取消準備呼叫:Sendmessage(your IpAddress+"|||Cancel|||");
下棋時呼叫:Sendmessage(your IpAddress + "|||CanDownChess|||" + "chess|||" + 棋子x座標 + "|" + 棋子y座標);
悔棋時呼叫:Sendmessage(your IpAddress+"|||Regred|||");
認輸或者中途退出遊戲時呼叫:Sendmessage(your IpAddress + "|||Surrender|||");
這樣,簡單的匹配對戰就完成了。當然,解析伺服器返回訊息並執行操作自己實現。這個只是個簡單的思路,實際實現和伺服器傳遞訊息要做相應的請求介面,如果要長久儲存資料,還要引入資料庫的內容。