溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

C# 異步Socket

發(fā)布時(shí)間:2020-07-03 06:30:25 來(lái)源:網(wǎng)絡(luò) 閱讀:1916 作者:Aonaufly 欄目:編程語(yǔ)言

先看看測(cè)試結(jié)果:

服務(wù)端:

C# 異步Socket

服務(wù)器端控制臺(tái):

C# 異步Socket

可以發(fā)現(xiàn)我服務(wù)端連了2個(gè)客戶端,第一個(gè)為局域網(wǎng)的一臺(tái)機(jī)器,另一個(gè)為服務(wù)器的主機(jī)


ip為192.168.1.105 ,端口為42794的客戶端:

C# 異步Socket

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

C# 異步Socket


需要發(fā)送聊天信息 : 使用“chat:”作為前綴。


值得注意的是 : 本文只探討異步Socket的封裝 , 包括包頭和包 。對(duì)與體驗(yàn)效果不好,不是此次討論的范圍,Sorry。


一,核心 :

①:關(guān)于消息的構(gòu)建類庫(kù):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SocketTool
{
    public sealed class SocketMsgTool
    {
        /// <summary>
        /// 構(gòu)造一個(gè)發(fā)送包
        /// </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;
        }
    }
}

②關(guān)于字節(jié)數(shù)組方法的擴(kuò)展:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Async_Svr_Socket_Lib.com
{
    /// <summary>
    /// 字節(jié)數(shù)組(byte[])的方法擴(kuò)展
    /// </summary>
    internal static class ByteArr_Fun_Extends
    {
        /// <summary>
        /// 追加數(shù)據(jù)到Buffer
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="buffer_off_index">數(shù)據(jù)的偏移下標(biāo)</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)
            {
                //需要擴(kuò)大buffer的size
                int off = add.Length - cur_con_count;
                Array.Resize<byte>(ref buffer, buffer.Length + off);//擴(kuò)充buffer的size
                add.CopyTo(buffer, buffer_off_index + 1);
                buffer_off_index += add.Length;//更新偏移
                return off;
            }
            else
            { 
                //不需要擴(kuò)大buffer的size
                add.CopyTo(buffer, buffer_off_index + 1);
                buffer_off_index += add.Length;//更新偏移
                return 0;
            }
        }
        /// <summary>
        /// 壓人新的數(shù)據(jù)(一般為包頭) - 構(gòu)造新的發(fā)送包
        /// </summary>
        /// <param name="buffer_send">需要發(fā)送的包體</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();//重新指定數(shù)據(jù)
        }
        /// <summary>
        /// 獲取當(dāng)前數(shù)據(jù)(取出一個(gè)完整的包)
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="buffer_off_index">數(shù)據(jù)的偏移下標(biāo)</param>
        /// <param name="cur_len">整個(gè)包的長(zhǎng)度</param>
        /// <returns>當(dāng)前的包</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>();//下一個(gè)包(存在粘包)
            byte[] cur_buffer = buffer.Skip<byte>(0).Take<byte>(cur_len).ToArray<byte>();//當(dāng)前的包(完整)
            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;
        }
    }
}

