国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

WebSocket 實(shí)現(xiàn)長(zhǎng)連接及通過WebSocket獲取客戶端IP

這篇具有很好參考價(jià)值的文章主要介紹了WebSocket 實(shí)現(xiàn)長(zhǎng)連接及通過WebSocket獲取客戶端IP。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

WebSocket 實(shí)現(xiàn)長(zhǎng)連接及通過WebSocket獲取客戶端IP

WebSocket 是一種支持雙向通訊的網(wǎng)絡(luò)通信協(xié)議。

實(shí)現(xiàn)過程:

1 添加ServerEndpointExporter配置bean

@Configuration
public class WebSocketConfig {

    // 自動(dòng)注冊(cè)使用了@ServerEndpoint**注解聲明的Websocket endpoint
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

2 實(shí)現(xiàn)過程

需求是通過WebSocket,建立長(zhǎng)連接,并獲取當(dāng)前在線的人數(shù)。通過Websocket 不斷發(fā)送消息,建立長(zhǎng)連接,給Session續(xù)命。我是通過MAC地址,區(qū)分不同的設(shè)備,因?yàn)槲业男枨笾行枰粋€(gè)賬號(hào)能夠登錄多臺(tái)機(jī)器。所以我通過MAC地址用于標(biāo)識(shí)不同的設(shè)備信息。(若是一個(gè)賬號(hào)只能登陸一次,采用用戶ID)

1 . 添加配置

@ServerEndpoint(value = "/websocket/onlineAme/{Mac}")

2. 主要方法

  • @OnOpen

    • 首次建立連接時(shí),運(yùn)行該注解下的方法。
    • 在此方法中可以獲取websocket的session
    • 并將該用戶的Mac 以及 Session存放到
    private static ConcurrentHashMap<String, Session> sessionMap = new ConcurrentHashMap<>();
    
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "Mac") String mac) throws IOException {
        log.info("【Ame websocket 鏈接成功】,Ame mac:"+ mac);
        session.setMaxIdleTimeout(sessionTimeout);
        // 獲取客戶端的Ip
        if(StringUtils.isBlank(mac)||ObjectUtil.isNull(mac)){
            log.error("并未上傳設(shè)備信息");
        }
        setMap(session,mac);
    }
    
    private void setMap(Session session,String mac){
        sessionMap.put(mac,session);
        log.warn("Ame MAC address:{},當(dāng)前在線人數(shù)為:{}",mac,sessionMap.size());
    }
    
  • @OnMessage

    • 該方法是客戶端與服務(wù)端進(jìn)行通訊。

    • 每次客戶端與服務(wù)端建立通訊時(shí),會(huì)給Session續(xù)命,延長(zhǎng)Session的時(shí)常

      @OnMessage
      public void onMessage(Session session, String msg)  {
              session.setMaxIdleTimeout(sessionTimeout);
              if(StringUtils.isBlank(msg)){
                  return;
              }
              // 判斷 MAC 地址 是否 是正在上線
              String mac = getMACBySession(session);
              if(StringUtils.isBlank(mac)){
                  return;
              }
              // 將上傳的msg轉(zhuǎn)化為 AmeServicePack
      		handleAmeMsg(mac,ame);
      }
      private String getMACBySession(Session session){
          String mac = getUserIdBySession(session);
          if(ObjectUtil.isNull(mac)){
              return null;
          }
          return mac;
      }
      private String getUserIdBySession(Session session){
          for (String mac : sessionMap.keySet()) {
              /*session 本身是有一個(gè)id的,通過userid 找到Session 然后再通過 其對(duì)應(yīng) id,與 傳入的Session 中的 session對(duì)比  */
              if(sessionMap.get(mac).getId().equals(session.getId())){
                  return mac;
              }
          }
          return null;
      }
      
  • @OnClose

    @OnClose
    public void onClose(Session session,@PathParam(value = "Mac") String mac) {
        removeMap(session);
        log.info("【websocket退出成功】該設(shè)備退出:"+mac);
    }
    
    private void removeMap(Session session){
        String mac = getUserIdBySession(session);
        if(ObjectUtil.isNull(mac)){
            return;
        }
        sessionMap.remove(mac);
        //userMap.remove(userId);
        removeAme(mac);
    }
    
    private void removeAme(String mac){
        ameHashMap.remove(mac);
        sendInfo("Ame:"+ameInfo.getAmeip()+"下線成功",mac);
    }
    
  • @OnError

    @OnError
    public void onError(Session session,Throwable throwable) {
        log.error("websocket: 發(fā)生了錯(cuò)誤");
        removeMap(session);
        throwable.printStackTrace();
    }
    
  • 向某一個(gè)用戶發(fā)送消息

     /*
       發(fā)送自定義消息
         向某一個(gè)用戶發(fā)送,消息*/
    public static void sendInfo(String message,String toMac){
        log.info("發(fā)送消息:{},內(nèi)容是:{}",message,toMac);
        if(ObjectUtil.isNull(toMac) || StringUtils.isBlank(message)){
            log.error("消息不完整");
            return;
        }
        // 包含就發(fā)送
        //System.out.println(sessionMap.containsKey(toUserId));
        if(sessionMap.containsKey(toMac)){
            try {
                sendMessage(sessionMap.get(toMac),message);
            }catch (Exception e){
                log.error("發(fā)送給用戶{}的消息出錯(cuò)",toMac);
            }
        }
        // 用戶不在線
        else {
            log.error("設(shè)備{}不在線",toMac);
        }
    
    }
    
    public static void sendMessage(Session session,String message) throws IOException {
        session.getBasicRemote().sendText(message);
    }
    

