精华内容
下载资源
问答
  • 断线重连
    千次阅读
    2022-02-06 16:48:34

    游戏在运行过程中,由于网络原因导致和服务器的长连接断开,需要使用重连机制来确保游戏稳定运行。重连是指和服务器重新建立连接,并且无需重新登录。
    在手机上,断线重连机制显得额外重要,我们在接打电话,切换应用,锁定屏幕,进入电梯等日常行为中都会导致游戏产生网络问题。
    那么断线重连如何实现呢?

    多问问题

    1. 在哪些情况下需要重连?哪些情况需要重新登录?
    2. 重连流程是什么样的?如何重新验证客户端身份?
    3. 断线前,客户端未收到的消息,如何处理?
    4. 重连成功后,是否停留在当前界面?如果停留,是否会造成卡死?

    给出自己的见解

    1. 网络正常情况下,由客户端收到的错误码做出区分,网络异常情况下,直接走重连流程。详尽的错误码对应的方案需要前后端共同拟定。
    2. 重连的流程一般为: 建立新连接->使用token重新验证身份->拉取历史消息(此步骤非必须)->切换界面。一般使用上一次的token进行重新验证。
    3. 断线前丢失的消息,可以不做处理,重连成功后,在特定的界面上需要切换会主界面,比如战斗结算页面。也可以在后端存储前端未确认的消息,在重连后提供拉取接口(此方案需要在协议头中加入已收到的最大消息号)。
    4. 如果后端提供未确认消息拉取接口,则重连成功后无需切换界面,如果对丢失的消息不做处理,需要在特定界面进行切换,防止卡死。
    更多相关内容
  • 1. 串口与TCP/IP调试助手,支持仿真设备通讯(把助手当作一个设备仪器,收到命令后能自动回复) 2. 支持ASCII码与HEX 一键转换,支持ASCII与HEX两种编码方式 3. TCP/IP通讯支持断线重连,实时知道连接状态
  • 主要介绍了Spring boot 数据库连接断线重连问题,需要的朋友可以参考下
  • websocket封装基于 1.websocket四大基础事件 2.扩展心跳检测与断线重连功能 3.核心对象封装,生成与销毁不需要客户端控制
  • 典型TCP/IP 通讯源码 实时连接状态查询 支持连接断开后自动重新连接
  • 主要介绍了C# Mqtt 断线重连,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • c#socket异步编程及断线重连。并怎样实现循环接受服务器的命令并处理。
  • ESP8266开发,实现MQTT客户端,与MQTT服务器通信,断线重连,有软件安装、使用及详细的代码注释,方便快速搭建自己的物联网系统。
  • live555demo版支持断线重连,多路接入 live555demo版支持断线重连,多路接入 live555demo版支持断线重连,多路接入 live555demo版支持断线重连,多路接入 断线重连并没有完全实现,但是整个思路已经很清晰。上层已...
  • c#Socket客户端断线重连封装类(可直接调用).rar
  • paho 断线重连方法

    2018-02-02 12:46:23
    paho没分钟自动检测连接状态,若发现连接断开,则自动重连.
  • Delphi ClientSocket断线重连.zip
  • 永不掉线自动重连多用户管理系统【服务端_客户端】 1、掉线自动重连 2、检测账号到期时间限制 3、检测账号重复登陆 4、检测软件更新 5、检测账号黑名单 7、服务端踢出用户 8、服务端与客户端交互数据 9、...
  • 自己写的源码,请拿去用!
  • 寞水

    使用脚本,即可实现。

    #!/bin/bash
    
    #exit 0
    
    #echo "4g test"
    #ls /dev/ttyU*
    #cat /dev/ttyUSB2 &
    #echo -en "AT\r\n" > /dev/ttyUSB2
    #killall cat
    #exit 0
    
    echo "4g pppd"
    
    count=0
    
    #sleep 5
    
    #procedure='pppd'
    if [ "$(ps |grep "pppd call" |grep -v grep |awk '{print $1}')" ]; then
        killall pppd #结束PPPD进程
    fi
    
    for ((i=0; i<15; i++))
    do
        sleep 1
        if [ -f "/sys/class/gpio/gpio65/value" ]; then
            break
        else
            echo 65 > /sys/class/gpio/export
        fi
    done
    echo high > /sys/class/gpio/gpio65/direction
    
    fun_check_usb(){
        countCheckUSB=0
        while true
        do
            usleep 500000
            ret=`ls /dev/ttyUSB*`
            if [ "$ret" ]; then
                echo $ret
                break
            fi
            let countCheckUSB++
            if [ $countCheckUSB -gt 35 ]; then
                reboot
                exit 0
            fi
        done
    }
    fun_check_usb
    
    #"/sys/class/net/eth0"
    #ifconfig eth0 down
    #ifconfig eth1 down
    
    #rm /etc/resolv.conf
    #ln -s /etc/ppp/resolv.conf /etc/resolv.conf
    cp /etc/ppp/resolv.conf /etc/resolv.conf
    
    pppd call wcdma-ec20 >/dev/null 2>&1 &
    
    sleep 12 #等待12秒
    fun_wait_ppp0(){
        countWait=0
        while true
        do
            usleep 500000
            if [ "$(ifconfig |grep ppp0)" ]; then
                break
            fi
            let countWait++
            echo "pppd countWait=$countWait"
            if [ $countWait -gt 30 ]; then
                date
                killall pppd #结束PPPD进程
                echo "ppp0 is not existed"
                if [ $count -lt 15 ]; then
                    count=15
                fi
                break
                #reboot
                #exit 0
            fi
        done
    }
    fun_wait_ppp0
    
    fun_route(){
        if [ ! "$(route -e |grep default |grep ppp0 |awk '{print $1}')" ]; then
            if [ "$(ifconfig |grep ppp0)" ]; then
                route del default
                route add default dev ppp0
            fi
        fi
    }
    fun_route
    
    #---auto ppp---
    dns1="8.8.8.8"
    dns2="114.114.114.114"
    sleep 12 #等待12秒
    while true
    do
        ping -s 1 -c 5 $dns1 >/dev/null 2>&1 #去PING第一个DNS
        if [ "$?" != "0" ] #假如PING不通
        then
            fun_route
            ping -s 1 -c 2 $dns2 >/dev/null 2>&1 #去PING第二个DNS
            if [ "$?" != "0" ]
            then
                date
                killall pppd #结束PPPD进程
                let count++
                echo "pppd count=$count"
                if [ $count -gt 30 ]; then
                    reboot
                    exit 0
                elif [ $count -gt 15 ]; then
                    echo 0 > /sys/class/gpio/gpio65/value
                    usleep 500000
                    echo 1 > /sys/class/gpio/gpio65/value
                    #ttyUSB* is existed about 10 second
                    #sleep 12 #等待12秒
                fi
                sleep 12 #等待12秒
                fun_check_usb
                #ifconfig eth0 down
                #ifconfig eth1 down
                #cp /etc/ppp/resolv.conf /etc/resolv.conf
                pppd call wcdma-ec20 >/dev/null 2>&1 & #再去拨号
                sleep 12 #等待12秒
                fun_wait_ppp0
                fun_route
                sleep 5
            else
                count=0
                sleep 60 #如果是PING  DNS2通的话就直接等待5秒
            fi
        else
            count=0
            sleep 120 #如果是PING  DNS1通的话就直接等待5秒(一般要设置多长时间去PING请改这里)
        fi
    done
    
    
    

    展开全文
  • reconnect Tcp断线重连实验
  • 虽然RabbitMQ.Client 库有心跳机制,有断线重连机制,但是在网络断掉的时候并不能重连,下面的代码就是解决这个问题,经本人测试有效,适合作为挂机程序

     虽然RabbitMQ.Client 库有心跳机制,有断线重连机制,但是在网络断掉的时候并不能重连,下面的代码就是解决这个问题,经本人测试有效,适合作为挂机程序

    using Newtonsoft.Json;
    using RabbitMQ.Client;
    using RabbitMQ.Client.Events;
    using RabbitMQ.Client.Exceptions;
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace HenryMes.RabbitMQ.Consumer
    {
        class Program
        {
            /// <summary>
            /// RabbitMQ 服务器IP
            /// </summary>
            private static string ServerIp => string.IsNullOrEmpty(Com.DotNet.Utilities.IO.Config.Select("RabbitMQInfo", "HostIp")) ? "127.0.0.1" :
                Com.DotNet.Utilities.IO.Config.Select("RabbitMQInfo", "HostIp");
    
            /// <summary>
            /// RabbitMQ 服务器端口, 默认 5672, 网页监控页面是 15672
            /// </summary>
            private static string ServerPort => string.IsNullOrEmpty(Com.DotNet.Utilities.IO.Config.Select("RabbitMQInfo", "HostPort")) ? "5672" :
                Com.DotNet.Utilities.IO.Config.Select("RabbitMQInfo", "HostPort");
    
            /// <summary>
            /// RabbitMQ 用户名, 默认 guest
            /// </summary>
            private static string UserName => string.IsNullOrEmpty(Com.DotNet.Utilities.IO.Config.Select("RabbitMQInfo", "UserName")) ? "guest" :
                Com.DotNet.Utilities.IO.Config.Select("RabbitMQInfo", "UserName");
    
            /// <summary>
            /// RabbitMQ 密码, 默认 guest
            /// </summary>
            private static string Password => string.IsNullOrEmpty(Com.DotNet.Utilities.IO.Config.Select("RabbitMQInfo", "Password")) ? "guest" :
                Com.DotNet.Utilities.IO.Config.Select("RabbitMQInfo", "Password");
    
            public static string ChannelName => string.IsNullOrEmpty(Com.DotNet.Utilities.IO.Config.Select("RabbitMQInfo", "Channel")) ? "tags_queue" :
                Com.DotNet.Utilities.IO.Config.Select("RabbitMQInfo", "Channel");
    
            /// <summary>
            /// Main entry point to the RabbitMQ .NET AMQP client API. Constructs RabbitMQ.Client.IConnection instances.
            /// </summary>
            private static ConnectionFactory _factory;
    
            private static readonly object Sync = new object();
    
            /// <summary>
            /// Main interface to an AMQP connection.
            /// </summary>
            private static IConnection _conn;
    
            public static IModel _model;
    
            static void Connect()
            {
                try
                {
                    //连接工厂
                    _factory = new ConnectionFactory();
    
                    //连接工厂信息
                    _factory.HostName = ServerIp;// "localhost";
    
                    int rabbitmq_port = 5672;    // 默认是5672端口
                    int.TryParse(ServerPort, out rabbitmq_port);
                    _factory.Port = rabbitmq_port;// "5672"
    
                    _factory.UserName = UserName;
                    _factory.Password = Password;
                    _factory.VirtualHost = "/";
    
                    _factory.RequestedHeartbeat = TimeSpan.FromSeconds(2);//心跳包
                    _factory.AutomaticRecoveryEnabled = true;//自动重连
                    _factory.TopologyRecoveryEnabled = true;//拓扑重连
                    _factory.NetworkRecoveryInterval = TimeSpan.FromSeconds(10);
    
                    //创建连接
                    _conn = _factory.CreateConnection();
    
                    //断开连接时,调用方法自动重连
                    _conn.ConnectionShutdown += Connection_ConnectionShutdown;
    
                    //创建接收频道
                    _model = _conn.CreateModel();
    
                    // 监控消息
                    RabbitmqMessageConsume();
    
                    Console.WriteLine("尝试连接至RabbitMQ服务器:" + ServerIp);
                }
                catch (BrokerUnreachableException e)
                {
                    throw e;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
    
            private static void Connection_ConnectionShutdown(object sender, ShutdownEventArgs e)
            {
                Console.WriteLine("RabbitMQ已经断开连接,正在尝试重新连接至RabbitMQ服务器");
                Reconnect();
            }
    
            private static void Reconnect()
            {
                try
                {
                    //清除连接及频道
                    Cleanup();
                    var mres = new ManualResetEventSlim(false); // state is initially false
                    while (!mres.Wait(3000)) // loop until state is true, checking every 3s
                    {
                        try
                        {
                            //连接
                            Connect();
                            mres.Set(); // state set to true - breaks out of loop
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine("RabbitMQ尝试连接RabbitMQ服务器出现错误:" + ex.Message, ex);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("RabbitMQ尝试重新连接RabbitMQ服务器出现错误:" + ex.Message, ex);
                }
            }
    
            static void Cleanup()
            {
                try
                {
                    if (_model != null && _model.IsOpen)
                    {
                        try
                        {
                            _model.Close();
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine("RabbitMQ重新连接,正在尝试关闭之前的Channel[接收],但遇到错误", ex);
                        }
                        _model = null;
                    }
    
                    if (_conn != null && _conn.IsOpen)
                    {
                        try
                        {
                            _conn.Close();
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine("RabbitMQ重新连接,正在尝试关闭之前的连接,但遇到错误", ex);
                        }
                        _conn = null;
                    }
                    // 重置OPC连接
                    if (OpcManager.GetInstance.Instance != null)
                    {
                        OpcManager.GetInstance.Instance = null;
                    }
                }
                catch (IOException ex)
                {
                    throw ex;
                }
            }
    
            private static void RabbitmqMessageConsume()
            {
                try
                {
                    if (_conn == null || !_conn.IsOpen) throw new Exception("连接为空或连接已经关闭");
                    if (_model == null || !_model.IsOpen) throw new Exception("通道为空或通道已经关闭");
    
    
                    bool queueDurable = true;
    
                    //在MQ上定义一个持久化队列,如果名称相同不会重复创建
                    _model.QueueDeclare(ChannelName, queueDurable, false, false, null);
                    //输入1,那如果接收一个消息,但是没有应答,则客户端不会收到下一个消息
                    _model.BasicQos(0, 1, true);
    
                    //创建基于该队列的消费者,绑定事件
                    var consumer = new EventingBasicConsumer(_model);
    
                    //回应消息监控
                    consumer.Received += SyncData_Received;
    
                    //绑定消费者
                    _model.BasicConsume(ChannelName, //队列名
                                          false,     //false:手动应答;true:自动应答
                                          consumer);
    
                    Console.WriteLine("开始监控RabbitMQ服务器,队列" + ChannelName);
    
                }
                catch (AggregateException ae)
                {
                    //错误信息去重
                    var errorList = (from error in ae.InnerExceptions select error.Message).Distinct().ToList();
                    //打印所有错误信息
                    foreach (string error in errorList)
                    {
                        Console.WriteLine(error);
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
    
            private static void SyncData_Received(object sender, BasicDeliverEventArgs e)
            {
                var watch = new Stopwatch();
                watch.Start();
    
                var body = e.Body.ToArray();
                var message = Encoding.UTF8.GetString(body);
    
                Console.Write("尝试读取OPC变量: ");
    
                //var obj = JsonConvert.DeserializeObject<string[]>(message);
                //var tags = HenryMes.OpcManager.GetInstance.Instance.Read<string>(obj);
    
                //每页条数   
                var nodes = JsonConvert.DeserializeObject<string[]>(message).ToList();
                const int pageSize = 500;
                //页码 0也就是第一条 
                int pageNum = 0;
                var tasks = new List<Task>();
                while (pageNum * pageSize < nodes.Count)
                {
                    var pageNodes = nodes.Skip(pageNum * pageSize).Take(pageSize).Select(t => t).ToArray();
                    tasks.Add(Task.Factory.StartNew(() =>
                    {
                        var tags = OpcManager.GetInstance.Instance.Read<string>(pageNodes);
                    }));
                    pageNum++;
                }
                Task.WaitAll(tasks.ToArray());
    
                // 确认收到
                _model.BasicAck(e.DeliveryTag, false);
                watch.Stop();
                TimeSpan timeSpan = watch.Elapsed;
                Console.WriteLine("处理耗时{0}ms.", watch.ElapsedMilliseconds);
            }
    
            static void Main(string[] args)
            {
                Reconnect();
                Console.ReadKey();
            }
        }
    }
    
    
    

    展开全文
  • TCP异步传输断线重连

    2018-06-02 13:27:59
    异步TCP传输,可以实现短线超时重连机制,代码中有详细注释
  • labview实现TCP通信例程,读写和自动识别网线,断线重连
  • CUBE配置STM32H750+Lan8720+FreeRTOS+lwip+掉线重连+KeepAlive成功移植后的完整cube工程,对于没调通或者没做到掉线重连的会非常有用,打通了掉线重连方案和tcp保活,绝对值得下载
  • C语言 TCP客户端支持掉线重连

    千次阅读 2021-12-03 16:21:04
    reconnect: /* 掉线重连 */ SystemInit(&fd , &sin , argv); // 系统初始化 if (connect (fd, (struct sockaddr *)&sin, sizeof (sin)) ) { perror ("connect"); close(fd); sleep(1); goto reconnect; } printf (...
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <assert.h>
    #include <time.h>
    #include <sys/select.h>
    #include <errno.h>
    #include <strings.h>
    #include <sys/types.h>			/* See NOTES */
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netinet/ip.h>			/* superset of previous */
    #include <arpa/inet.h>
    #include <sys/stat.h>
    #include <sys/ioctl.h>
    #include <fcntl.h>
    #include <netinet/tcp.h>
    
    /**************************************************************************
    **************************************************************************
    *
    * 主方法Main
    	参数argv[1] :SERVER IP
    	参数argv[2] :SERVER PORT
    	
    **************************************************************************
    ***************************************************************************/
    int main(int argc, char **argv)
    {	
    	/* tcp相关参数 */
    	char * msg = (char *) malloc(MSGLEN*sizeof(char));	//TCP报文申请内存
    	struct sockaddr_in sin;
    	struct tcp_info info;
    	int len = sizeof(info);
    	
    reconnect:
    	/* 掉线重连 */
    	SystemInit(&fd , &sin , argv);			//	系统初始化
    	
    	if (connect (fd, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
    		perror ("connect");
    		close(fd);
    		sleep(1);
    		goto reconnect;
    	}
    	printf ("Client staring...OK!\n");
    
        while(1){
    
    		/* 判断是否掉线 */
    		getsockopt(fd, IPPROTO_TCP, TCP_INFO, &info, (socklen_t *)&len); 
    		if((info.tcpi_state==TCP_ESTABLISHED));
    		else 
    		{ 
    			printf("socket Reconnecting....\n"); 
    			close(fd);
    			sleep(1);
    			goto reconnect;
    		} 
    
    		Client_Working(fd ,msg);
        }
    
    	free(msg);
        return 0;
    }
    
    
    /***************************************************
    * 系统初始化
    ***************************************************/
    static void SystemInit(int *fd , struct sockaddr_in *sin , char **argv)
    {
    
    	/* 创建socket */	
    	if ((*fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
    		perror ("Error:socket");
    		exit (1);
    	}
    	
    	bzero(sin, sizeof(*sin));
    	
    	sin->sin_family = AF_INET;
    	sin->sin_port = htons(atoi(argv[2]));
    	
    	if (inet_pton (AF_INET, argv[1], (void *)&sin->sin_addr) != 1) {
    		perror ("Error:inet_pton");
    		close(*fd);
    		exit (1);
    	}	
    
    }

    展开全文
  • 关于tcp断线重连的问题

    千次阅读 2020-02-06 11:55:31
    在工控上经常用到tcp连接,比如串口服务器或某些支持...搜索了个C++ 的tcp断线重连的案例(http://www.cnblogs.com/kingdom_0/articles/2571727.html),使用这个的原因还因其使用的是收发多线程。server和clie...
  • SocketClient MFC 代码,实现与tcp sever的链接,实现自动断线重连
  • 实现netty作为服务端,websocket连接成功,将channel保存到map集合,通过js发送心跳,服务端接收心跳信息并响应给客户端,当服务端断开时 客户端进行重连操作
  • android java socket断线重连thread = new Thread(new Runnable(){@Overridepublic void run(){while (true){boolean close = isServerClose(socket);//判断是否断开if(close){//没有断开,开始读数据;try{Log.d(TAG...
  • c#socket异步及断线重连

    热门讨论 2016-01-01 23:41:27
    c#socket异步编程及断线重连。并怎样实现循环接受服务器的命令并处理。
  • Netty断线重连解决方案.docx
  • Android Socket连接,包含心跳检测,断线重连,数据发送等等 博客地址:http://blog.csdn.net/yuzhiqiang_1993/article/details/78094909
  • 实现SOCKET TCP断开连接后,重新连接 比如TCP通信过程中,网断了或者拨了网线,如何在代码中自动重新连接TCP服务器.这是常见需求

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 28,555
精华内容 11,422
关键字:

断线重连