③關(guān)于服務(wù)端Socket類庫(kù):

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>
    /// 服務(wù)器Socket封裝
    /// </summary>
    public sealed class Svr_Socket
    {
        private Socket _listener = null;//服務(wù)器Socket
        private readonly IPEndPoint _ip_point = null;
        private Action<Socket_CallBack_Type, Object, Socket> _callback = null;//回調(diào)函數(shù)
        private readonly int _connect_count = 0;
        private readonly int _state_object_bufferlen = 0;
        private ManualResetEvent allDone = null;//信號(hào)量
        private Timer _heart_beat_timer = null;//心跳包及時(shí)機(jī)制
        /// <summary>
        /// 構(gòu)造函數(shù)
        /// </summary>
        /// <param name="ip_point">服務(wù)端ip+port</param>
        /// <param name="callback">回調(diào)函數(shù)</param>
        /// <param name="connect_count">可連接的服務(wù)端個(gè)數(shù)</param>
        /// <param name="state_object_bufferlen">client buffer長(zhǎng)度</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>
        /// 請(qǐng)求連接Socket服務(wù)器
        /// </summary>
        public void Accept()
        {
            this._listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//構(gòu)建Tcp通訊
            allDone = new ManualResetEvent(false);
            try
            {
                this._listener.Bind(this._ip_point);
                this._listener.Listen(this._connect_count);
                while (true)//持續(xù)的監(jiān)聽(tīng)連接
                {
                    allDone.Reset();//置為無(wú)信號(hào)狀態(tài)
                    this._listener.BeginAccept(new AsyncCallback(this.Async_Accept_Callback), this._listener);
                    allDone.WaitOne();//當(dāng)前線程等待
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Socket Error! -> {0}" , e.Message);
            }
        }
        //連接異步回調(diào)處理
        private void Async_Accept_Callback(IAsyncResult ar)
        {
            allDone.Set();//置為有信號(hào)狀態(tài)
            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);
            }
        }
        //接收字節(jié)
        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);
        }
        //接收異步回調(diào)處理
        private void Async_Receive_Callback(IAsyncResult ar)
        {
            State_Object state = (State_Object)ar.AsyncState;
            try
            { 
                int byte_read_count = state.Client_Socket.EndReceive(ar);//接收的字節(jié)數(shù)
                if (byte_read_count > 0)
                {
                    state.Buffer_Off_Index += byte_read_count;
                    this.Receive_Handler(state);
                }
                else
                { 
                    //玩家主動(dòng)關(guān)閉了連接
                    this._callback(Socket_CallBack_Type.client_active_off, null, state.Client_Socket);
                }
            }
            catch( Exception e )
            {
                //玩家被迫斷開(kāi)(客戶端沒(méi)發(fā)送斷開(kāi)指令)
                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);//取出當(dāng)前的包(一整個(gè)包)
                    state.Buffer_Off_Index = buffer_off_index;//重新賦值
                    this._callback( Socket_CallBack_Type.receive, cur_packet, state.Client_Socket);//回調(diào)接收到的包
                    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)//當(dāng)包長(zhǎng)大于buffer時(shí)
                {
                    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>
        /// 發(fā)送信息
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="msg">要發(fā)送的信息</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);
            }
        }
        //發(fā)送信息返回
        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回調(diào)類型
    /// </summary>
    public enum Socket_CallBack_Type : uint
    {
        [Description("連接成功")]
        connect_succ = 0,
        [Description("連接失敗")]
        connect_fail = 1,
        [Description("接收返回")]
        receive = 2,
        [Description("發(fā)送返回")]
        send = 3,
        [Description("客戶端被迫斷開(kāi)")]
        client_passive_off = 4,
        [Description("客戶端主動(dòng)斷開(kāi)")]
        client_active_off = 5
    }
}


④關(guān)于客戶端Socket類庫(kù):

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">服務(wù)端ip+port</param>
        /// <param name="callback">回調(diào)函數(shù)</param>
        /// <param name="state_object_bufferlen">buffer默認(rèn)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();//開(kāi)始接收數(shù)據(jù)
            }
            catch (Exception e)
            {
                this._callback(Socket_CallBack_Type.connect_fail, e);
            }
        }
        //開(kāi)始接收數(shù)據(jù)
        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);
        }
        //接收數(shù)據(jù)返回
        private void Async_Receive_Callback(IAsyncResult ar)
        {
            State_Object state = (State_Object)ar.AsyncState;
            try
            {
                int byte_read_count = this._client.EndReceive(ar);//接收的字節(jié)數(shù)
                if (byte_read_count > 0)
                {
                    state.Buffer_Off_Index += byte_read_count;//增加的數(shù)據(jù)量
                    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)//包頭的信心已經(jīng)收到
            {
                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);//取出當(dāng)前的包(一整個(gè)包)
                    state.Buffer_Off_Index = buffer_off_index;//重新賦值
                    this._callback(Socket_CallBack_Type.receive ,cur_packet);//回調(diào)接收到的包------------------
                    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>
        /// 發(fā)送Socket請(qǐng)求
        /// </summary>
        /// <param name="msg">請(qǐng)求信息</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);//發(fā)送了多少字節(jié)
            this._callback(Socket_CallBack_Type.send, byte_send_count);
        }
    }
    /// <summary>
    /// Socket回調(diào)類型
    /// </summary>
    public enum Socket_CallBack_Type : uint
    {
        [Description("連接成功")]
        connect_succ = 0,
        [Description("連接失敗")]
        connect_fail = 1,
        [Description("接收返回")]
        receive = 2,
        [Description("發(fā)送返回")]
        send = 3,
        [Description("服務(wù)端被迫斷開(kāi)")]
        server_passive_off = 4,
        [Description("服務(wù)端主動(dòng)斷開(kāi)")]
        server_active_off = 5
    }
}