3 通過WebSocket獲取 請(qǐng)求Ip地址

Websocket 中的request中并沒有header 中并沒有客戶端的Ip地址,但是在SpringCloud中,是通過網(wǎng)關(guān),路由轉(zhuǎn)發(fā)。在網(wǎng)關(guān)中的請(qǐng)求的request中存在Ip地址,可以通過攔截器,獲取網(wǎng)關(guān)的ip然后將request放到websocket的request中。文章來源地址http://www.zghlxwxcb.cn/news/detail-700094.html

3.1 攔截器
package com.mam.gateway.filter;

import jdk.nashorn.internal.runtime.regexp.joni.Config;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.net.InetSocketAddress;
import java.util.Objects;

/**
 * 獲取 WebSocket 上傳Session的 Ip信息
 */
@Component
public class SessionFilter extends AbstractGatewayFilterFactory<SessionFilter.Config> {
    public SessionFilter()
    {
        super(SessionFilter.Config.class);
    }

    @Override
    public String name()
    {
        return "SessionFilter";
    }

    @Override
    public GatewayFilter apply(SessionFilter.Config config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                ServerWebExchange mutatedServerWebExchange = exchange.mutate().request(exchange.getRequest()).build();
                return chain.filter(mutatedServerWebExchange);
            }
        };
    }
    static class Config
    {
        private Integer order;
        public Integer getOrder()
        {
            return order;
        }
        public void setOrder(Integer order)
        {
            this.order = order;
        }
    }
}

3.2 ServerEndpointConfig 的配置
public class WebSocketConfigurator extends ServerEndpointConfig.Configurator{
    private static final Logger log = LoggerFactory.getLogger(WebSocketConfigurator.class);

    @Override
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
        Map<String, Object> attributes = sec.getUserProperties();
        try{
            String clientIp = IpUtils.getIpAddrByHandshakeRequest(request.getHeaders());
            attributes.put("clientIp",clientIp);
            log.info("websocker攔截器X-Real_IP{}header{}",request.getHeaders().get("X-Real_IP"),request.getHeaders().toString());
        }catch (Exception e){
            e.printStackTrace();
        }
        super.modifyHandshake(sec,request,response);
    }
}
public static String getIpAddrByHandshakeRequest(Map<String, List<String>> map)
{
    if (map == null)
    {
        return null;
    }

    String ip = null;

    // X-Forwarded-For:Squid 服務(wù)代理
    String ipAddresses = Convert.toStr(map.get("X-Forwarded-For"));
    if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses))
    {
        // Proxy-Client-IP:apache 服務(wù)代理
        ipAddresses = Convert.toStr(map.get("Proxy-Client-IP"));
    }else {
        ipAddresses = ipAddresses.substring(1,ipAddresses.length()-1);
    }
    if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses))
    {
        // WL-Proxy-Client-IP:weblogic 服務(wù)代理
        ipAddresses = Convert.toStr(map.get("WL-Proxy-Client-IP"));
    }
    if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses))
    {
        // HTTP_CLIENT_IP:有些代理服務(wù)器
        ipAddresses = Convert.toStr(map.get("HTTP_CLIENT_IP"));
    }
    if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses))
    {
        // X-Real-IP:nginx服務(wù)代理
        ipAddresses = Convert.toStr(map.get("X-Real-IP"));
    }

    // 有些網(wǎng)絡(luò)通過多層代理,那么獲取到的ip就會(huì)有多個(gè),一般都是通過逗號(hào)(,)分割開來,并且第一個(gè)ip為客戶端的真實(shí)IP
    if (ipAddresses != null && ipAddresses.length() != 0)
    {
        ip = ipAddresses.split(",")[0];
    }
    return ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
}

