先看看測試結果:
服務端:

服務器端控制臺:

可以發現我服務端連了2個客戶端,第一個為局域網的一臺機器,另一個為服務器的主機
ip為192.168.1.105 ,端口為42794的客戶端:

ip為192.168.1.104,端口為30547的客戶端:

需要發送聊天信息 : 使用“chat:”作為前綴。
值得注意的是 : 本文只探討異步Socket的封裝 , 包括包頭和包 。對與體驗效果不好,不是此次討論的范圍,Sorry。
一,核心 :
①:關于消息的構建類庫:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SocketTool
{
public sealed class SocketMsgTool
{
/// <summary>
/// 構造一個發送包
/// </summary>
/// <param name="mainCode">主碼</param>
/// <param name="subCode">分碼</param>
/// <param name="type">類型碼</param>
/// <param name="Body">包體</param>
/// <returns></returns>
public static byte[] Creat_Msg(ushort mainCode, ushort subCode, ushort type, byte[] Body)
{
List<byte> cur = new List<byte>(Body);
cur.InsertRange(0, BitConverter.GetBytes(mainCode));
cur.InsertRange(2, BitConverter.GetBytes(subCode));
cur.InsertRange(4, BitConverter.GetBytes(type));
ushort body_len = Convert.ToUInt16(Body.Length);
cur.InsertRange(6, BitConverter.GetBytes(body_len));
return cur.ToArray<byte>();
}
/// <summary>
/// 獲取主碼
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
public static ushort Get_MainCode(byte[] msg)
{
return BitConverter.ToUInt16(msg, 0);
}
/// <summary>
/// 獲取分碼
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
public static ushort Get_SubCode(byte[] msg)
{
return BitConverter.ToUInt16(msg, 2);
}
/// <summary>
/// 獲取類型碼
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
public static ushort Get_Type(byte[] msg)
{
return BitConverter.ToUInt16(msg, 4);
}
/// <summary>
/// 獲取包體
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
public static byte[] Get_Body(byte[] msg)
{
byte[] body = new byte[BitConverter.ToUInt16(msg, 6)];
Array.Copy(msg, 8, body, 0, body.Length);
return body;
}
}
}②關于字節數組方法的擴展:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Async_Svr_Socket_Lib.com
{
/// <summary>
/// 字節數組(byte[])的方法擴展
/// </summary>
internal static class ByteArr_Fun_Extends
{
/// <summary>
/// 追加數據到Buffer
/// </summary>
/// <param name="buffer"></param>
/// <param name="buffer_off_index">數據的偏移下標</param>
/// <param name="add">增加的byte[]</param>
/// <returns>需要增加的size量</returns>
public static int Push_Data(this byte[] buffer, ref int buffer_off_index, byte[] add)
{
int cur_con_count = buffer.Length - ( buffer_off_index + 1 );
if (add.Length > cur_con_count)
{
//需要擴大buffer的size
int off = add.Length - cur_con_count;
Array.Resize<byte>(ref buffer, buffer.Length + off);//擴充buffer的size
add.CopyTo(buffer, buffer_off_index + 1);
buffer_off_index += add.Length;//更新偏移
return off;
}
else
{
//不需要擴大buffer的size
add.CopyTo(buffer, buffer_off_index + 1);
buffer_off_index += add.Length;//更新偏移
return 0;
}
}
/// <summary>
/// 壓人新的數據(一般為包頭) - 構造新的發送包
/// </summary>
/// <param name="buffer_send">需要發送的包體</param>
/// <param name="unshift">壓入增加的byte[]</param>
/// <returns>需要增加的size量</returns>
public static void Unshift_Data(this byte[] buffer_send , byte[] unshift)
{
byte[] effective = buffer_send.Skip<byte>(0).Take<byte>(buffer_send.Length).ToArray<byte>();
List<byte> list = new List<byte>(effective);
list.InsertRange(0, unshift);//頭部插入
buffer_send = list.ToArray();//重新指定數據
}
/// <summary>
/// 獲取當前數據(取出一個完整的包)
/// </summary>
/// <param name="buffer"></param>
/// <param name="buffer_off_index">數據的偏移下標</param>
/// <param name="cur_len">整個包的長度</param>
/// <returns>當前的包</returns>
public static byte[] Shift_Data(this byte[] buffer, ref int buffer_off_index, int cur_len)
{
byte[] next_buffer = null;
if (cur_len < buffer_off_index + 1)
next_buffer = buffer.Skip<byte>(cur_len - 1).Take<byte>(buffer_off_index + 1 - cur_len).ToArray<byte>();//下一個包(存在粘包)
byte[] cur_buffer = buffer.Skip<byte>(0).Take<byte>(cur_len).ToArray<byte>();//當前的包(完整)
if (next_buffer == null)
buffer_off_index = -1;
else
{
Array.Resize<byte>(ref buffer, next_buffer.Length);
next_buffer.CopyTo(buffer, 0);//注入新的包
buffer_off_index = next_buffer.Length - 1;
}
return cur_buffer;
}
}
}③關于服務端Socket類庫:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Async_Svr_Socket_Lib.com;
using System.ComponentModel;
namespace Async_Svr_Socket_Lib
{
/// <summary>
/// 服務器Socket封裝
/// </summary>
public sealed class Svr_Socket
{
private Socket _listener = null;//服務器Socket
private readonly IPEndPoint _ip_point = null;
private Action<Socket_CallBack_Type, Object, Socket> _callback = null;//回調函數
private readonly int _connect_count = 0;
private readonly int _state_object_bufferlen = 0;
private ManualResetEvent allDone = null;//信號量
private Timer _heart_beat_timer = null;//心跳包及時機制
/// <summary>
/// 構造函數
/// </summary>
/// <param name="ip_point">服務端ip+port</param>
/// <param name="callback">回調函數</param>
/// <param name="connect_count">可連接的服務端個數</param>
/// <param name="state_object_bufferlen">client buffer長度</param>
public Svr_Socket(IPEndPoint ip_point, Action<Socket_CallBack_Type, Object, Socket> callback, int connect_count = 100, int state_object_bufferlen = 512)
{
this._ip_point = ip_point;
this._callback = callback;
this._connect_count = connect_count;
this._state_object_bufferlen = state_object_bufferlen;
}
/// <summary>
/// 請求連接Socket服務器
/// </summary>
public void Accept()
{
this._listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//構建Tcp通訊
allDone = new ManualResetEvent(false);
try
{
this._listener.Bind(this._ip_point);
this._listener.Listen(this._connect_count);
while (true)//持續的監聽連接
{
allDone.Reset();//置為無信號狀態
this._listener.BeginAccept(new AsyncCallback(this.Async_Accept_Callback), this._listener);
allDone.WaitOne();//當前線程等待
}
}
catch (Exception e)
{
Console.WriteLine("Socket Error! -> {0}" , e.Message);
}
}
//連接異步回調處理
private void Async_Accept_Callback(IAsyncResult ar)
{
allDone.Set();//置為有信號狀態
Socket listener = (Socket)ar.AsyncState;
try
{
Socket client = listener.EndAccept(ar);
State_Object state = new State_Object(this._state_object_bufferlen);
state.Client_Socket = client;
this._callback(Socket_CallBack_Type.connect_succ, true, client);//連接成功
this.receive(state);
}
catch (Exception e)
{
this._callback(Socket_CallBack_Type.connect_fail, e, null);
}
}
//接收字節
private void receive(State_Object state)
{
state.Client_Socket.BeginReceive(state.Buffer, state.Buffer_Off_Index + 1, state.Buffer.Length - (state.Buffer_Off_Index + 1), 0, new AsyncCallback(this.Async_Receive_Callback), state);
}
//接收異步回調處理
private void Async_Receive_Callback(IAsyncResult ar)
{
State_Object state = (State_Object)ar.AsyncState;
try
{
int byte_read_count = state.Client_Socket.EndReceive(ar);//接收的字節數
if (byte_read_count > 0)
{
state.Buffer_Off_Index += byte_read_count;
this.Receive_Handler(state);
}
else
{
//玩家主動關閉了連接
this._callback(Socket_CallBack_Type.client_active_off, null, state.Client_Socket);
}
}
catch( Exception e )
{
//玩家被迫斷開(客戶端沒發送斷開指令)
this._callback(Socket_CallBack_Type.client_passive_off, e, state.Client_Socket);
}
}
/// <summary>
/// 處理了粘包及斷包
/// </summary>
/// <param name="state"></param>
private void Receive_Handler(State_Object state )
{
byte[] client_buffer = state.Buffer;
if (state.Buffer_Off_Index + 1 >= 8)//如果包頭取到
{
ushort body_len = BitConverter.ToUInt16(state.Buffer, 6);
ushort packet_all_len = Convert.ToUInt16(body_len + 8);
if (packet_all_len <= state.Buffer_Off_Index + 1)
{
int buffer_off_index = state.Buffer_Off_Index;
byte[] cur_packet = state.Buffer.Shift_Data(ref buffer_off_index, packet_all_len);//取出當前的包(一整個包)
state.Buffer_Off_Index = buffer_off_index;//重新賦值
this._callback( Socket_CallBack_Type.receive, cur_packet, state.Client_Socket);//回調接收到的包
if (state.Buffer_Off_Index == -1)
{
Array.Resize<byte>(ref client_buffer, this._state_object_bufferlen);//再次初始化buffer
this.receive(state);
}
else
{
this.Receive_Handler(state);
}
}
else if (packet_all_len > state.Buffer.Length)//當包長大于buffer時
{
Array.Resize<byte>(ref client_buffer, state.Buffer.Length + this._state_object_bufferlen);
this.receive(state);
}
else
{
this.receive(state);
}
}
else
{
this.receive(state);
}
}
/// <summary>
/// 發送信息
/// </summary>
/// <param name="socket"></param>
/// <param name="msg">要發送的信息</param>
public void Send(Socket socket, byte[] msg)
{
if (socket != null && socket.Connected)
{
socket.BeginSend(msg, 0, msg.Length, 0, new AsyncCallback(this.Async_Send_Callback), socket);
}
}
//發送信息返回
private void Async_Send_Callback(IAsyncResult ar)
{
Socket socket = (Socket)ar.AsyncState;
int byte_send_count = socket.EndSend(ar);
this._callback(Socket_CallBack_Type.send, byte_send_count, socket);
}
}
/// <summary>
/// Socket回調類型
/// </summary>
public enum Socket_CallBack_Type : uint
{
[Description("連接成功")]
connect_succ = 0,
[Description("連接失敗")]
connect_fail = 1,
[Description("接收返回")]
receive = 2,
[Description("發送返回")]
send = 3,
[Description("客戶端被迫斷開")]
client_passive_off = 4,
[Description("客戶端主動斷開")]
client_active_off = 5
}
}④關于客戶端Socket類庫:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using Async_Cli_Socket_Lib.com;
using System.ComponentModel;
namespace Async_Cli_Socket_Lib
{
/// <summary>
/// 客戶端socket
/// </summary>
public sealed class Cli_Socket
{
private Socket _client = null;
private IPEndPoint _ip_point = null;
private Action<Socket_CallBack_Type , Object> _callback = null;
private readonly int _state_object_bufferlen = 0;
private State_Object _state = null;
/// <summary>
///
/// </summary>
/// <param name="ip_point">服務端ip+port</param>
/// <param name="callback">回調函數</param>
/// <param name="state_object_bufferlen">buffer默認size</param>
public Cli_Socket(IPEndPoint ip_point, Action<Socket_CallBack_Type, Object> callback, int state_object_bufferlen = 512)
{
this._ip_point = ip_point;
this._callback = callback;
this._state_object_bufferlen = state_object_bufferlen;
this._state = new State_Object(state_object_bufferlen);
}
/// <summary>
/// 獲取Socket
/// </summary>
public Socket Client
{
get { return this._client; }
}
public void Connect()
{
if (_client == null)
_client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_client.BeginConnect(this._ip_point, new AsyncCallback(this.Async_Connect_Callback), _client);
}
private void Async_Connect_Callback(IAsyncResult ar)
{
Socket client = (Socket)ar.AsyncState;
try
{
client.EndConnect(ar);
this._callback(Socket_CallBack_Type.connect_succ, true);
this.receive();//開始接收數據
}
catch (Exception e)
{
this._callback(Socket_CallBack_Type.connect_fail, e);
}
}
//開始接收數據
private void receive()
{
this._client.BeginReceive(this._state.Buffer, this._state.Buffer_Off_Index + 1, this._state.Buffer.Length - (this._state.Buffer_Off_Index + 1), 0, new AsyncCallback(this.Async_Receive_Callback), this._state);
}
//接收數據返回
private void Async_Receive_Callback(IAsyncResult ar)
{
State_Object state = (State_Object)ar.AsyncState;
try
{
int byte_read_count = this._client.EndReceive(ar);//接收的字節數
if (byte_read_count > 0)
{
state.Buffer_Off_Index += byte_read_count;//增加的數據量
this.Receive_Handler(state);
}
else
{
this._callback(Socket_CallBack_Type.server_active_off, this._client);
}
}
catch (Exception e)
{
this._callback(Socket_CallBack_Type.server_passive_off, e);
}
}
private void Receive_Handler(State_Object state)
{
byte[] client_buffer = state.Buffer;
if (state.Buffer_Off_Index + 1 >= 8)//包頭的信心已經收到
{
ushort body_len = BitConverter.ToUInt16(state.Buffer, 6);
ushort packet_all_len = Convert.ToUInt16(body_len + 8);
if (packet_all_len <= state.Buffer_Off_Index + 1)
{
int buffer_off_index = state.Buffer_Off_Index;
byte[] cur_packet = state.Buffer.Shift_Data(ref buffer_off_index, packet_all_len);//取出當前的包(一整個包)
state.Buffer_Off_Index = buffer_off_index;//重新賦值
this._callback(Socket_CallBack_Type.receive ,cur_packet);//回調接收到的包------------------
if (state.Buffer_Off_Index == -1)
{
Array.Resize<byte>(ref client_buffer, this._state_object_bufferlen);//再次初始化buffer
this.receive();
}
else
{
this.Receive_Handler(state);
}
}
else if (packet_all_len > state.Buffer.Length)
{
Array.Resize<byte>(ref client_buffer, state.Buffer.Length + this._state_object_bufferlen);
this.receive();
}
else
{
this.receive();
}
}
else
{
this.receive();
}
}
/// <summary>
/// 發送Socket請求
/// </summary>
/// <param name="msg">請求信息</param>
public void Send(byte[] msg)
{
_client.BeginSend(msg, 0, msg.Length, 0, new AsyncCallback(this.Async_Send_Callback), this._state);
}
private void Async_Send_Callback(IAsyncResult ar)
{
State_Object state = (State_Object)ar.AsyncState;
int byte_send_count = this._client.EndSend(ar);//發送了多少字節
this._callback(Socket_CallBack_Type.send, byte_send_count);
}
}
/// <summary>
/// Socket回調類型
/// </summary>
public enum Socket_CallBack_Type : uint
{
[Description("連接成功")]
connect_succ = 0,
[Description("連接失敗")]
connect_fail = 1,
[Description("接收返回")]
receive = 2,
[Description("發送返回")]
send = 3,
[Description("服務端被迫斷開")]
server_passive_off = 4,
[Description("服務端主動斷開")]
server_active_off = 5
}
}⑤:服務端 state_object
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
namespace Async_Svr_Socket_Lib.com
{
/// <summary>
/// Socket數據
/// </summary>
internal sealed class State_Object
{
/// <summary>
/// Client Socket
/// </summary>
public Socket Client_Socket { set; get; }
private byte[] _buffer = null;
private int _buffer_off_index = -1;
/// <summary>
/// 構造函數
/// </summary>
/// <param name="buffer_size">緩存初始的字節數</param>
public State_Object(int buffer_size = 512)
{
this._buffer = new byte[buffer_size];
this.Buffer_Off_Index = -1;
}
/// <summary>
/// 字節數組
/// </summary>
public byte[] Buffer
{
get { return this._buffer; }
}
/// <summary>
/// 緩存已經存儲的下標( 顯然從0開始 , -1表示沒有數據 )
/// </summary>
public int Buffer_Off_Index
{
set { this._buffer_off_index = value; }
get { return this._buffer_off_index; }
}
}
}⑥:客戶端state_object
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Async_Cli_Socket_Lib.com
{
/// <summary>
/// Socket數據
/// </summary>
internal sealed class State_Object
{
private byte[] _buffer = null;
private int _buffer_off_index = -1;
/// <summary>
/// 構造函數
/// </summary>
/// <param name="buffer_size">緩存初始的字節數</param>
public State_Object(int buffer_size = 512)
{
this._buffer = new byte[buffer_size];
this.Buffer_Off_Index = -1;
}
/// <summary>
/// 字節數組
/// </summary>
public byte[] Buffer
{
get { return this._buffer; }
}
/// <summary>
/// 緩存已經存儲的下標( 顯然從0開始 , -1表示沒有數據 )
/// </summary>
public int Buffer_Off_Index
{
set { this._buffer_off_index = value; }
get { return this._buffer_off_index; }
}
}
}二,測試(使用控制臺)
①:服務端
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Async_Svr_Socket_Lib;
using System.Net;
using System.Net.Sockets;
using SocketTool;
using System.Diagnostics;
using System.Threading;
namespace Server_Socket_Test
{
class Program
{
private Dictionary<string,Socket> _client_list = null;//因為測試的環境原因 , 使用 key :姓名 , 在真實的開發中應該使用用戶的ID號
private Svr_Socket _socket = null;//本人封裝的服務端Socket
static void Main(string[] args)
{
Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = ConsoleColor.Green;
Thread.CurrentThread.IsBackground = true;//退出后自動殺死進程
IPEndPoint ipe = new IPEndPoint(IPAddress.Parse("192.168.1.104"), 6065);
Program pro = new Program();
pro._socket = new Svr_Socket(ipe, pro.CallBack);
Console.WriteLine("等待請求連接.......");
pro._socket.Accept();
Console.Read();
}
private void CallBack(Socket_CallBack_Type type , object msg, Socket client)
{
string key = String.Empty;
switch (type)
{
case Socket_CallBack_Type.connect_succ:
this.connect(msg , client);
break;
case Socket_CallBack_Type.connect_fail:
Console.WriteLine("連接失敗 : {0}", ((Exception)msg).Message);
break;
case Socket_CallBack_Type.receive:
this.receive(msg, client);
break;
case Socket_CallBack_Type.send:
//Console.WriteLine("發送的字節數 : {0}", Convert.ToInt32(msg));
break;
case Socket_CallBack_Type.client_active_off://主動下線
#if DEBUG
Console.WriteLine("{0} 下線了 !!", client.RemoteEndPoint);
#endif
this.RemoveClient(client);
break;
case Socket_CallBack_Type.client_passive_off://被迫下線
#if DEBUG
Console.WriteLine("{0} 下線了 !!", client.RemoteEndPoint);
#endif
this.RemoveClient(client);
break;
}
}
/// <summary>
/// 玩家下線
/// </summary>
/// <param name="client"></param>
private void RemoveClient(Socket client)
{
if (this._client_list == null) return;
string remove_name = string.Empty;
foreach (KeyValuePair<string, Socket> kv in this._client_list)
{
if (kv.Value == client)
{
remove_name = kv.Key;
break;
}
}
this._client_list.Remove(remove_name);
if (client != null && client.Connected)
{
client.Shutdown(SocketShutdown.Both);
client.Close();
}
if (this._client_list.Count > 0)
{
string remove_msg = "{0},下線了?。?!";
byte[] msg = Encoding.UTF8.GetBytes(string.Format(remove_msg, remove_name));
msg = SocketMsgTool.Creat_Msg(1, 1, 3, msg);
foreach (KeyValuePair<string, Socket> kv in this._client_list)
{
kv.Value.Send(msg);
}
}
}
/// <summary>
/// 玩家上線
/// </summary>
/// <param name="body"></param>
/// <param name="client"></param>
private void AddClient( byte[] body , Socket client)
{
string str = Encoding.UTF8.GetString(body);
string name = str.Split(new char[] { ',' })[0];
Console.WriteLine("{0} > {1}", client.RemoteEndPoint, str);
//開始啟動服務端的心跳包
if (this._client_list == null)
this._client_list = new Dictionary<string, Socket>();
if (!this._client_list.ContainsKey(name))
this._client_list.Add(name, client);
string add_msg = "{0},上線了!!!";
byte[] msg = Encoding.UTF8.GetBytes(string.Format(add_msg, name));
msg = SocketMsgTool.Creat_Msg(1, 1, 4, msg);
foreach (KeyValuePair<string, Socket> kv in this._client_list)
{
kv.Value.Send(msg);
}
}
private void connect(object msg , Socket client)
{
Console.WriteLine("連接成功 client ip : {0}" , client.RemoteEndPoint);
byte[] welcome = Encoding.UTF8.GetBytes(String.Format("歡迎 : {0} , 尊姓大名?", client.RemoteEndPoint));
welcome = SocketMsgTool.Creat_Msg(1, 1, 1, welcome);
client.Send(welcome);
}
private void receive(object msg, Socket client)
{
byte[] data = (byte[])msg;
ushort mainCode = SocketMsgTool.Get_MainCode(data);
ushort subCode = SocketMsgTool.Get_SubCode(data);
ushort type = SocketMsgTool.Get_Type(data);
byte[] body = SocketMsgTool.Get_Body(data);
switch (mainCode)
{
case 1:
switch (subCode)
{
case 0://
break;
case 1:
switch (type)
{
case 2:
this.AddClient(body, client);
break;
}
break;
}
break;
case 2:
switch (subCode)
{
case 1:
switch (type)
{
case 1://聊天信息
this.Chat(body, client);
break;
}
break;
}
break;
}
}
/// <summary>
/// 聊天處理
/// </summary>
/// <param name="body"></param>
/// <param name="client"></param>
private void Chat(byte[] body, Socket client)
{
string msg = Encoding.UTF8.GetString(body);
byte[] all_mag = SocketMsgTool.Creat_Msg(2, 1, 1, body);
foreach (KeyValuePair<string, Socket> kv in this._client_list)
{
if (kv.Value != client)
{
kv.Value.Send(all_mag);//發送聊天信息
}
}
Console.WriteLine(msg);
}
}
}②,客戶端
using System;
using System.Text;
using System.Net;
using Async_Cli_Socket_Lib;
using SocketTool;
using System.Net.Sockets;
using System.Threading;
namespace Client_Socket_Test
{
class Program
{
private Cli_Socket _socket = null;
private readonly string _name = string.Empty;
public Program(string name)
{
this._name = name;
}
static void Main(string[] args)
{
Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = ConsoleColor.Green;
Thread.CurrentThread.IsBackground = true;//退出后自動殺死進程
Console.Write("請輸入用戶名:");
string name = Console.ReadLine();
IPEndPoint ipe = new IPEndPoint(IPAddress.Parse("192.168.1.104"), 6065);
Program pro = new Program(name);
pro._socket = new Cli_Socket(ipe, pro.CallBack);
Console.WriteLine("請求連接Socket服務器");
pro._socket.Connect();
string code = Console.ReadLine();
while(true)
{
if (code.Trim().ToLower() == "off")
{
pro._socket.Client.Shutdown(SocketShutdown.Both);
pro._socket.Client.Close();
break;
}
else
{
//聊天信息
if (code.Trim() != string.Empty && code.Trim().Substring(0,5) == "chat:")
{
pro.Chat(code.Trim().Substring(5));//發送聊天信息
}
code = Console.ReadLine();
}
}
}
/// <summary>
/// 發送聊天信息
/// </summary>
/// <param name="msg"></param>
private void Chat(string chats)
{
string msg = string.Format("{0} 說 : {1}", _name, chats);
byte[] by = SocketMsgTool.Creat_Msg(2,1,1,Encoding.UTF8.GetBytes(msg));
this._socket.Send(by);
}
private void CallBack( Socket_CallBack_Type type , Object msg )
{
switch (type)
{
case Socket_CallBack_Type.connect_succ:
this.connect(msg);
break;
case Socket_CallBack_Type.connect_fail:
Console.WriteLine("連接失敗 : {0}", ((Exception)msg).Message);
break;
case Socket_CallBack_Type.receive:
this.receive(msg);
break;
case Socket_CallBack_Type.send:
Console.WriteLine("發送的字節數 : {0}", Convert.ToInt32(msg));
break;
case Socket_CallBack_Type.server_active_off:
#if DEBUG
Console.WriteLine("主動 : 服務器斷開連接 : {0}", (msg as Exception).Message);
#endif
if (_socket.Client != null && _socket.Client.Connected)
{
_socket.Client.Shutdown(SocketShutdown.Both);
_socket.Client.Close();
}
break;
case Socket_CallBack_Type.server_passive_off:
#if DEBUG
Console.WriteLine("被迫 : 服務器斷開連接 : {0}", (msg as Exception).Message);
#endif
if (_socket.Client != null && _socket.Client.Connected)
{
_socket.Client.Shutdown(SocketShutdown.Both);
_socket.Client.Close();
}
break;
}
}
private void connect(object msg)
{
Console.WriteLine("已經成功連接到了Socket服務器了");
}
private void receive(object msg)
{
byte[] data = (byte[])msg;
ushort mainCode = SocketMsgTool.Get_MainCode(data);
ushort subCode = SocketMsgTool.Get_SubCode(data);
ushort type = SocketMsgTool.Get_Type(data);
byte[] body = SocketMsgTool.Get_Body(data);
switch (mainCode)
{
case 1:
switch (subCode)
{
case 1:
switch (type)
{
case 0:
break;
case 1:
//Console.WriteLine(Encoding.UTF8.GetString(body));
byte[] hello = Encoding.UTF8.GetBytes(string.Format("{0},請多指教" , this._name));
Console.WriteLine("{0},請多指教", this._name);
hello = SocketMsgTool.Creat_Msg(1, 1, 2, hello);
this._socket.Send(hello);
break;
case 3://有玩家下線
string remove_news = string.Format("【{0}】:{1}", "Server", Encoding.UTF8.GetString(body));
Console.WriteLine(remove_news);
break;
case 4://有玩家上線
string add_msg = Encoding.UTF8.GetString(body);
string add_name = add_msg.Split(new char[] { ',' })[0];
if (add_name != _name)
{
add_msg = string.Format("【{0}】:{1}", "Server", add_msg);
Console.WriteLine(add_msg);
}
break;
}
break;
}
break;
case 2:
switch (subCode)
{
case 1:
switch (type)
{
case 1://聊天信息
//Console.Clear();
string chat = Encoding.UTF8.GetString(body);
Console.WriteLine(chat);
break;
}
break;
}
break;
}
}
}
}值得注意的是 : 此封裝不僅可以用于聊天,body也可以進行加密,用于游戲Socket通訊。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。