• Socket 简易搭建


    虽然之前在项目中也有用过Socket,但始终不是自己搭建的,所以对Server,Clinet端以及心跳,断线重连总没有很深入的理解,现在自己搭建了一遍加深一下理解。

    服务端使用WPF界面,客户端使用控制台。实现了心跳,断线重连,一个服务端对应多个客户端的功能。

    一.服务端

    1.1 先创建一个Socket实例,并绑定到20000端口号;通过Listen方法开始监听并设置最大监听数量。

    //新建一个Socket服务端实例,并绑定到20000端口
    socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    socketServer.Bind(new IPEndPoint(IPAddress.Any, 20000));
    
    //设置最大监听数量
    socketServer.Listen(10);

    1.2 当有客户端成功连接,则会通过Accept方法生产一个新的Socket实例;此时可开启心跳定时器,并开启一个线程接收消息。

    复制代码
    //开启一个线程监听客户端
    Thread thd = new Thread(new ThreadStart(ListenSocket));
    thd.Start();
    
    /// <summary>
    /// 开始监听
    /// </summary>
    private void ListenSocket()
    {
        try
        {
            while (true)
            {
                Socket _socket = socketServer.Accept();
    
                //开始心跳
                System.Timers.Timer heartbeatTimer = new System.Timers.Timer();
                heartbeatTimer.Interval = 60000;
                heartbeatTimer.Elapsed += new System.Timers.ElapsedEventHandler((s, e) => heartbeatTimerIsUp(s, e, _socket));
                heartbeatTimer.Start();
    
                Thread thdReceive = new Thread(new ParameterizedThreadStart(thdRevMethod));
                thdReceive.Start(_socket);
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show("程序出现异常:" + ex);
        }
    }
    复制代码

    1.3 接收消息与发送消息的代码如下

    复制代码
    /// <summary>
    /// 接收消息
    /// </summary>
    /// <param name="obj"></param>
    private void thdRevMethod(object obj)
    {
        Socket _socket = obj as Socket;
        try
        {
            while (true)
            {
                byte[] resByte = new byte[1024];
                int resInt = _socket.Receive(resByte);
                if (resInt > 0)
                {
                    string res = Encoding.Default.GetString(resByte, 0, resInt);///接收消息后操作
                }
            }
        }
        catch (SocketException sex)
        {
            if (sex.SocketErrorCode == SocketError.ConnectionReset)
            {
                //当客户端断开连接,从客户端列表中移除该客户端
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show("程序出现异常:" + ex);
        }
    }
    
    /// <summary>
    /// 发送消息
    /// </summary>
    /// <param name="msg"></param>
    /// <param name="ipAndPord"></param>
    public bool sendMsg(string msg,string ipAndPord)
    {
        try
        {
            Socket _socket = socketTimerDic.SingleOrDefault(r => string.Equals(r.Key.RemoteEndPoint.ToString(), ipAndPord)).Key;
            if (_socket != null)
            {
                byte[] byteStr = Encoding.Default.GetBytes(msg);
                _socket.Send(byteStr);
                return true;
            }
            else
            {
                return false;
            }
        }
        catch (Exception)
        {
            return false;
        }
    }
    复制代码

    二.客户端

    2.1 先创建一个Socket实例,并连接到服务端所在的ip端口;连接成功后开启心跳定会器并开启发送和接收消息的两个线程。

    复制代码
    // 新建客户端实例,并连接到服务端所在的端口号
    socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    
    socketClient.Connect("127.0.0.1", 20000);
    Console.WriteLine("成功连接到服务端");
    heartbeatTimer.Start();
    
    //开启一个线程发送消息
    Thread thdSend = new Thread(new ThreadStart(thdSendMethod));
    thdSend.Start();
    
    //开启一个线程接收信息
    Thread thdRev = new Thread(new ThreadStart(thdRevMethod));
    thdRev.Start();
    复制代码

    2.2 发送消息和接收消息的代码如下,当服务端断开会在接收消息的线程中触发sex.SocketErrorCode == SocketError.ConnectionReset的异常,此时捕获到后开启重连定时器即可

    复制代码
    /// <summary>
    /// 接收消息
    /// </summary>
    private static void thdRevMethod()
    {
        try
        {
            while (true)
            {
                byte[] resByte = new byte[1024];
                int resInt = socketClient.Receive(resByte);
                if (resInt > 0)
                {
                     Console.WriteLine(Encoding.Default.GetString(resByte,0, resInt));
                }
            }
    
        }
        catch (SocketException sex)
        {
            if (sex.SocketErrorCode == SocketError.ConnectionReset)
            {
                Console.WriteLine("服务端断开!5s后重连!");
                reconnectTimer.Start();
                heartbeatTimer.Stop();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("程序出现异常:" + ex);
            heartbeatTimer.Stop();
        }
    }
    
    //发送信息
    private static void thdSendMethod()
    {
        try
        {
            while (true)
            {
                string res = Console.ReadLine();
                byte[] resByte = Encoding.Default.GetBytes(res);
                socketClient.Send(resByte);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("程序出现异常:" + ex);
            heartbeatTimer.Stop();
        }
    }    
    复制代码

    三.运行示例

    四..总结

    假如代码中有错误的地方,希望可以帮忙指出来改之。

    其中要注意的地方如下:
    1.WPF关闭窗口后,需要通过 Environment.Exit(0);来结束掉当前整个服务端进程,否则Socket开启的接收和发送进程将还在,客户端也不会检测到服务端断开。

    2.在SocketException中捕获异常sex.SocketErrorCode == SocketError.ConnectionReset时说明客户端/服务端连接断开了,需要进行重连等操作。

    3.在接收到消息时候需要用GetString(byte[] bytes, int index, int count)指定长度,而不该使用GetString(byte[] bytes),否则可能出现很多空格。

    4.定时器假如需要传递参数,可以通过设置全局变量,或者(s, e) => heartbeatTimerIsUp(s, e, _socket)单独传递一个变量到方法中。

    源码下载地址如下:SocketDemo.rar

  • 相关阅读:
    mybatis3这个问题我晕为什么对于配置信息的节点放的位置也会报错
    QTP的那些事增删改查中的增加操作的测试用例及其脚本设计思路
    QTP的那些事importsheet注意的一些事情
    mybatis3中的结果集
    QTP的那些事终极项目脚本设计思路及其测试查询功能的一些实际项目体会
    mybatis+spring整合的几个好的例子
    QTP的那些事操作excel数据需要注意的事
    hibernate4的使用第一步环境搭建
    项目中关于IFRAME引发的问题【出现率很高】
    oracle直接sql语句后台递归查询返回一个树
  • 原文地址:https://www.cnblogs.com/Freedom0221/p/12604354.html
Copyright © 2020-2023  润新知