3.3 WebSocket 獲取Ip
AmeServicePack ame = JSONObject.toJavaObject(JSONObject.parseObject(msg), AmeServicePack.class);
Map<String, Object> userProperties = session.getUserProperties();
String clientip = (String) userProperties.get("clientIp");

4 完整代碼

@Component
@ServerEndpoint(value = "/websocket/onlineAme/{Mac}",configurator = WebSocketConfigurator.class)
public class AmeLoginWebSocket {

    static Logger log = LoggerFactory.getLogger(AmeLoginWebSocket.class);

    /* 存儲(chǔ)session */
    private static ConcurrentHashMap<String, Session> sessionMap = new ConcurrentHashMap<>();
    /* 存儲(chǔ) 在線 ame服務(wù) 信息*/
    private  ConcurrentHashMap<String,AmeServicePack> ameHashMap = new ConcurrentHashMap<>();
    /* 存儲(chǔ) Ip  */

    private static final long sessionTimeout = 600000;


    /** 鏈接成功后發(fā)送消息**/
    @OnMessage
    public void onMessage(Session session, String msg)  {
        session.setMaxIdleTimeout(sessionTimeout);
        log.info("【websocket 接收成功】?jī)?nèi)容為"+msg);
        if(StringUtils.isBlank(msg)){
            return;
        }
        // 判斷 MAC 地址 是否 是正在上線
        String mac = getMACBySession(session);
        if(StringUtils.isBlank(mac)){
            return;
        }
        AmeServicePack ame = JSONObject.toJavaObject(JSONObject.parseObject(msg), AmeServicePack.class);
        Map<String, Object> userProperties = session.getUserProperties();
        String clientip = (String) userProperties.get("clientIp");
        // 將上傳的msg轉(zhuǎn)化為 AmeServicePack
        handleAmeMsg(mac,ame);
        
    }

    private void handleAmeMsg(String mac, AmeServicePack ameInfo) {

        log.info("Ame:MAC{}Ip{}:",mac,ameInfo.getAmeip());
        if(ameHashMap.containsKey(mac)){
            log.info("該設(shè)備{}Ip{}已上線",mac,ameInfo.getAmeip());
            sendInfo("該用戶Ip"+ameInfo.getAmeip()+"已存在",mac);
        }else {
            ameHashMap.put(mac,ameInfo);
        }
    }

    private boolean updateOnline(AmeServicePack ameInfo){
        AjaxResult isonline = SpringUtils.getBean(IAmePackService.class).update(ameInfo,SecurityConstants.INNER);
        if((Integer)isonline.get("code")== 200){
            return true;
        }else {
            return false;
        }
    }

    /**
     * ameIp 為上線 但 任務(wù)表中仍有 正在運(yùn)行的任務(wù),并將其修改為 -2
     * @param ameIp
     */
    private void updateErrorTaskStatus(String ameIp){
        SpringUtils.getBean(IAmePackService.class).updateErrorAMEStatus(ameIp,SecurityConstants.INNER);
    }



    private void handlePCMsg(LoginUser loginUser, String msg) {
        log.info("系統(tǒng)用戶:{},消息{}:",loginUser.getUsername(),msg);
    }
    private String getMACBySession(Session session){
        String mac = getUserIdBySession(session);
        if(ObjectUtil.isNull(mac)){
            return null;
        }
        return mac;
    }
    /*
     *成功建立連接后調(diào)用
     * @param [session, username]
     * @return void
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "Mac") String mac) throws IOException {
        log.info("【Ame websocket 鏈接成功】,Ame mac:"+ mac);
        session.setMaxIdleTimeout(sessionTimeout);
        // 獲取客戶端的Ip


        if(StringUtils.isBlank(mac)||ObjectUtil.isNull(mac)){
            log.error("并未上傳設(shè)備信息");
        }
        setMap(session,mac);
    }
    private void setMap(Session session,String mac){
        sessionMap.put(mac,session);
        log.warn("Ame MAC address:{},當(dāng)前在線人數(shù)為:{}",mac,sessionMap.size());
    }


    /*
     *關(guān)閉連接時(shí)調(diào)用
     * @param [userId]
     * @return void
     */
    @OnClose
    public void onClose(Session session,@PathParam(value = "Mac") String mac) {
        removeMap(session);
        log.info("【websocket退出成功】該設(shè)備退出:"+mac);
    }

