温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

C# 异步Socket

发布时间:2020-07-03 06:30:25 来源:网络 阅读:1916 作者:Aonaufly 栏目:编程语言

先看看测试结果:

服务端:

C# 异步Socket

服务器端控制台:

C# 异步Socket

可以发现我服务端连了2个客户端,第一个为局域网的一台机器,另一个为服务器的主机


ip为192.168.1.105 ,端口为42794的客户端:

C# 异步Socket

ip为192.168.1.104,端口为30547的客户端:

C# 异步Socket


需要发送聊天信息 : 使用“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通讯。

附件:http://down.51cto.com/data/2366908
向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI