Java Socket长连接示例代码

SocketListenerPusher.java代码如下: 

Java代码  

  1. import java.io.IOException;  
  2. import java.net.InetSocketAddress;  
  3. import java.net.ServerSocket;  
  4. import java.net.Socket;  
  5. import java.util.concurrent.ExecutorService;  
  6. import java.util.concurrent.Executors;  
  7. import java.util.concurrent.ScheduledThreadPoolExecutor;  
  8. import java.util.concurrent.TimeUnit;  
  9.   
  10. import org.apache.commons.configuration.ConfigurationException;  
  11. import org.directwebremoting.impl.DaemonThreadFactory;  
  12. import org.slf4j.Logger;  
  13. import org.slf4j.LoggerFactory;  
  14.   
  15. import com.shihuan.dragonkeeper.common.utils.PropertiesUtil;  
  16. import com.shihuan.dragonkeeper.global.ConfigFile;  
  17.   
  18. public class SocketListenerPusher implements Runnable {  
  19.   
  20.     protected static Logger logger = LoggerFactory.getLogger(SocketListenerPusher.class);  
  21.       
  22.     public static String socketlistenerserver_CONFIG = ConfigFile.SOCKETLISTENERSERVER__CONFIG + ConfigFile.SUFFIX_NAME;  
  23.       
  24.     private ServerSocket serverSocket;  
  25.     private ExecutorService pool;  
  26.       
  27.       
  28.     public SocketListenerPusher() {  
  29.         int port = 0;  
  30.         int poolsize = 0;  
  31.           
  32.         try {  
  33.             port = Integer.parseInt(PropertiesUtil.getPropertiesValue(socketlistenerserver_CONFIG, “serverport”));  
  34.             poolsize = Integer.parseInt(PropertiesUtil.getPropertiesValue(socketlistenerserver_CONFIG, “poolsize”));  
  35.               
  36.             serverSocket = new ServerSocket();  
  37.             serverSocket.setReuseAddress(true);  
  38.             serverSocket.bind(new InetSocketAddress(port));  
  39.             pool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * poolsize);  
  40.               
  41.             //下面两句循环执行run()方法, 相当于while(true){…}  
  42.             ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1, new DaemonThreadFactory());  
  43.             executor.scheduleAtFixedRate(this, 1L, 1L, TimeUnit.MILLISECONDS);  
  44.               
  45.         } catch (NumberFormatException e) {  
  46.             logger.error(e.getMessage(), e);  
  47.             e.printStackTrace();  
  48.         } catch (ConfigurationException e) {  
  49.             logger.error(e.getMessage(), e);  
  50.             e.printStackTrace();  
  51.         } catch (IOException e) {  
  52.             logger.error(e.getMessage(), e);  
  53.             e.printStackTrace();  
  54.         }  
  55.   
  56.     }  
  57.       
  58.     public void run() {  
  59.         Socket socket = null;  
  60.         try {  
  61.             socket = serverSocket.accept();  
  62.             pool.execute(new SocketListenerHandler(socket));  
  63.         } catch (IOException e) {  
  64.             System.out.println(“线程池被关闭!!!!!!!!!!!”);  
  65.             pool.shutdown();  
  66.             logger.error(e.getMessage(), e);  
  67.             e.printStackTrace();  
  68.         }  
  69.           
  70.     }  

SocketListenerHandler.java代码如下: 

Java代码  

  1. import java.io.BufferedInputStream;  
  2. import java.io.BufferedReader;  
  3. import java.io.IOException;  
  4. import java.io.InputStreamReader;  
  5. import java.io.ObjectInputStream;  
  6. import java.net.Socket;  
  7. import java.sql.Connection;  
  8. import java.sql.SQLException;  
  9.   
  10. import org.apache.commons.configuration.ConfigurationException;  
  11. import org.apache.commons.dbutils.DbUtils;  
  12. import org.apache.commons.dbutils.QueryRunner;  
  13. import org.apache.commons.io.IOUtils;  
  14. import org.directwebremoting.Browser;  
  15. import org.directwebremoting.ScriptSessions;  
  16. import org.slf4j.Logger;  
  17. import org.slf4j.LoggerFactory;  
  18.   
  19. import com.alibaba.fastjson.JSON;  
  20. import com.shihuan.dragonkeeper.common.dto.DataSourceInfo;  
  21. import com.shihuan.dragonkeeper.common.utils.ByteArrayUtil;  
  22. import com.shihuan.dragonkeeper.common.utils.DataSourceMapUtil;  
  23. import com.shihuan.dragonkeeper.common.utils.DateFormatterUtil;  
  24. import com.shihuan.dragonkeeper.common.utils.PropertiesUtil;  
  25. import com.shihuan.dragonkeeper.global.ConfigFile;  
  26. import com.shihuan.dragonkeeper.server.bean.ActivityServiceBean;  
  27.   
  28. public class SocketListenerHandler implements Runnable {  
  29.   
  30.     protected static Logger logger = LoggerFactory.getLogger(SocketListenerHandler.class);  
  31.       
  32.     private static String jdbc_CONFIG = ConfigFile.JDBC_CONFIG + ConfigFile.SUFFIX_NAME;  
  33.       
  34.     public static final int timeOut = 0*1000 ;  //设置读取操作异常为1秒  
  35.     private final String dataRealTimeAction_id = “Agentdata_” + Math.random();  
  36.       
  37.     private static final String noData = “{‘nodata’:’心跳信息’}”;  
  38.     private static final String errorData = “{‘error’:’无法解析的请求’}”;  
  39.       
  40.       
  41.     private Socket connectedsocket = null;  
  42.       
  43.     public SocketListenerHandler(Socket socket){  
  44.         this.connectedsocket = socket;  
  45.     }  
  46.   
  47. @Override  
  48.     public void run() {  
  49.         BufferedReader in = null;  
  50. String resultData = “”;  
  51.           
  52.         try {  
  53.             connectedsocket.setSoTimeout(timeOut);  //表示接收数据时的等待超时数据, 此方法必须在接收数据之前执行才有效. 此外, 当输入流的 read()方法抛出 SocketTimeoutException后, Socket仍然是连接的, 可以尝试再次读数据, 单位为毫秒, 它的默认值为 0(表示会无限等待, 永远不会超时)  
  54.             connectedsocket.setKeepAlive(false);   //表示对于长时间处于空闲状态的Socket, 是否要自动把它关闭.  
  55.               
  56.             in = new BufferedReader(new InputStreamReader(connectedsocket.getInputStream()));  
  57. if (in.ready()) {  //判断流中是否有数据  
  58.                   
  59.                 resultData = getNoHeadData(in.readLine());   //从Agent端接收到的数据  
  60.                 logger.info(“#### 结果DATA = “+resultData);  
  61.                   
  62.                 if (resultData==null || “”.equals(resultData)) {  
  63.                     logger.info(dataRealTimeAction_id + ” –>>> ” + “内容为空!”);  
  64.                 } else if (resultData.charAt(0) != ‘{‘) {  //要在客户端定时维持心跳信息  
  65.                     logger.info(dataRealTimeAction_id + ” –>>> ” + noData);  
  66.                 } else {  
  67.                     ActivityServiceBean asb = JSON.parseObject(resultData, ActivityServiceBean.class);  
  68.                     System.out.println(“打印预处理信息Start……”);  
  69.                     System.out.println(asb.getProxyname() + ” — ” + asb.getIp() + ” — ” + asb.getCalltime() + ” — ” + asb.getAnswertime() + ” — ” + asb.getCpu() + ” — ” + asb.getThread() + ” — ” + asb.getStatus() + ” — ” + asb.getAccessaddress() + ” — ” + asb.getAccessfilename() + ” — ” + asb.getSql() + ” — ” + asb.getContent());  
  70.                     System.out.println(“打印预处理信息End……”);  
  71. //                  parseData(ois);  
  72.                       
  73.                     logger.info(dataRealTimeAction_id + “: 成功处理了接收到的数据!”);  
  74.                 }  
  75.                   
  76.             }  
  77. catch (IOException e) {  
  78.             logger.error(e.getMessage() + ” ” + errorData, e);  
  79.             e.printStackTrace();  
  80.         } catch (NumberFormatException e) {  
  81.             logger.error(e.getMessage(), e);  
  82.             e.printStackTrace();  
  83.         } finally {  
  84.               
  85.             if (in != null) {  
  86.                 try {  
  87.                     in.close();  
  88.                 } catch (IOException e) {  
  89.                     logger.error(e.getMessage(), e);  
  90.                     e.printStackTrace();  
  91.                 }  
  92.             }  
  93. }  
  94.           
  95.     }  

TestSocketListenerPusher.java请求端代码如下: 

Java代码  

  1. import java.io.BufferedOutputStream;  
  2. import java.io.IOException;  
  3. import java.io.OutputStream;  
  4. import java.net.Socket;  
  5. import java.net.UnknownHostException;  
  6. import java.util.Date;  
  7.   
  8. import org.apache.commons.configuration.ConfigurationException;  
  9.   
  10. import com.alibaba.fastjson.JSON;  
  11. import com.shihuan.dragonkeeper.common.utils.ByteArrayUtil;  
  12. import com.shihuan.dragonkeeper.common.utils.PropertiesUtil;  
  13. import com.shihuan.dragonkeeper.global.ConfigFile;  
  14. import com.shihuan.dragonkeeper.server.bean.ActivityServiceBean;  
  15.   
  16. public class TestSocketListenerPusher implements Runnable {  
  17.   
  18.     private static String socketlistenerserver_CONFIG = ConfigFile.SOCKETLISTENERSERVER__CONFIG + ConfigFile.SUFFIX_NAME;  
  19.       
  20.     private Socket socketclient = null;  
  21.       
  22.     @Override  
  23.     public void run() {  
  24.           
  25.         String serverip = “”;  
  26.         int port = 0;  
  27.           
  28.         OutputStream os = null;  
  29.           
  30.         try {  
  31.             serverip = PropertiesUtil.getPropertiesValue(socketlistenerserver_CONFIG, “serverip”);  
  32.             port = Integer.parseInt(PropertiesUtil.getPropertiesValue(socketlistenerserver_CONFIG, “serverport”));  
  33.               
  34.               
  35.             ActivityServiceBean asb = null;  
  36.               
  37.             for (int i=0; i<2; i++) {  
  38.                 asb = new ActivityServiceBean();  
  39.                 asb.setProxyname(“testProxyname”+i);  
  40.                 asb.setIp(“testIp”+i);  
  41.                 Date curdate = new Date();  
  42.                 asb.setCalltime(curdate);  
  43.                 asb.setAnswertime(curdate);  
  44.                 asb.setCpu(“testCpu”+i);  
  45.                 asb.setThread(“testThread”+i);  
  46.                 asb.setStatus(“testStatus”+i);  
  47.                 asb.setAccessaddress(“testAccessaddress”+i);  
  48.                 asb.setAccessfilename(“testAccessfilename”+i);  
  49.                 asb.setSql(“testSql”+i);  
  50.                 asb.setContent(“testContent”+i);  
  51.                   
  52.                 String jsonStr = JSON.toJSONString(asb).trim();  
  53.                 byte[] information = (new String(ByteArrayUtil.getIntToByte(jsonStr.length()))+jsonStr).getBytes();  
  54.                   
  55.                 System.out.println(information.length);  
  56.                   
  57.                 socketclient = new Socket(serverip, port);  
  58.                 socketclient.setSoTimeout(0);  
  59.                 socketclient.setKeepAlive(false);  
  60.                   
  61.                 os = new BufferedOutputStream(socketclient.getOutputStream());  
  62.                 os.write(information);  
  63.                 os.flush();  
  64.                   
  65.                 System.out.println(“Client” + i + ” –>>> ” + new String(ByteArrayUtil.getIntToByte(jsonStr.length()))+jsonStr);  
  66.                   
  67.                 os.close();  
  68.                 Thread.sleep(3000);  
  69.             }  
  70.               
  71.               
  72.         } catch (ConfigurationException e) {  
  73.             e.printStackTrace();  
  74.         } catch (UnknownHostException e) {  
  75.             e.printStackTrace();  
  76.         } catch (IOException e) {  
  77.             e.printStackTrace();  
  78.         } catch (InterruptedException e) {  
  79.             e.printStackTrace();  
  80.         } finally {  
  81.             /* 
  82.             try { 
  83.                 if (os != null) { 
  84.                     os.close(); 
  85.                 } 
  86.             } catch (IOException e) { 
  87.                 e.printStackTrace(); 
  88.             } 
  89.             */  
  90.         }  
  91.           
  92.           
  93.     }  
  94.       
  95.     public static void main(String[] args) {  
  96.         Thread t = new Thread(new TestSocketListenerPusher());  
  97.         t.start();  
  98.     }  
  99.   
  100. }  

源代码在笔者shihuan8@163.com邮箱网盘中J2EE代码文件夹里。 

———————————————————————————- 
如果是按byte[]传输数据的情况,请参考如下代码: 

SimpleSocketServer.java代码如下: 

Java代码  

  1. package com.shihuan.socket;  
  2.   
  3. import java.io.BufferedInputStream;  
  4. import java.io.IOException;  
  5. import java.io.InputStream;  
  6. import java.net.InetSocketAddress;  
  7. import java.net.ServerSocket;  
  8. import java.net.Socket;  
  9.   
  10. public class SimpleSocketServer {  
  11.   
  12.     public static void main(String[] args) {  
  13.         try {  
  14.             ServerSocket ss = new ServerSocket();  
  15.             ss.setReuseAddress(true);  //两个进程共用同一个端口的时候,一个进程关闭后,另一个进程还能够立刻重用相同端口  
  16.             ss.setReceiveBufferSize(128*1024);  //缓冲区中允许接收的最大字节数,默认是8192  
  17.             ss.bind(new InetSocketAddress(19990));   
  18.               
  19.             Socket client = ss.accept();  
  20.             InputStream in = new BufferedInputStream(client.getInputStream());  
  21.               
  22.             byte tmpb = (byte)in.read();  
  23.             System.out.println(“第一个字节的byte值 —>> ” + tmpb);  
  24.             System.out.println(“接收字节 —>> ” + in.available());  
  25.             byte[] bc = new byte[in.available()+1];  
  26.             bc[0] = tmpb;  
  27.             in.read(bc, 1, in.available());  
  28.               
  29.             System.out.println(bc.length);  
  30.             System.out.println(new String(bc));  
  31.             in.close();  
  32.         } catch (IOException e) {  
  33.             System.out.println(e.getMessage());  
  34.             e.printStackTrace();  
  35.         }  
  36.   
  37.     }  
  38.   
  39. }  

SimpleSocketClient.java代码如下: 

Java代码  

  1. package com.shihuan.socket;  
  2.   
  3. import java.io.BufferedOutputStream;  
  4. import java.io.IOException;  
  5. import java.io.OutputStream;  
  6. import java.net.Socket;  
  7. import java.net.UnknownHostException;  
  8.   
  9. public class SimpleSocketClient {  
  10.   
  11.     public static void main(String[] args) throws UnknownHostException {  
  12.         try {  
  13.             Socket s = new Socket(“192.168.1.10”, 19990);  
  14.             OutputStream os = new BufferedOutputStream(s.getOutputStream());  
  15.             String info = “abc!”;  
  16.             info = “大家好!”;  
  17.             byte[] bi = info.getBytes();  
  18.             os.write(bi);  
  19.             os.flush();  
  20.             os.close();  
  21.         } catch (IOException e) {  
  22.             System.out.println(e.getMessage());  
  23.             e.printStackTrace();  
  24.         }  
  25.     }  
  26.   
  27. }  

稍微复杂一点儿代码示例,处理了粘包问题: 
StartListenerTcpThread.java代码: 

Java代码  

  1. import java.io.BufferedInputStream;  
  2. import java.io.IOException;  
  3. import java.io.InputStream;  
  4. import java.net.InetSocketAddress;  
  5. import java.net.ServerSocket;  
  6. import java.net.Socket;  
  7. import java.net.SocketAddress;  
  8. import java.util.Vector;  
  9. import java.util.concurrent.ExcutorService;  
  10. import java.util.concurrent.Excutors;  
  11.   
  12. import org.apache.commons.io.IUtils;  
  13. import org.slf4j.Logger;  
  14. import org.slf4j.LoggerFactory;  
  15.   
  16. import com.shihuan.dragonkeeper.common.utils.ByteArrayUtil;  
  17. import com.shihuan.dragonkeeper.global.ConfigFile;  
  18.   
  19. public class StartListenerTcpThread implements Runnable {  
  20.    public static Logger logger = LoggerFactory.getLogger(StartListenerTcpThread.class);  
  21.   
  22.    private static ExcutorService Threadpool = Excutors.newCachedThreadPool();  
  23.    private static boolean businessflag = true;  
  24.    private static final int receiveBufferSize = 128;  
  25.    private static Vector<byte[]> tmpbytes = new Vector<byte[]>();  
  26.    private ServerSocket serverSocket = null;  
  27.   
  28.    public StartListenerTcpThread(String ip, int port){  
  29.       try{  
  30.          serverSocket = new ServerSocket();  
  31.          serverSocket.setReuseAddress(true);  
  32.          serverSocket.setReceiveBufferSize(receiveBufferSize*1024);  
  33.          serverSocket.setSoTimeout(0);  
  34.          SocketAddress sa = new InetSocketAddress(port);  
  35.          serverSocket.bind(sa, 20);  
  36.       }catch(IOException e){  
  37.          logger.error(e.getMessage(), e);  
  38.       }  
  39.    }  
  40.   
  41.    public void run(){  
  42.       Socket socket = null;  
  43.       while(true){  
  44.          if(businessflag){  
  45.             try{  
  46.                socket = serverSocket.accept();  
  47.                System.out.println(“New connection accepted ” + socket.getInetAddress() + “:” + socket.getPort());  
  48.                InputStream socketIn = new BufferedInputStream(socket.getInputStream());  
  49.                byte tmpb = (byte)socketIn.read();  
  50.                byte[] currentbytes = null;  
  51.                if(tmpbytes.size() > 0){  //上一次IO流中有未处理的剩余包  
  52.                   int oldBytesLen = tmpbytes.get(0).length;  
  53.                   int socketBytesLen = socketIn.available()+1;  
  54.                   int currentLength = oldByteLen + socketBytesLen;  
  55.                   currentbytes = new byte[currentLength];  
  56.                   System.arraycopy(tmpbytes.get(0), 0, currentbytes, oldBytesLen);  
  57.                   currentbytes[oldBytesLen] = tmpb;  
  58.                   socketIn.read(currentbytes, oldBytesLen+1, socketBytesLen-1);  
  59.                   socketIn.close();  
  60.                   splitInputStreamByte(currentbytes);  
  61.                }else{  //正常未粘包情况  
  62.                   int socketBytesLen = socketIn.available()+1;  
  63.                   currentbytes = new byte[socketBytesLen];  
  64.                   currentbytes[0] = tmpb;  
  65.                   socketIn.read(currentbytes, 1, socketBytesLen-1);  
  66.                   socketIn.close();  
  67.                   splitInputStreamByte(currentbytes);  
  68.                }  
  69.             }catch(IOException e){  
  70.                logger.error(e.getMessage(), e);  
  71.             }  
  72.          }  
  73.       }  
  74.    }  
  75.   
  76.    /** 
  77.     * 拆分byte数组并分多线程处理 
  78.     * @param parambytes 原byte数组 
  79.     * @return 处理后剩余部分的byte数组 
  80.    */  
  81.    private static void splitInputStreamByte(byte[] parambytes) {  
  82.       if(parambytes != null){  
  83.          if(parambytes.length > 4){  
  84.             byte[] head = new byte[4];  //单包长度  
  85.             System.arraycopy(parambytes, 0, head, 0, 4);  
  86.             int bodyLength = ByteArrayUtil.getint(head);  
  87.             if(bodyLength <= parambytes.length-4){  
  88.                final byte[] body = new byte[bodyLength];  
  89.                System.arraycopy(parambytes, 4, body, 0, bodyLength);  
  90.                ThreadPool.execute(new Runnable(){  
  91.                   public void run(){  
  92.                      byte[] processDatas = body;  
  93.                      try{  
  94.                         System.out.println(IOUtils.toString(processDatas, “UTF-8”).trim());  
  95.                      }catch(IOException e){  
  96.                         logger.error(e.getMessage(), e);  
  97.                      }  
  98.                   }  
  99.                });  
  100.   
  101.                int resultLen = parambytes.length-4-bodyLength;  
  102.                if(resultLen == 0){  
  103.                   splitInputStreamByte(null);  
  104.                }else{  
  105.                   byte[] resultbytes = new byte[resultLen];  
  106.                   System.arraycopy(parambytes, 4+bodyLength, resultbytes, 0, resultLen);  
  107.                   splitInputStreamByte(resultbytes);  
  108.                }  
  109.             }else{  
  110.                tmpbytes.clear();  
  111.                tmpbytes.add(parambytes);  
  112.             }  
  113.          }else{  
  114.             tmpbytes.clear();  
  115.             tmpbytes.add(parambytes);  
  116.          }  
  117.       }  
  118.    }  
  119.   
  120.    public static void openflag(){  
  121.       businessflag = true;  
  122.    }  
  123.   
  124.    public static void closeflag(){  
  125.       businessflag = false;  
  126.    }  
  127.   
  128. }  

TestTcpSocket.java代码: 

Java代码  

  1. import java.io.IOException;  
  2. import java.io.OutputStream;  
  3. import java.net.Socket;  
  4. import java.net.UnknownHostException;  
  5.   
  6. import com.shihuan.dragonkeeper.common.utils.ByteArrayUtil;  
  7. import com.shihuan.dragonkeeper.global.ConfigFile;  
  8.   
  9. public class TestTcpSocket implements Runnable{  
  10.    private Socket socketClient = null;  
  11.   
  12.    public void run(){  
  13.       String serverip = “192.168.1.10”;  
  14.       int port = 19990;  
  15.       try{  
  16.          while(true){  
  17.            System.out.println(“SocketClient start……”);  
  18.            String mystr = “hello everyone!”;  
  19.            socketClient = new Socket(serverip, port);  
  20.            OutputStream os = socketClient.getOutputStream();  
  21.            byte[] head = ByteArrayUtil.int2byte(mystr.length());  
  22.            byte[] body = mystr.getBytes();  
  23.            byte[] total = ByteArrayUtil.byteMerge(head, body);  
  24.   
  25.            os.write(total);  
  26.            os.flush();  
  27.            os.close();  
  28.   
  29.            Thread.sleep(1000);  
  30.   
  31.            System.out.println(“SocketClient end……”);  
  32.          }  
  33.       }catch(Exception e){  
  34.          logger.error(e.getMessage(), e);  
  35.       }  
  36.    }  
  37.   
  38.    public static void main(String[] args){  
  39.       Thread t = new Thread(new TestTcpSocket());  
  40.       t.start();  
  41.    }  
  42. }   

下面写ByteArrayUtil.java代码: 

Java代码  

  1. package com.shihuan.dragonkeeper.common.utils;  
  2.   
  3. public class ByteArrayUtil {  
  4.   
  5.    /** 
  6.     * 将int型的数据类型转换成byte[]类型 
  7.    */  
  8.    public static final byte[] int2byte(int paramInt){  
  9.       byte[] resultByte = new byte[4];  
  10.       resultByte[3] = ((byte)(paramInt & 0xFF));  
  11.       resultByte[2] = ((byte)(paramInt >>> 8 & 0xFF));  
  12.       resultByte[1] = ((byte)(paramInt >>> 16 & 0xFF));  
  13.       resultByte[0] = ((byte)(paramInt >>> 24 & 0xFF));  
  14.   
  15.       return resultByte;  
  16.    }  
  17.   
  18.    /** 
  19.     * 将byte型的数据类型转换成int类型 
  20.    */  
  21.    public static final int getint(byte[] paramArrayOfByte){  
  22.       int result = (paramArrayOfByte[0] & 0xFF) << 24 | (paramArrayOfByte[1] & 0xFF) << 16 | (paramArrayOfByte[2] & 0xFF) << 8 | paramArrayOfByte[3] & 0xFF;  
  23.       return result;  
  24.    }  
  25.   
  26.    /** 
  27.     * 合并两个byte数组到一个byte数组中 
  28.    */  
  29.    public static byte[] byteMerge(byte[] byte1, byte[] byte2){  
  30.       byte[] result = new byte[byte1.length+byte2.length];  
  31.       System.arraycopy(byte1, 0, result, 0, byte1.length);  
  32.       System.arraycopy(byte2, 0, result, byte1.length, byte2.length);  
  33.       return result;  
  34.    }  
  35. }  

http://blog.csdn.net/defonds/article/details/8782785

    原文作者:Study_Work
    原文地址: https://www.cnblogs.com/yhtboke/p/6230149.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