    private void removeMap(Session session){
        String mac = getUserIdBySession(session);
        if(ObjectUtil.isNull(mac)){
            return;
        }
        sessionMap.remove(mac);
        //userMap.remove(userId);
        removeAme(mac);
    }
    private String getUserIdBySession(Session session){
        for (String mac : sessionMap.keySet()) {
            /*session 本身是有一個(gè)id的,通過userid 找到Session 然后再通過 其對(duì)應(yīng) id,與 傳入的Session 中的 session對(duì)比  */
            if(sessionMap.get(mac).getId().equals(session.getId())){
                return mac;
            }
        }
        return null;
    }
    private void removeAme(String mac){
        ameHashMap.remove(mac);
        log.info("{}:下線成功",ameInfo.getAmeip());
        sendInfo("Ame:"+ameInfo.getAmeip()+"下線成功",mac);
    }
    /*
     *發(fā)生錯(cuò)誤時(shí)調(diào)用
     * @param [session, throwable]
     * @return void
     */
    @OnError
    public void onError(Session session,Throwable throwable) {
        log.error("websocket: 發(fā)生了錯(cuò)誤");
        removeMap(session);
        throwable.printStackTrace();
    }

    /*
     發(fā)送自定義消息
     向某一個(gè)用戶發(fā)送,消息
    */
    public static void sendInfo(String message,String toMac){
        log.info("發(fā)送消息:{},內(nèi)容是:{}",message,toMac);
        if(ObjectUtil.isNull(toMac) || StringUtils.isBlank(message)){
            log.error("消息不完整");
            return;
        }
        // 包含就發(fā)送
        //System.out.println(sessionMap.containsKey(toUserId));
        if(sessionMap.containsKey(toMac)){
            try {
                sendMessage(sessionMap.get(toMac),message);
            }catch (Exception e){
                log.error("發(fā)送給用戶{}的消息出錯(cuò)",toMac);
            }
        }
        // 用戶不在線
        else {
            log.error("設(shè)備{}不在線",toMac);
        }

    }

    public static void sendMessage(Session session,String message) throws IOException {
        session.getBasicRemote().sendText(message);
    }
}

