網絡遊戲是一種人們娛樂休閒互交的應用軟件。既然是互交,當然需要彼此間的瞭解通訊。要通訊那必須需要Socket:我們今天要實現的主角即套接字。Socket的英文原義是“孔”或“插座”,正如其英文原意那樣,象一個多孔插座。一臺電腦機器猶如佈滿各種插座的房間,每個插座有一個編號,有的插座提供220伏交流電, 有的提供110伏交流電,有的則提供有線電視節目。 客戶軟件將插頭插到不同編號的插座,就可以得到不同的服務。下面我們來看看下圖,遊戲中玩家移動是如何通訊:
下面是Unity3d遊戲通訊Socket實現: BaseGameSocket.cs
@原創:dongfu.luo
using System;
using System.Collections.Generic;
using System.Net.Sockets;
{
//用來接收服務端發過來的緩衝Buff
private byte[] _data_buffer;
//緩衝二進制數組從哪裏開始讀
private int _data_offset;
//緩衝二進制數組讀多少個byte
private int _data_size;
//遊戲服務器IP地址
private string _ip;
private bool _is_read_head;
//遊戲服務器端口
private int _port;
//要服務端發送的數據命令列表
private List<PacketOut> _send_list = new List<PacketOut>();
private Socket _sock;
private const int MAX_SEND_QUEUE = 0x3e8;
//清空數據,一般是在斷開重聯時候調用
{
this._ip = null;
this._port = 0;
this._sock = null;
List<PacketOut> list = this._send_list;
lock (list)
{
this._send_list.Clear();
}
this._is_read_head = false;
this._data_buffer = null;
this._data_offset = 0;
this._data_size = 0;
}
//關閉客戶端的Socket
{
try
{
Socket socket = this._sock;
this.Clear();
if ((socket != null) && socket.Connected)
{
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
}
catch (Exception exception)
{
UEDebug.LogError("Connect: " + exception.ToString());
this.Error(Lang.GetString("k3432"));
}
}
//連接遊戲服務端
{
try
{
this.Close();
this._ip = ip;
this._port = port;
this._sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
this._sock.NoDelay = true;
this._sock.BeginConnect(this._ip, this._port, new AsyncCallback(this.OnConnect), this._sock);
}
catch (Exception exception)
{
UEDebug.LogError("Connect: " + exception.ToString());
this.Error(Lang.GetString("k3432"));
}
}
//如果Socket沒有關閉繼續等服務器信息,如果有信息則開始讀
{
try
{
if (this.IsConnected)
{
this._sock.BeginReceive(this._data_buffer, this._data_offset, this._data_size - this._data_offset, SocketFlags.None, new AsyncCallback(this.OnRead), null);
}
}
catch (Exception exception)
{
UEDebug.LogError(exception.ToString());
this.Error(Lang.GetString("k3432"));
}
}
//從發送隊列從不斷向遊戲服務器發送命令
{
PacketOut state = null;
List<PacketOut> list = this._send_list;
lock (list)
{
if (this._send_list.Count == 0)
{
return;
}
state = this._send_list[0];
if (state.start)
{
return;
}
state.start = true;
}
Socket sock = state.sock;
if (sock.Connected)
{
sock.BeginSend(state.buff, 0, state.buff.Length, SocketFlags.None, new AsyncCallback(this.OnSend), state);
}
}
//發送失敗或錯誤,則關閉Socket一般是網絡斷了服務器關閉了
{
this.Close();
this.OnError(msg);
}
//程序猿都知道這是析構函數
{
this.Close();
}
{
List<PacketOut> list = this._send_list;
lock (list)
{
return this._send_list.Count;
}
}
//此函數由子類去處理
//如果是第一次連接上了,解析消息頭
private void OnConnect(IAsyncResult ret)
{
if (ret.AsyncState == this._sock)
{
try
{
this._sock.EndConnect(ret);
this.ReadHead();
this.OnConnect();
}
catch (Exception exception)
{
}
}
}
protected abstract void OnPack(byte[] data);
//有服務端信息來,開始解析,現解析信息頭再解析消息體
private void OnRead(IAsyncResult ar)
{
try
{
if (this.IsConnected)
{
int num = this._sock.EndReceive(ar);
this._data_offset += num;
if (num <= 0)
{
}
else if (this._data_offset != this._data_size)
{
this.ContinueRead();
}
else if (this._is_read_head)
{
int num2 = BitConverter.ToInt32(this._data_buffer, 0);
this.ReadData(num2);
}
else
{
this.OnPack(this._data_buffer);
this.ReadHead();
}
}
}
catch (Exception exception)
{
}
}
//如果命令發送成功,檢查發送隊列是否還有需要發送的命令。如果有則繼續發送
{
PacketOut asyncState = ar.AsyncState as PacketOut;
Socket sock = asyncState.sock;
if (sock.Connected)
{
sock.EndSend(ar);
List<PacketOut> list = this._send_list;
lock (list)
{
if (this._send_list.Contains(asyncState))
{
this._send_list.Remove(asyncState);
}
}
this.ContinueSend();
}
}
//讀取消息體
{
this._is_read_head = false;
this._data_size = pack_len;
this._data_offset = 4;
this._data_buffer = new byte[this._data_size];
this.ContinueRead();
}
//讀取消息頭
{
this._is_read_head = true;
this._data_size = 4;
this._data_offset = 0;
this._data_buffer = new byte[this._data_size];
this.ContinueRead();
}
//具體的發送信息,先把數據發到發送隊列
{
if (this.IsConnected)
{
PacketOut item = new PacketOut {
start = false,
buff = buff,
sock = this._sock
};
int count = 0;
List<PacketOut> list = this._send_list;
lock (list)
{
this._send_list.Add(item);
count = this._send_list.Count;
}
if (count > 0x3e8)
{
{
this.ContinueSend();
}
}
}
{
get
{
return (this._sock == null);
}
}
{
get
{
return ((this._sock != null) && this._sock.Connected);
}
}
{
public byte[] buff;
public Socket sock;
public bool start;
}
}