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;
namespace TestBoom
{
class Client //這是封裝好的使用者端類
{
public String receivestr = null;
private static Client client;
private Socket ClientSocket;
private Client(string ip1, int port1)
{
ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Init(ip1, port1);
}
public static Client clientsocket(string ip1,int port1)
{
if (client == null)
{
client = new Client(ip1,port1);
}
return client;
}
private void Init(string ip1, int port1)
{
IPEndPoint iPEnd = new IPEndPoint(IPAddress.Parse(ip1), port1);
ClientSocket.Connect(iPEnd);
Thread reciveThread = new Thread(Recive);
reciveThread.IsBackground = true;
reciveThread.Start();
}
public void Recive()
{
while (true)
{
byte[] Btye = new byte[1024];
ClientSocket.Receive(Btye);
receivestr = Encoding.UTF8.GetString(Btye,0,3);
if (receivestr[0] == '0')
{
Console.WriteLine($"接受對方了轟炸位置{receivestr}");
}
else if(receivestr[0]=='1')
{
Console.WriteLine($"接受轟炸位置結果{receivestr}");
}
}
}
public void Send(int i,int x,int y)
{
string str =Convert.ToString(i)+Convert.ToString(x) + Convert.ToString(y);
byte[] Btye = Encoding.UTF8.GetBytes(str);
ClientSocket.Send(Btye);
if (str[0] == '0')
{
Console.WriteLine($"已傳送轟炸位置 {str}");
}
else if (str[0] == '1')
{
Console.WriteLine($"已傳送對方轟炸位置結果{str}");
}
}
}
}
1. 首先這個遊戲我們必須要知道的一點是我們想要實現兩臺電腦之間的互動,就必須使用ip和埠進行連線,而想要進行連線就必須使用一個範例化的物件(在這裡我沒有體現出來,因為範例化物件在另一個from中,在按鈕事務響應的函數中進行範例化),而且在這個遊戲中,範例化物件必須是單例模型,原因之前提到過,那麼範例化物件就必須包含單例化的過程;
public String receivestr = null; //receivestr是接受函數中接收到對方的傳輸過來的資訊,後面用到
private static Client client; //單例化物件所需要的物件
private Socket ClientSocket; //Socket類的一個範例化物件
private Client(string ip1, int port1) //Client()使用者端建構函式
{
ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Init(ip1, port1);
}
public static Client clientsocket(string ip1,int port1) //單例化實現函數
{
if (client == null) //如果範例化物件不存在,則建立一個
{
client = new Client(ip1,port1);
}
return client; //如果存在,則直接返回存在的那個物件,這樣便實現了單例化
}
private void Init(string ip1, int port1) //初始化,用於進行使用者端和伺服器端的連線
{
IPEndPoint iPEnd = new IPEndPoint(IPAddress.Parse(ip1), port1);
ClientSocket.Connect(iPEnd);
Thread reciveThread = new Thread(Recive);
reciveThread.IsBackground = true;
reciveThread.Start();
}
2. 其次在連線妥當之後,必須進行資訊傳輸,如果而現在假定使用者端時先手,則要進行 send() 函數的呼叫,在函數中你可以傳送任意的資料,但必須時btye陣列(因為在物理層傳輸資料是傳送的是位元,傳送到對方物理層會進行解析還原,但是這些東西C#的Socket類已經封裝好了,我們呼叫介面即可),需要注意的是在使用 send() 的時候必須呼叫(這個之後再詳細說);
public void Send(int i,int x,int y) //這裡面的引數 i,x,y 的含義分別是 模式0/1,x座標, y座標,可以根據需求改變
{
string str =Convert.ToString(i)+Convert.ToString(x) + Convert.ToString(y); //將數位轉化為string型別字串
byte[] Btye = Encoding.UTF8.GetBytes(str); //將剛剛轉化好的string型別字串轉化為byte型別陣列
ClientSocket.Send(Btye); //呼叫Socket類中的Send()函數傳送資料
if (str[0] == '0') //判斷模式0/1,在己方控制檯顯示己方傳送過去的內容,方便自己檢視
{
Console.WriteLine($"已傳送轟炸位置 {str}");
}
else if (str[0] == '1')
{
Console.WriteLine($"已傳送對方轟炸位置結果{str}");
}
}
3. 最後闡述一下 receive() 函數,再對方(伺服器端)接收到你傳送的資訊之後,一定會返回一個資訊(因為下棋是互動的嘛),這時候你便需要一個接收函數 receive() ,這個函數是用來接受對方傳送的資訊的,但是需要注意的是這個函數會隨著你的程序一直執行,在from中是不需要呼叫的。
public void Recive()
{
while (true) //因為是一直在另一個程序中執行,所以給一個死迴圈
{
byte[] Btye = new byte[1024]; //接收也是byte陣列的
ClientSocket.Receive(Btye);
receivestr = Encoding.UTF8.GetString(Btye,0,3); //轉化為string型別
if (receivestr[0] == '0') //判斷模式0/1,在己方控制檯顯示對方傳送過來的內容,方便檢視對方資訊
{
Console.WriteLine($"接受對方了轟炸位置{receivestr}");
}
else if(receivestr[0]=='1')
{
Console.WriteLine($"接受轟炸位置結果{receivestr}");
}
}
}
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;
namespace TestBoom
{
class Server
{
public String receivestr = null;
private Socket SocketWatch;
private Socket SocketSend;
private static Server server = null;
private Server(string ip1, int port1)
{
SocketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Init(ip1,port1);
}
public static Server serversocket(string ip1, int port1)
{
if (server == null)
{
server = new Server(ip1, port1);
}
return server;
}
private void Init(string ip1, int port1)
{
SocketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint iPEnd = new IPEndPoint(IPAddress.Parse(ip1), port1);
SocketWatch.Bind(iPEnd);
SocketWatch.Listen(1);
System.Windows.Forms.MessageBox.Show("開始監聽...");
Thread thread = new Thread(Listen);
thread.IsBackground = true;
thread.Start();
}
void Listen()
{
while (SocketSend==null)
{
SocketSend = SocketWatch.Accept();
}
System.Windows.Forms.MessageBox.Show("連線成功..." + SocketSend.RemoteEndPoint.ToString());
Thread reciveThread = new Thread(Recive);
reciveThread.IsBackground = true;
reciveThread.Start();
}
public void Recive()
{
while (true)
{
byte[] buffer = new byte[1024];
SocketSend.Receive(buffer);
receivestr = Encoding.UTF8.GetString(buffer, 0, 3);
if (receivestr[0] == '0')
{
Console.WriteLine($"接受對方了轟炸位置{receivestr}");
}
else if (receivestr[0] == '1')
{
Console.WriteLine($"接受我方轟炸位置結果{receivestr}");
}
}
}
public void Send(int i,int x,int y)
{
string str = Convert.ToString(i) + Convert.ToString(x) + Convert.ToString(y);
byte[] buffer = Encoding.UTF8.GetBytes(str);
SocketSend.Send(buffer);
if (str[0] == '0')
{
Console.WriteLine($"已傳送轟炸位置 {str}");
}
else if (str[0] == '1')
{
Console.WriteLine($"已傳送對方轟炸位置結果{str}");
}
}
}
}
private void button2_Click(object sender, EventArgs e)
{
if (Plane_Sum < 3)
{
label4.Text = "請先放置坤坤";
}
else
{
if(ipok && portok)
{
label4.Text = "坤坤已放置好";
label3.Text = "你的回合";
client = Client.clientsocket(ip,port); //範例化使用者端
serorcli = true;
}
else
{
label4.Text = "沒有輸入ip或者埠";
}
}
}
private void button1_Click(object sender, EventArgs e)
{
if (Plane_Sum < 3)
{
label4.Text = "請先放置坤坤";
}
else
{
if(ipok && portok)
{
label4.Text = "坤坤已放置好";
label3.Text = "對手回合";
server = Server.serversocket(ip, port); //範例化伺服器端
serorcli = false;
}
else
{
label4.Text = "沒有輸入ip或者埠";
}
}
}
private void button3_Click(object sender, EventArgs e)
{
if (Plane_Sum < 3)
{
label4.Text = "請先放置坤坤";
}
else
{
if (serorcli == false&&ipok&&portok)
{
while (server.receivestr == null) { } //判斷有沒有接收,直到有接收才可以跳出迴圈
if (server.receivestr[0] == '0')//接收直接使用,由於接收是處於一直接收的狀態
{
PutKunKun2(server.receivestr[1] - '0', server.receivestr[2] - '0');
server.Send(1, Board1[server.receivestr[1] - '0', server.receivestr[2] - '0'], 0); //傳送呼叫
server.receivestr = null; //賦值為null,為下一次接收做準備
}
}
}
}
private void textBox1_ipChanged(object sender, EventArgs e)
{
ip = textBox1.Text; //輸入ip
ipok = true;
}
private void textBox2_portChanged(object sender, EventArgs e)
{
int.TryParse(textBox2.Text,out port); //輸入port
portok = true;
}
在這個專案中,我對計算機網路中學習的內容有了更深的理解,對Socket通訊有了更深的認識,對TCP和UDP也有了不同於書本單薄的理解。