TCP Socket服務端客戶端(二)

本文服務端客戶端封裝代碼轉自https://blog.csdn.net/zhujunxxxxx/article/details/44258719,並做了簡單的修改。node

 

1)服務端服務器

此類主要處理服務端相關消息網絡

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace TcpSocketServer
{
    /// <summary>
    /// Socket異步TCP服務器
    /// 建議把close方法改成私有,即服務端不主動關閉鏈接
    /// 客戶端主動關閉鏈接後,其receive仍在
    /// </summary>
    public class TCPServerAsync : IDisposable
    {
        #region Fields 
        private int _maxClient;// 服務器程序容許的最大客戶端鏈接數
        private int _clientCount;// 當前的鏈接的客戶端數 
 
        private Socket _serverSock;// 服務器使用的異步socket
  
        private List<ClientInfo> _clients;// 客戶端會話列表
        private bool disposed = false;//內存釋放
        #endregion
        #region Properties 
        public bool IsRunning { get; private set; }// 服務器是否正在運行 
        public IPAddress Address { get; private set; }// 監聽的IP地址 
        public int Port { get; private set; }// 監聽的端口 
 
        public Encoding Encoding { get; set; }// 通訊使用的編碼
        #endregion
 
        #region 構造函數 
        /// <summary> 
        /// 異步Socket TCP服務器 
        /// </summary> 
        public TCPServerAsync(int listenPort)
            : this(IPAddress.Any, listenPort, 1024)
        {
        }
        public TCPServerAsync(IPEndPoint localEP)
            : this(localEP.Address, localEP.Port, 1024)
        {
        }
        public TCPServerAsync(IPAddress localIPAddress, int listenPort, int maxClient)
        {
            this.Address = localIPAddress;
            this.Port = listenPort;
            this.Encoding = Encoding.Default;
            _maxClient = maxClient;
            _clients = new List<ClientInfo>();
            _serverSock = new Socket(localIPAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
        }
        #endregion
        #region Method 
        /// <summary> 
        /// 啓動服務器 
        /// </summary> 
        public void Start()
        {
            if (!IsRunning)
            {
                IsRunning = true;
                _serverSock.Bind(new IPEndPoint(this.Address, this.Port));
                _serverSock.Listen(1024);
                _serverSock.BeginAccept(new AsyncCallback(HandleAcceptConnected), _serverSock);
            }
        }
        /// <summary> 
        /// 啓動服務器 
        /// </summary> 
        /// <param name="backlog"> 
        /// 服務器所容許的掛起鏈接序列的最大長度 
        /// </param> 
        public void Start(int backlog)
        {
            if (!IsRunning)
            {
                IsRunning = true;
                _serverSock.Bind(new IPEndPoint(this.Address, this.Port));
                _serverSock.Listen(backlog);
                _serverSock.BeginAccept(new AsyncCallback(HandleAcceptConnected), _serverSock);
            }
        }
        /// <summary> 
        /// 中止服務器 
        /// </summary> 
        public void Stop()
        {
            if (IsRunning)
            {
                IsRunning = false;
                _serverSock.Close();
                //TODO 關閉對全部客戶端的鏈接 
                CloseAllClient();
            }
        }
        #region Close 
        /// <summary> 
        /// 關閉一個與客戶端之間的會話 
        /// </summary> 
        /// <param name="state">須要關閉的客戶端會話對象</param> 
        public void Close(ClientInfo state)
        {
            if (state != null)
            {
                //state.Datagram = null;
                state.RecvDataBuffer = null;
                _clients.Remove(state);
                _clientCount--;
                //TODO 觸發關閉事件 
                state.Close();
            }
        }
        /// <summary> 
        /// 關閉全部的客戶端會話,與全部的客戶端鏈接會斷開 
        /// </summary> 
        public void CloseAllClient()
        {
            foreach (ClientInfo client in _clients)
            {
                Close(client);
            }
            _clientCount = 0;
            _clients.Clear();
        }
        #endregion
        /// <summary> 
        /// 處理客戶端鏈接 
        /// </summary> 
        /// <param name="ar"></param> 
        private void HandleAcceptConnected(IAsyncResult ar)
        {
            if (IsRunning)
            {
                Socket server = (Socket)ar.AsyncState;
                Socket client = server.EndAccept(ar);
                //檢查是否達到最大的容許的客戶端數目 
                if (_clientCount >= _maxClient)
                {
                    //C-TODO 觸發事件 
                    RaiseOtherException(null);
                }
                else
                {
                    ClientInfo state = new ClientInfo(client);
                    lock (_clients)
                    {
                        _clients.Add(state);
                        _clientCount++;
                        RaiseClientConnected(state); //觸發客戶端鏈接事件 
                    }
                    state.RecvDataBuffer = new byte[client.ReceiveBufferSize];
                    //開始接受來自該客戶端的數據 
                    client.BeginReceive(state.RecvDataBuffer, 0, state.RecvDataBuffer.Length, SocketFlags.None,
                     new AsyncCallback(HandleDataReceived), state);
                }
                //接受下一個請求 
                server.BeginAccept(new AsyncCallback(HandleAcceptConnected), ar.AsyncState);
            }
        }
        /// <summary> 
        /// 處理客戶端數據 
        /// </summary> 
        /// <param name="ar"></param> 
        private void HandleDataReceived(IAsyncResult ar)
        {
            if (IsRunning)
            {
                ClientInfo state = (ClientInfo)ar.AsyncState;
                Socket client = state.ClientSocket;
                try
                {
                    //異步接收,當客戶端退出的時候會再次執行EndReceive                     
                    int recv = client.EndReceive(ar);
     //客戶端主動斷開鏈接時(採用close關閉)recv == 0
     //因此執行回掉RaiseClientDisconnected,並在回掉函數中關閉鏈接
     //以不在RaiseClientDisconnected回掉中關閉鏈接爲優,即直接調用Close關閉
     if (recv == 0)
                    {
                        //C- TODO 觸發事件 (關閉客戶端) 
                        //Close(state);
                        RaiseClientDisconnected(state);
                        return;
                    }
                    //TODO 處理已經讀取的數據 ps:數據在state的RecvDataBuffer中 
                    state._recvdBufferLength = recv;
                    //C- TODO 觸發數據接收事件 
                    RaiseDataReceived(state);
                }
                catch (SocketException)
                {
                    //C- TODO 異常處理 
                    RaiseNetError(state);
     //客戶端主動斷開鏈接時(直接關閉程序,而非採用close關閉)引起以嘗
     //因此執行回掉RaiseClientDisconnected,並在回掉函數中關閉鏈接
     //以不在回掉中關閉鏈接爲優,直接/Close(state)關閉
     state._recvdBufferLength = 0;
                    RaiseClientDisconnected(state);
                    return;
                }
                //繼續接收來自來客戶端的數據
                //ps: 若是未接收到數據則始終處於掛起狀態;
                //pss:當收到close消息,server主動關閉鏈接(212行RaiseDataReceived中進行了關閉)時因爲已經關閉鏈接,因此下述代碼會有異常
                //後續可在應用只要不是經過客戶端發消息主動close就可避免此問題,因此在此加一個異常處理,或者加一個bool變量判斷是否斷掉
                try
                {
                    client.BeginReceive(state.RecvDataBuffer, 0, state.RecvDataBuffer.Length, SocketFlags.None,
                     new AsyncCallback(HandleDataReceived), state);
                }
                catch{}  
            }
        }
        /// <summary> 
        /// 發送數據 
        /// </summary> 
        /// <param name="state">接收數據的客戶端會話</param> 
        /// <param name="data">數據報文</param> 
        public void Send(ClientInfo state, byte[] data)
        {
            RaisePrepareSend(state);
            Send(state.ClientSocket, data);
        }
        /// <summary> 
        /// 異步發送數據至指定的客戶端 
        /// </summary> 
        /// <param name="client">客戶端</param> 
        /// <param name="data">報文</param> 
        public void Send(Socket client, byte[] data)
        {
            if (!IsRunning)
                throw new InvalidProgramException("This TCP Scoket server has not been started.");
            if (client == null)
                throw new ArgumentNullException("client");
            if (data == null)
                throw new ArgumentNullException("data");
            client.BeginSend(data, 0, data.Length, SocketFlags.None,
             new AsyncCallback(SendDataEnd), client);
        }
        /// <summary> 
        /// 發送數據完成處理函數 
        /// </summary> 
        /// <param name="ar">目標客戶端Socket</param> 
        private void SendDataEnd(IAsyncResult ar)
        {
            ((Socket)ar.AsyncState).EndSend(ar);
            RaiseCompletedSend(new TcpSocketServer.ClientInfo((Socket)ar.AsyncState));
        }
        #endregion
        #region 事件 
        #region 客戶端鏈接事件
        public event EventHandler<TCPMessageArgs> ClientConnecting;//客戶端正在鏈接事件
        public event EventHandler<TCPMessageArgs> ClientConnected; //客戶端鏈接事件    
        public event EventHandler<TCPMessageArgs> ClientDisconnected;//客戶端斷開鏈接
        //掛起事件
        private void RaiseClientConnecting(ClientInfo state)
        {
            if(ClientConnecting!=null)
            {
                ClientConnecting(this, new TCPMessageArgs(state));
            }
        }
        private void RaiseClientConnected(ClientInfo state)
        {
            if (ClientConnected != null)
            {
                ClientConnected(this, new TCPMessageArgs(state));
            }
        }
        private void RaiseClientDisconnected(ClientInfo state)
        {
            if (ClientDisconnected != null)
            {
                ClientDisconnected(this, new TCPMessageArgs(state));
            }
        }
        #endregion
        #region 數據發送事件
        public event EventHandler<TCPMessageArgs> PrepareSend;//數據準備發送事件
        public event EventHandler<TCPMessageArgs> DataSending;//數據正在發送事件
        public event EventHandler<TCPMessageArgs> CompletedSend;//數據發送結束事件
        public event EventHandler<TCPMessageArgs> DataReceived;//接受到客戶端數據事件
        //掛起事件
        private void RaisePrepareSend(ClientInfo state)
        {
            if (PrepareSend != null)
            {
                PrepareSend(this, new TCPMessageArgs(state));
            }
        }
        private void RaiseDataSending(ClientInfo state)
        {
            if (PrepareSend != null)
            {
                DataSending(this, new TCPMessageArgs(state));
            }
        }
        private void RaiseDataReceived(ClientInfo state)
        {
            if (DataReceived != null)
            {
                DataReceived(this, new TCPMessageArgs(state));
            }
        }
        private void RaiseCompletedSend(ClientInfo state)
        {
            if (CompletedSend != null)
            {
                CompletedSend(this, new TCPMessageArgs(state));
            }
        }
        #endregion
        #region 關閉鏈接事件
        public event EventHandler<TCPMessageArgs> ClientClose;//關閉客戶端事件
        public event EventHandler<TCPMessageArgs> AllClientsClose;//關閉全部客戶端事件
        //掛起事件
        private void RaiseClientClose(ClientInfo state)
        {
            if(ClientClose!=null)
            {
                ClientClose(this, new TcpSocketServer.TCPMessageArgs(state));
            }
        }
        private void RaiseAllClientClose(ClientInfo state)
        {
            if (AllClientsClose != null)
            {
                AllClientsClose(this, new TcpSocketServer.TCPMessageArgs(state));
            }
        }
        #endregion
        #region 其餘事件
        public event EventHandler<TCPMessageArgs> NetError;// 網絡錯誤事件
        public event EventHandler<TCPMessageArgs> OtherException;//其餘異常
        //掛起事件
        private void RaiseNetError(ClientInfo state)
        {
            if (OtherException != null)
            {
                OtherException(this, new TCPMessageArgs(state));
            }
        }
        private void RaiseOtherException(ClientInfo state)
        {
            RaiseOtherException(state);
        }
        #endregion
        #endregion
        #region 釋放 
        /// <summary> 
        /// Performs application-defined tasks associated with freeing,  
        /// releasing, or resetting unmanaged resources. 
        /// </summary> 
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        /// <summary> 
        /// Releases unmanaged and - optionally - managed resources 
        /// </summary> 
        /// <param name="disposing"><c>true</c> to release  
        /// both managed and unmanaged resources; <c>false</c>  
        /// to release only unmanaged resources.</param> 
        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    try
                    {
                        Stop();
                        if (_serverSock != null)
                        {
                            _serverSock = null;
                        }
                    }
                    catch (SocketException)
                    {
                        //TODO 
                        RaiseOtherException(null);
                    }
                }
                disposed = true;
            }
        }
        #endregion
    }
}

2)客戶端app

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace TcpSocketClient
{
    public class TCPClientAsync
    {
        #region 字段

        private Socket clientSock;

        //private byte[] recvBuffer;

        private ClientInfo state;

        #endregion

        #region 屬性

        public IPAddress Address { get; private set; }// 監聽的IP地址  

        public int Port { get; private set; }// 監聽的端口  
        public bool IsConnected { get;private set; }

        #endregion

        #region 構造方法

        public TCPClientAsync(IPAddress ipAddress,int port)
        {
            this.Address = ipAddress;
            this.Port = port;
            clientSock=new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        }

        public TCPClientAsync(IPEndPoint ipEndPort)
            :this(ipEndPort.Address,ipEndPort.Port)
        {
        }

        #endregion

        #region Method

        public void Connect()//開始鏈接
        {
            if(!IsConnected)
            {
                //clientSock.BeginConnect(Address, Port, new AsyncCallback(HandleConnectAccepted), clientSock);
                clientSock.BeginConnect(Address, Port, iAsyncResult=>
                {
                    try
                    {
                        clientSock.EndConnect(iAsyncResult);
                        IsConnected = true;
                        state = new TcpSocketClient.ClientInfo(clientSock);
                        RaiseConnectAccepted(state);//掛起鏈接事件
                    }
                    catch
                    {
                        //TODO鏈接失敗
                        RaiseConnectFailed();
                    }
                    
                }, null);
            }            
        }

        //private void HandleConnectAccepted(IAsyncResult iAsyncResult)
        //{
        //    clientSock.EndConnect(iAsyncResult);
        //    IsConnected = true;
        //}

        public void Send(byte[] data)
        {
            if (!IsConnected) return;

            //clientSock.BeginSend(data, 0, data.Length, SocketFlags.None, new AsyncCallback(HandleDataSend), null);
            clientSock.BeginSend(data, 0, data.Length, SocketFlags.None, iAsyncResult=>
            {
                clientSock.EndSend(iAsyncResult);

                RaiseDataSend(state);
            }, null);
        }

        public void Receive()
        {
            if (!IsConnected) return;

            state.RecvDataBuffer = new byte[clientSock.ReceiveBufferSize];
            clientSock.BeginReceive(state.RecvDataBuffer, 0, state.RecvDataBuffer.Length, SocketFlags.None, new AsyncCallback(HandleDataReceive), null);
        }

        private void HandleDataReceive(IAsyncResult iAsyncResult)
        {
            int recv = 0;
            try
            {
                recv = clientSock.EndReceive(iAsyncResult);

                if (recv == 0)//客戶端主動斷開鏈接時recv=0
                {
                    Close();
                    RaiseServerCloseLink();
                    return;
                }

                state._recvdBufferLength = recv;

                RaiseDataReceived(state);
            }
            catch(Exception ex)
            {
                //TODO 信息獲取失敗
                string str = ex.Message;
                return;
            }

            //if (!IsConnected) return;
            clientSock.BeginReceive(state.RecvDataBuffer, 0, state.RecvDataBuffer.Length, SocketFlags.None, new AsyncCallback(HandleDataReceive), null);
        }
        //private void HandleDataSend(IAsyncResult iAsyncResult)
        //{
        //    clientSock.EndSend(iAsyncResult);
        //}

        public void Close()
        {
            //關閉數據的接受和發送  
            clientSock.Shutdown(SocketShutdown.Both);

            //清理資源  
            clientSock.Close();

            state = null;
            IsConnected = false;
            GC.Collect();
        }
        #endregion

        #region 事件

        public event EventHandler<TCPMessageArgs> ConnectAccepted;//鏈接事件 

        public event EventHandler<TCPMessageArgs> DataSend;//數據發送事件  

        public event EventHandler<TCPMessageArgs> DataReceived;//數據發送事件

        public event EventHandler<TCPMessageArgs> ErrorException;//錯誤信息

        public event EventHandler<TCPMessageArgs> ServerCloseLink;//服務端關閉鏈接

        public event EventHandler<TCPMessageArgs> ConnectFailed;//鏈接失敗

        private void RaiseConnectAccepted(ClientInfo state)
        {
            if (ConnectAccepted != null)
            {
                ConnectAccepted(this, new TCPMessageArgs(state));
            }
        }

        private void RaiseDataSend(ClientInfo state)
        {
            if (DataSend != null)
            {
                DataSend(this, new TcpSocketClient.TCPMessageArgs(state));
            }
        }

        private void RaiseDataReceived(ClientInfo state)
        {
            if(DataReceived!=null)
            {
                DataReceived(this, new TcpSocketClient.TCPMessageArgs(state));
            }
        }

        private void RaiseErrorException()
        {
            if(ErrorException!=null)
            {
                ErrorException(this, null);
            }
        }

        private void RaiseServerCloseLink()
        {
            if(ServerCloseLink!=null)
            {
                ServerCloseLink(this, null);
            }
        }

        private void RaiseConnectFailed()
        {
            if(ConnectFailed!=null)
            {
                ConnectFailed(this,null);
            }
        }

        #endregion
    }
}

3)消息類異步

此類存儲相關消息socket

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TcpSocketServer
{
    /// <summary>
    /// Socket TCP事件參數
    /// </summary>
    public class TCPMessageArgs : EventArgs
    {
        /// <summary>  
        /// 提示信息  
        /// </summary>  
        public string _msg;

        /// <summary>  
        /// 客戶端狀態封裝類  
        /// </summary>  
        public ClientInfo state;

        /// <summary>  
        /// 是否已經處理過了  
        /// </summary>  
       // public bool IsHandled { get; set; }

        public TCPMessageArgs(string msg)
        {
            this._msg = msg;
            //IsHandled = false;
        }
        public TCPMessageArgs(ClientInfo state)
        {
            this.state = state;
            // IsHandled = false;
        }
        public TCPMessageArgs(string msg, ClientInfo state)
        {
            this._msg = msg;
            this.state = state;
            //IsHandled = false;
        }
    }
}

4)服務端存儲全部客戶端類tcp

經過ide

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;

namespace TcpSocketServer
{
    
    /// <summary>
    /// 客戶端信息
    /// </summary>
    public class ClientInfo
    {
        #region 字段 

        public int _recvdBufferLength;//接收到的數據長度

        private byte[] _recvBuffer;// 接收數據緩衝區  

        private string _datagram;// 客戶端發送到服務器的報文 
  
        private Socket _clientSock;// 客戶端的Socket

        private string tempMsg = string.Empty;

        #endregion

        #region 屬性  

        /// <summary>  
        /// 接收數據緩衝區   
        /// </summary>  
        public byte[] RecvDataBuffer
        {
            get
            {
                return _recvBuffer;
            }
            set
            {
                _recvBuffer = value;
            }
        }

        /// <summary>  
        /// 存取會話的報文  
        /// </summary>  
        public string Datagram
        {
            get
            {
                _datagram = Encoding.Default.GetString(_recvBuffer, 0, _recvdBufferLength);
                return _datagram;
            }
        }

        public List<MsgProtocol> MsgList
        {
            get
            {
                _datagram = Encoding.Default.GetString(_recvBuffer, 0, _recvdBufferLength);
                return HandlerRecvdString(_datagram);
            }
        }


        /// <summary>  
        /// 得到與客戶端會話關聯的Socket對象  
        /// </summary>  
        public Socket ClientSocket
        {
            get
            {
                return _clientSock;
            }
        }

        #endregion

        public ClientInfo(Socket clientSocket)
        {
            _clientSock = clientSocket;
        }

 
        public void Close()
        {
            //關閉數據的接受和發送  
            _clientSock.Shutdown(SocketShutdown.Both);

            //清理資源  
            _clientSock.Close();
        }

        public List<MsgProtocol> HandlerRecvdString(string msg)
        {
            List<MsgProtocol> msgProList = new List<MsgProtocol>();
            if (!String.IsNullOrEmpty(tempMsg))
            {
                msg = tempMsg + msg;
            }
            string pattern = "(^<protocol>.*?</protocol>)";
            if (Regex.IsMatch(msg, pattern))
            {
                //匹配協議內容
                string message = Regex.Match(msg, pattern).Groups[0].Value;
                //將匹配的內容添加到集合
                msgProList.Add(HandleMsg(message));
                tempMsg = string.Empty;
                //截取未匹配字符串,進行下一次匹配
                msg = msg.Substring(message.Length);
                if (!String.IsNullOrEmpty(msg))
                {
                    msgProList.AddRange(HandlerRecvdString(msg));
                }
            }
            else
            {
                tempMsg = msg;
            }
            return msgProList;
        }

        private MsgProtocol HandleMsg(string msg)
        {
            MsgProtocol msgProtocol = new TcpSocketServer.MsgProtocol();

            XmlDocument xml = new XmlDocument();
            xml.LoadXml(msg);
            XmlNode node = xml.DocumentElement;
            XmlNode message = node.FirstChild;// xml.SelectSingleNode("message");

            if(message.Attributes["type"].Value==MsgType.TEXT.ToString())
            {
                TextProtocol text = new TcpSocketServer.TextProtocol(message.Attributes["content"].Value);
                msgProtocol.type = MsgType.TEXT;
                msgProtocol.textProtocol = text;
            }
            else
            {
                FileProtocol file = new TcpSocketServer.FileProtocol(message.Attributes["content"].Value, message.Attributes["file"].Value);
                msgProtocol.type = MsgType.FILE;
                msgProtocol.fileProtocol = file;
            }

            return msgProtocol;
        }

    }
}

5)消息協議函數

處理每次消息發送時粘包問題測試

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace TcpSocketServer
{
    public enum MsgType
    {
        UNKNOWN = 0,
        TEXT = 1,
        FILE = 2
    }

    public class TextProtocol
    {
        public string content;

        private MsgType type=MsgType.TEXT;

        public TextProtocol(string content)
        {
            this.content = content;
        }

        //public byte[] ToBytes()
        //{
        //    string msgPackage = ToString();
        //    return Encoding.Default.GetBytes(msgPackage);
        //}

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<message ");
            sb.Append(string.Format("type=\"{0}\"", type.ToString()));
            sb.Append(string.Format(" content=\"{0}\"", content));
            sb.Append("/>");

            return sb.ToString();
        }
    }

    public class FileProtocol
    {
        public string filePath;

        public string content;

        private string fileName;

        private MsgType type = MsgType.FILE;

        public FileProtocol(string content,string filePath)
        {
            this.filePath = filePath;
            this.content = content;
        }

        public FileProtocol(string filePath)
        {
            this.filePath = filePath;
        }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<message ");
            sb.Append(string.Format("type=\"{0}\"", type.ToString()));
            sb.Append(string.Format(" file=\"{0}\"", GetFileName()));
            sb.Append(string.Format(" content=\"{0}\"", GetFileContent()));
            sb.Append("/>");

            return sb.ToString();
        }

        public byte[] ToBytes()
        {
            return Encoding.Default.GetBytes(content);
        }

        private string GetFileName()
        {
            if(File.Exists(filePath))
            {
                return Path.GetFileName(filePath);
            }
            else
            {
                return "";
            }
        }

        private string GetFileContent()
        {
            if(File.Exists(filePath))
            {
                byte[] bytes = File.ReadAllBytes(filePath);
                content = Encoding.Default.GetString(bytes);
            }
  
            return content;
        }
    }

    public class MsgProtocol
    {
        //公共字段
        //public string fileName;
        public MsgType type = MsgType.UNKNOWN;

        public TextProtocol textProtocol;

        public FileProtocol fileProtocol;

        public MsgProtocol()
        {

        }

        public MsgProtocol(TextProtocol textProtocol)
        {
            this.type = MsgType.TEXT;
            this.textProtocol = textProtocol;
        } 
        
        public MsgProtocol(FileProtocol fileProtocol)
        {
            this.type = MsgType.FILE;
            this.fileProtocol = fileProtocol;
        }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<protocol>");

            if(type==MsgType.TEXT)
            {
                sb.Append(textProtocol.ToString());
            }
            else
            {
                sb.Append(fileProtocol.ToString());
            }

            sb.Append("</protocol>");

            return sb.ToString();
        }

        public byte[] ToBytes()
        {
            return Encoding.Default.GetBytes(this.ToString());
        }

        //public MsgProtocol(string filePath,MsgType type)
        //{
        //    type = MsgType.FILE;
        //    this.fileName = fileName;
        //    this.file
        //}      
    }
}

 

6)主程序應用

一、服務端

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TcpSocketServer
{
    class Program
    {
        private static TCPServerAsync tcpServer;

        static void Main(string[] args)
        {
            tcpServer = new TcpSocketServer.TCPServerAsync(8899);

            tcpServer.DataReceived += new EventHandler<TcpSocketServer.TCPMessageArgs>(OnDataReceived);
            tcpServer.ClientConnected += new EventHandler<TcpSocketServer.TCPMessageArgs>(OnClientConnected);
            tcpServer.ClientDisconnected += new EventHandler<TcpSocketServer.TCPMessageArgs>(OnClientDisconnected);

            tcpServer.Start();
            Console.ReadKey();        
        }

        public static void OnDataReceived(object obj,TCPMessageArgs message)
        {
            ClientInfo state = message.state;
            string sendData = "Server ";

            //byte[] data = state.RecvDataBuffer;
            //string strData = Encoding.Default.GetString(data);

            //Console.WriteLine(message.state.Datagram);


            #region 協議功能測試
            List<MsgProtocol> msgList = state.MsgList;

            foreach (MsgProtocol msgProtocol in msgList)
            {
                if (msgProtocol.type == MsgType.TEXT)
                {
                    Console.WriteLine(msgProtocol.textProtocol.content);
                    sendData += msgProtocol.textProtocol.content;
                }
                else
                {
                    Console.WriteLine(msgProtocol.fileProtocol.filePath);
                    sendData += msgProtocol.fileProtocol.filePath;
                }

            }
            #endregion

            if (message.state.Datagram=="close")
            {
                tcpServer.Close(message.state);
                return;
            }

            //數據處理後發送回客戶端
            //string sendData = "Server " + message.state.Datagram;
            //byte[] sendBytes = Encoding.Default.GetBytes(sendData);
            //tcpServer.Send(state, sendBytes);

            #region 協議功能測試      
            MsgProtocol protocol = new TcpSocketServer.MsgProtocol(new TcpSocketServer.TextProtocol(sendData));
            tcpServer.Send(state, protocol.ToBytes());
            #endregion
        }

        public static void OnClientConnected(object obj, TCPMessageArgs message)
        {
            Console.WriteLine("Connect:" + message.state.ClientSocket.RemoteEndPoint.ToString());
        }
        public static void OnClientDisconnected(object obj, TCPMessageArgs message)
        {
            Console.WriteLine("Disconnect:" + message.state.ClientSocket.RemoteEndPoint.ToString());
            tcpServer.Close(message.state);
        }
    }
}

 

二、客戶端調用

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;

namespace TcpSocketClient
{
    class Program
    {
        private static TCPClientAsync tcpclient;
        private static bool b_Connecting = true;

        static void Main(string[] args)
        {
            IPAddress ip = IPAddress.Parse("192.168.8.15");
            tcpclient = new TcpSocketClient.TCPClientAsync(ip, 8899);
            tcpclient.ConnectAccepted += new EventHandler<TcpSocketClient.TCPMessageArgs>(OnConnected);
            tcpclient.DataReceived += new EventHandler<TcpSocketClient.TCPMessageArgs>(OnReceived);
            tcpclient.ServerCloseLink += new EventHandler<TCPMessageArgs>(OnDisConnected);
            tcpclient.Connect();

            while(b_Connecting)
            {
                string msg = Console.ReadLine();
                if(msg=="exit")
                {
                    tcpclient.Close();
                    //b_Connecting = false;
                    break;
                }

                if(msg=="close")
                {
                    //tcpclient.IsConnected = false;
                }

                //byte[] data = Encoding.Default.GetBytes(msg);
                //tcpclient.Send(data);
                //tcpclient.Receive();

                MsgProtocol msgProtocol = new TcpSocketClient.MsgProtocol(new TcpSocketClient.TextProtocol(msg));

                tcpclient.Send(msgProtocol.ToBytes());
            }            
        }

        public static void OnConnected(object obj,TCPMessageArgs msg)
        {
            Console.WriteLine("Connected.......");
            tcpclient.Receive();
        }

        public static void OnReceived(object obj, TCPMessageArgs msg)
        {
            //Console.WriteLine("Receivedd "+msg.state.Datagram);
            List<MsgProtocol> msgList = msg.state.MsgList;

            foreach(MsgProtocol msgProtocol in msgList)
            {
                if(msgProtocol.type==MsgType.TEXT)
                {
                    Console.WriteLine(msgProtocol.textProtocol.content);
                }
                else
                {
                    Console.WriteLine(msgProtocol.fileProtocol.filePath);
                }
                
            }
        }

        public static void OnDisConnected(object obj,TCPMessageArgs msg)
        {
            Console.WriteLine("Server Disconnected");
        }
    }
}

 

 

PS:未做客戶端短線重連

相關文章
相關標籤/搜索