到了這里,關(guān)于WebSocket 實(shí)現(xiàn)長(zhǎng)連接及通過WebSocket獲取客戶端IP的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【go】gorilla/websocket如何判斷客戶端強(qiáng)制斷開連接

    當(dāng)客戶端因?yàn)槟承﹩栴}異常關(guān)閉連接時(shí),可以判斷關(guān)閉連接的異常類型 通過調(diào)用websocket.IsCloseError或websocket.IsUnexpectedCloseError即可 其中g(shù)ithub源碼如下 異常類型如下

    2024年02月16日
    瀏覽(56)
  • Springboot 集成WebSocket作為客戶端,含重連接功能,開箱即用

    使用演示 只需要init后調(diào)用sendMessage方法即可,做到開箱即用。內(nèi)部封裝了失敗重連接、斷線重連接等功能。 基于Springboot工程 引入websocket依賴 開箱即用的工具類

    2024年02月04日
    瀏覽(36)
  • Java 構(gòu)建websocket客戶端,構(gòu)建wss客戶端,使用wss連接,并發(fā)送數(shù)據(jù)到服務(wù)器端,接收服務(wù)器端消息

    Java 構(gòu)建websocket客戶端,構(gòu)建wss客戶端,使用wss連接,并發(fā)送數(shù)據(jù)到服務(wù)器端,接收服務(wù)器端消息 回調(diào)函數(shù)處理

    2024年02月13日
    瀏覽(33)
  • 通過Milo實(shí)現(xiàn)的OPC UA客戶端連接并訂閱Prosys OPC UA Simulation Server模擬服務(wù)器

    通過Milo實(shí)現(xiàn)的OPC UA客戶端連接并訂閱Prosys OPC UA Simulation Server模擬服務(wù)器

    前面我們搭建了一個(gè)本地的 PLC 仿真環(huán)境,并通過 KEPServerEX6 讀取 PLC 上的數(shù)據(jù),最后還使用 UAExpert 作為 OPC 客戶端完成從 KEPServerEX6 這個(gè)OPC服務(wù)器的數(shù)據(jù)讀取與訂閱功能:SpringBoot集成Milo庫實(shí)現(xiàn)OPC UA客戶端:連接、遍歷節(jié)點(diǎn)、讀取、寫入、訂閱與批量訂閱。 注意,如果實(shí)際工

    2024年02月16日
    瀏覽(26)
  • Java編程技巧:獲取ip地址、通過ip獲取地理位置、獲取客戶端操作系統(tǒng)、獲取客戶端瀏覽器、獲取主機(jī)名、獲取操作系統(tǒng)、獲取系統(tǒng)架構(gòu)

    說明: 大家直接去對(duì)應(yīng)項(xiàng)目位置找到代碼,然后看著復(fù)制就行了 1.1、若依(自己寫的代碼) 項(xiàng)目:https://gitee.com/y_project/RuoYi 子模塊:ruoyi-common 所在類:com.ruoyi.common.utils.IpUtils 所在方法:getIpAddr 詳細(xì)位置:整個(gè)方法 1.2、Snowy(借助hutool工具包) 項(xiàng)目:https://gitee.com/xiaonuo

    2024年02月04日
    瀏覽(236)
  • websocket客戶端實(shí)現(xiàn)(java)

    其中,headers 參數(shù)是一個(gè)鍵值對(duì),表示需要設(shè)置的請(qǐng)求頭。在構(gòu)造函數(shù)中,我們首先創(chuàng)建了一個(gè) ClientEndpointConfig.Configurator 對(duì)象,重寫了其中的 beforeRequest() 方法,用于在請(qǐng)求之前設(shè)置請(qǐng)求頭。然后,我們使用 ClientEndpointConfig.Builder.create() 方法創(chuàng)建一個(gè) ClientEndpointConfig 對(duì)象,并

    2024年02月15日
    瀏覽(26)
  • Java實(shí)現(xiàn)websocket客戶端

    常規(guī)情況下,大多數(shù)時(shí)候Java后臺(tái)作為websocket服務(wù)端,實(shí)現(xiàn)方式也比較簡(jiǎn)單,網(wǎng)上很多案例代碼。但是很多時(shí)候項(xiàng)目中服務(wù)與服務(wù)之間也需要使用websocket通信,此時(shí)項(xiàng)目就需要實(shí)現(xiàn)客戶端功能。 步驟一:導(dǎo)入依賴: 步驟二:實(shí)現(xiàn)WebSocketClient抽象類: 該類中和websocket服務(wù)端接口

    2024年02月16日
    瀏覽(86)
  • 通過 EPOLL 解決客戶端同時(shí)連接多服務(wù)器的問題

    項(xiàng)目需求是? 程序上 同時(shí)配置了多個(gè)服務(wù)端 設(shè)備 每隔一段時(shí)間需要 比如1分鐘 連一下服務(wù)器看下是否連通?? 并將結(jié)果上報(bào)給平臺(tái)? 原來是用線程池來做的?? 具體大概就是 定時(shí)器到了之后? 遍歷設(shè)備列表? 找到設(shè)備之后? 通過 socket連接 發(fā)送一個(gè)指令 等待服務(wù)器返回 用來

    2024年02月13日
    瀏覽(21)
  • SpringBoot+WebSocket實(shí)現(xiàn)服務(wù)端、客戶端

    SpringBoot+WebSocket實(shí)現(xiàn)服務(wù)端、客戶端

    小編最近一直在使用springboot框架開發(fā)項(xiàng)目,畢竟現(xiàn)在很多公司都在采用此框架,之后小編也會(huì)陸續(xù)寫關(guān)于springboot開發(fā)常用功能的文章。 什么場(chǎng)景下會(huì)要使用到websocket的呢? websocket主要功能就是實(shí)現(xiàn)網(wǎng)絡(luò)通訊,比如說最經(jīng)典的客服聊天窗口、您有新的消息通知,或者是項(xiàng)目與

    2024年02月13日
    瀏覽(25)
  • JAVA使用WebSocket實(shí)現(xiàn)多客戶端請(qǐng)求

    工作前提:兩個(gè)服務(wù)之間實(shí)現(xiàn)聊天通訊,因?yàn)榻橛趦蓚€(gè)服務(wù),兩個(gè)客戶端 方案1:多個(gè)服務(wù)端,多個(gè)客戶端,使用redis把用戶數(shù)據(jù)ip進(jìn)行存儲(chǔ),交互拿到redis數(shù)據(jù)進(jìn)行推送 方案2: 一個(gè)服務(wù)端,多個(gè)客戶端,拿到客戶端的id和需要推送的id進(jìn)行拼接存儲(chǔ) 此文章使用的是方案2 1. 引

    2024年02月11日
    瀏覽(17)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包