⑤:服務(wù)端 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數(shù)據(jù)
    /// </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>
        /// 構(gòu)造函數(shù)
        /// </summary>
        /// <param name="buffer_size">緩存初始的字節(jié)數(shù)</param>
        public State_Object(int buffer_size = 512)
        {
            this._buffer = new byte[buffer_size];
            this.Buffer_Off_Index = -1;
        }
        /// <summary>
        /// 字節(jié)數(shù)組
        /// </summary>
        public byte[] Buffer
        {
            get { return this._buffer; }
        }
        /// <summary>
        /// 緩存已經(jīng)存儲(chǔ)的下標(biāo)( 顯然從0開(kāi)始 , -1表示沒(méi)有數(shù)據(jù) )
        /// </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數(shù)據(jù)
    /// </summary>
    internal sealed class State_Object
    {
        private byte[] _buffer = null;
        private int _buffer_off_index = -1;
        /// <summary>
        /// 構(gòu)造函數(shù)
        /// </summary>
        /// <param name="buffer_size">緩存初始的字節(jié)數(shù)</param>
        public State_Object(int buffer_size = 512)
        {
            this._buffer = new byte[buffer_size];
            this.Buffer_Off_Index = -1;
        }
        /// <summary>
        /// 字節(jié)數(shù)組
        /// </summary>
        public byte[] Buffer
        {
            get { return this._buffer; }
        }
        /// <summary>
        /// 緩存已經(jīng)存儲(chǔ)的下標(biāo)( 顯然從0開(kāi)始 , -1表示沒(méi)有數(shù)據(jù) )
        /// </summary>
        public int Buffer_Off_Index
        {
            set { this._buffer_off_index = value; }
            get { return this._buffer_off_index; }
        }
    }
}


二,測(cè)試(使用控制臺(tái))

①:服務(wù)端

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;//因?yàn)闇y(cè)試的環(huán)境原因 , 使用 key :姓名 , 在真實(shí)的開(kāi)發(fā)中應(yīng)該使用用戶的ID號(hào)
        private Svr_Socket _socket = null;//本人封裝的服務(wù)端Socket
        static void Main(string[] args)
        {
            Console.BackgroundColor = ConsoleColor.Black;
            Console.ForegroundColor = ConsoleColor.Green;
            Thread.CurrentThread.IsBackground = true;//退出后自動(dòng)殺死進(jìn)程
            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("等待請(qǐng)求連接.......");
            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("發(fā)送的字節(jié)數(shù) : {0}", Convert.ToInt32(msg));
                    break;
                case Socket_CallBack_Type.client_active_off://主動(dòng)下線
#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);
            //開(kāi)始啟動(dòng)服務(wù)端的心跳包
            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);//發(fā)送聊天信息
                }
            }
            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;//退出后自動(dòng)殺死進(jìn)程
            Console.Write("請(qǐng)輸入用戶名:");
            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("請(qǐng)求連接Socket服務(wù)器");
            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));//發(fā)送聊天信息
                    }
                    code = Console.ReadLine();
                }
            }
        }
        /// <summary>
        /// 發(fā)送聊天信息
        /// </summary>
        /// <param name="msg"></param>
        private void Chat(string chats)
        {
            string msg = string.Format("{0} 說(shuō) : {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("發(fā)送的字節(jié)數(shù) : {0}", Convert.ToInt32(msg));
                    break;
                case Socket_CallBack_Type.server_active_off:
#if DEBUG
                    Console.WriteLine("主動(dòng) : 服務(wù)器斷開(kāi)連接 : {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("被迫 : 服務(wù)器斷開(kāi)連接 : {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("已經(jīng)成功連接到了Socket服務(wù)器了");
        }
        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},請(qǐng)多指教" , this._name));
                                    Console.WriteLine("{0},請(qǐng)多指教", 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也可以進(jìn)行加密,用于游戲Socket通訊。

附件:http://down.51cto.com/data/2366908
向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI