天天看点

基于TCP的C#通讯窗口

1.前言

这两天在公司刚入职没得电脑,师傅叫我用tcp/ip编写一个小的聊天Demo。刚好这两天才看设计模式,就寻思着将设计模式里面学的的东西应用到这个小Demo中。考虑到后期代码的界面的复用,这里用的是Build模式,Builder模式主要用于“分步骤构建一个复杂的对象”。在这其中“分步骤”是一个稳定算法,也就是程序的主线,而负责对象的各个部分则经常变化。变化点在哪里,封装哪里,Builder模式主要在与应对“复杂对象各个部分”的频繁需求变动。其缺点在于难以应对“分步骤构建算法”的需求变动。代码链接。

2.服务端

不多bb,这几上代码。先创建一个抽象类,然后罗列出主要的方法。感觉这利用接口也可以实现出不错的效果。

public abstract class Server
    {
        public delegate void EventReceiveMessage(string message);
        /// <summary>
        /// 开始服务
        /// </summary>
        /// <returns></returns>
        public abstract bool StartService();
        /// <summary>
        /// 停止服务
        /// </summary>
        /// <returns></returns>
        public abstract bool EndService();

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="message"></param>
        public abstract void SendMessage(string message);
        /// <summary>
        /// 连接状态
        /// </summary>
        public abstract bool ConnectState { get;}

        /// <summary>
        /// 数据接收事件
        /// </summary>
        public abstract event EventReceiveMessage OnReceiveMessage;

    }
           

然后就是,这里使用Task进行后台线程监视数据变化,不过好像Task不适合这种长时间监测的任务,用线程池可能会好一点。

public class TcpConnectionServer : Server
    {
        private bool StartServiceBool = false;
        private Socket sendreceiveSocket;
        TcpListener server;
        /// <summary>
        /// 获取一个bool量,判断是否连接,这个值是根据Socket的连接状态来判定的
        /// </summary>
        public override bool ConnectState { get => (sendreceiveSocket!=null)?sendreceiveSocket.Connected:false; }

        public override event EventReceiveMessage OnReceiveMessage;

        public override bool EndService()
        {
            //先将StartServiceBool置为false
            StartServiceBool = false;
            sendreceiveSocket.Shutdown(SocketShutdown.Send);
            server.Stop();
            OnReceiveMessage("服务已关闭");
            return true;
        }

        public override void SendMessage(string message)
        {
            byte[] res;
            res = System.Text.Encoding.Default.GetBytes(message);
            sendreceiveSocket.Send(res);//发送
            //sendSocket.Shutdown(SocketShutdown.Send);
        }

        public override bool StartService()
        {
            IPAddress ipListener = new IPAddress(new byte[] { 127, 1, 1, 1 });
            server = new TcpListener(ipListener, 8005);
            server.Start();//服务端启动侦听
            if(null!=OnReceiveMessage)
            {
                //防止其它线程操作事件
                EventReceiveMessage TempOnReceiveMessage = OnReceiveMessage;
                OnReceiveMessage("服务端启动成功");
            }
            sendreceiveSocket = server.AcceptSocket();
            StartServiceBool = true;
            Task task = Task.Factory.StartNew(() =>
              {
                  //Socket s = sendreceiveSocket;
                  byte[] recByte = new byte[4096];
                  while (StartServiceBool)
                  {
                      try
                      {
                          if(sendreceiveSocket.Available>0)
                          {
                              int bytes = sendreceiveSocket.Receive(recByte, recByte.Length, 0);
                              //Encoding.Default.GetBytes("发送为空");
                              string recStr = Encoding.Default.GetString(recByte, 0, bytes);
                              OnReceiveMessage(recStr);
                          }
                          System.Threading.Thread.Sleep(100);
                      }
                      catch (Exception ex)
                      {

                      }
                      
                  }
              });
            return true;
        }
    }
           

下面就是设计出的界面了

基于TCP的C#通讯窗口

将Server封装起来,然后在界面中就可以直接调用了。客户端也是同样的道理,我将项目上传。

3.服务端

贴代码吧

namespace ConsoleClient
{
    public abstract class Client
    {
        public delegate void EventReceiveMessage(string message);
        /// <summary>
        /// 连接服务器
        /// </summary>
        /// <returns></returns>
        public abstract bool ConnectServer();
        /// <summary>
        /// 关闭连接
        /// </summary>
        /// <returns></returns>
        public abstract bool DisConnect();

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="message"></param>
        public abstract void SendMessage(string message);
        /// <summary>
        /// 连接状态
        /// </summary>
        public abstract bool ConnectState { get; }

        /// <summary>
        /// 数据接收事件
        /// </summary>
        public abstract event EventReceiveMessage OnReceiveMessage;
    }

    public class TcpConnectionClient : Client
    {
        public override bool ConnectState { get => (null!=Serverclient) ? Serverclient.Connected : false; }

        public override event EventReceiveMessage OnReceiveMessage;
        IPAddress IPClient;
        TcpClient Serverclient;
        NetworkStream SendReceiveStream;
        bool StartServiceBool = false;
        //this.reader = new StreamReader(this.stream);
        //this.writer = new StreamWriter(this.stream);
        public override bool ConnectServer()
        {
            //客户端
            IPClient = IPAddress.Parse("127.1.1.1");
            Serverclient = new TcpClient();
            Serverclient.Connect(IPClient, 8005);//8005端口号,必须与服务端给定的端口号一致,否则天堂无门
            SendReceiveStream = Serverclient.GetStream();
            StartServiceBool = true;
            Task task = Task.Factory.StartNew(() =>
              {
                  byte[] buffer;
                  while (StartServiceBool)
                  {
                      try
                      {
                          if(Serverclient.Available > 0)
                          {
                              
                              buffer = new byte[Serverclient.Available];
                              SendReceiveStream.Read(buffer, 0, Serverclient.Available);
                              string receoveStr = Encoding.Default.GetString(buffer);
                              OnReceiveMessage(receoveStr);
                          }
                          System.Threading.Thread.Sleep(100);
                      }
                      catch(Exception ex)
                      {

                      }
  
                  }
              });
            return true;

        }

        public override bool DisConnect()
        {

            StartServiceBool = false;
            SendReceiveStream.Dispose();
            Serverclient.Close();
            Serverclient = null;
            return true;
        }

        public override void SendMessage(string message)
        {
            byte[] res;
            res = System.Text.Encoding.Default.GetBytes(message);
            SendReceiveStream.Write(res,0,res.Length);
        }
    }
}
           

4.小结

TCP/IP还是很复杂的,这次写的很多方面不好,后面在慢慢研究。