Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 中文字幕精品视频,午夜国产情侣拍视频,国产精品视频一区二区三区

          整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          java-socket長連接demo體驗

          java-socket長連接demo體驗
          作者:DavidDing
          來源:https://zhuanlan.zhihu.com/p/56135195
          

          、前言

          最近公司在預研設備app端與服務端的交互方案,主要方案有:

          • 服務端和app端通過阿里iot套件實現消息的收發;
          • 服務端通過極光推送主動給app端推消息,app通過rest接口與服務端進行交互;
          • 服務端與app通過mqtt消息隊列來實現彼此的消息交互;
          • 服務端與app通過原生socket長連接交互。

          雖然上面的一些成熟方案肯定更利于上生產環境,但它們通訊基礎也都是socket長連接,所以本人主要是預研了一下socket長連接的交互,寫了個簡單demo,采用了BIO的多線程方案,集成了springboot,實現了自定義簡單協議,心跳機制,socket客戶端身份強制驗證,socket客戶端斷線獲知等功能,并暴露了一些接口,可通過接口簡單實現客戶端與服務端的socket交互。

          Github源碼:

          https://github.com/DavidDingXu/springboot-socket-demo

          二、IO通訊模型

          1. IO通訊模型簡介

          IO通訊模型主要包括阻塞式同步IO(BIO),非阻塞式同步IO,多路復用IO以及異步IO。

          該部分內容總結自專欄文章:

          https://blog.csdn.net/yinwenjie/column/info/sys-communication/3

          1.1 阻塞式同步IO

          BIO就是:blocking IO。最容易理解、最容易實現的IO工作方式,應用程序向操作系統請求網絡IO操作,這時應用程序會一直等待;另一方面,操作系統收到請求后,也會等待,直到網絡上有數據傳到監聽端口;操作系統在收集數據后,會把數據發送給應用程序;最后應用程序受到數據,并解除等待狀態。



          BIO通訊示意圖

          1.2 非阻塞式同步IO

          這種模式下,應用程序的線程不再一直等待操作系統的IO狀態,而是在等待一段時間后,就解除阻塞。如果沒有得到想要的結果,則再次進行相同的操作。這樣的工作方式,暴增了應用程序的線程可以不會一直阻塞,而是可以進行一些其他工作。



          非阻塞式IO示意圖

          1.3 多路復用IO(阻塞+非阻塞)



          多路復用IO示意圖

          目前流程的多路復用IO實現主要包括四種:select、poll、epoll、kqueue。下表是他們的一些重要特性的比較:



          1.4 異步IO

          異步IO則是采用“訂閱-通知”模式:即應用程序向操作系統注冊IO監聽,然后繼續做自己的事情。當操作系統發生IO事件,并且準備好數據后,在主動通知應用程序,觸發相應的函數。



          異步IO示意圖

          和同步IO一樣,異步IO也是由操作系統進行支持的。微軟的windows系統提供了一種異步IO技術:IOCP(I/O Completion Port,I/O完成端口);

          Linux下由于沒有這種異步IO技術,所以使用的是epoll(上文介紹過的一種多路復用IO技術的實現)對異步IO進行模擬。

          2. Java對IO模型的支持

          • Java對阻塞式同步IO的支持主要是java.net包中的Socket套接字實現;
          • Java中非阻塞同步IO模式通過設置serverSocket.setSoTimeout(100);即可實現;
          • Java 1.4中引入了NIO框架(java.nio包)可以構建多路復用、同步非阻塞IO程序;
          • Java 7中對NIO進行了進一步改進,即NIO2,引入了異步非阻塞IO方式。

          由于是要實現socket長連接的demo,主要關注其一些實現注意點及方案,所以本demo采用了BIO的多線程方案,該方案代碼比較簡單、直觀,引入了多線程技術后,IO的處理吞吐量也大大提高了。下面是BIO多線程方案server端的簡單實現:

          public static void main(String[] args) throws Exception{
           ServerSocket serverSocket=new ServerSocket(83);
           try {
           while(true) {
           Socket socket=null;
           socket=serverSocket.accept();
           //這邊獲得socket連接后開啟一個線程監聽處理數據
           SocketServerThread socketServerThread=new SocketServerThread(socket);
           new Thread(socketServerThread).start();
           }
           } catch(Exception e) {
           log.error("Socket accept failed. Exception:{}", e.getMessage());
           } finally {
           if(serverSocket !=null) {
           serverSocket.close();
           }
           }
           }
          }
          @slf4j
          class SocketServerThread implements Runnable {
           private Socket socket;
           public SocketServerThread (Socket socket) {
           this.socket=socket;
           }
           @Override
           public void run() {
           InputStream in=null;
           OutputStream out=null;
           try {
           in=socket.getInputStream();
           out=socket.getOutputStream();
           Integer sourcePort=socket.getPort();
           int maxLen=2048;
           byte[] contextBytes=new byte[maxLen];
           int realLen;
           StringBuffer message=new StringBuffer();
           BIORead:while(true) {
           try {
           while((realLen=in.read(contextBytes, 0, maxLen)) !=-1) {
           message.append(new String(contextBytes , 0 , realLen));
           /*
           * 我們假設讀取到“over”關鍵字,
           * 表示客戶端的所有信息在經過若干次傳送后,完成
           * */
           if(message.indexOf("over") !=-1) {
           break BIORead;
           }
           }
           }
           //下面打印信息
           log.info("服務器(收到來自于端口:" + sourcePort + "的信息:" + message);
           //下面開始發送信息
           out.write("回發響應信息!".getBytes());
           //關閉
           out.close();
           in.close();
           this.socket.close();
           } catch(Exception e) {
           log.error("Socket read failed. Exception:{}", e.getMessage());
           }
           }
          }
          

          三、注意點及實現方案

          1. TCP粘包/拆包

          1.1 問題說明

          假設客戶端分別發送了兩個數據包D1和D2給服務端,由于服務端一次讀取到的字節數是不確定的,故可能存在以下4種情況。 1. 服務端分兩次讀取到了兩個獨立的數據包,分別是D1和D2,沒有粘包和拆包; 2. 服務端一次接收到了兩個數據包,D1和D2粘合在一起,被稱為TCP粘包; 3. 服務端分兩次讀取到了兩個數據包,第一次讀取到了完整的D1包和D2包的部分內容,第二次讀取到了D2包的剩余內容,這被稱為TCP拆包; 4. 服務端分兩次讀取到了兩個數據包,第一次讀取到了D1包的部分內容D1_1,第二次讀取到了D1包的剩余內容D1_2和D2包的整包。如果此時服務端TCP接收滑窗非常小,而數據包D1和D2比較大,很有可能會發生第五種可能,即服務端分多次才能將D1和D2包接收完全,期間發生多次拆包。

          1.2 解決思路

          由于底層的TCP無法理解上層的業務數據,所以在底層是無法保證數據包不被拆分和重組的,這個問題只能通過上層的應用協議棧設計來解決,根據業界的主流協議的解決方案,可以歸納如下: 1. 消息定長,例如每個報文的大小為固定長度200字節,如果不夠,空位補空格; 2. 在包尾增加回車換行符進行分割,例如FTP協議; 3. 將消息分為消息頭和消息體,消息頭中包含表示消息總長度(或者消息體長度)的字段,通常設計思路為消息頭的第一個字段使用int32來表示消息的總長度; 4. 更復雜的應用層協議。

          1.3 demo方案

          作為socket長連接的demo,使用了上述的解決思路2,即在包尾增加回車換行符進行數據的分割,同時整體數據使用約定的Json體進行作為消息的傳輸格式。

          使用換行符進行數據分割,可如下進行數據的單行讀取:

          BufferedReader reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
          String message;
          while ((message=reader.readLine()) !=null) {
          //....
          }
          

          可如下進行數據的單行寫入:

          PrintWriter writer=new PrintWriter(new OutputStreamWriter(socket.getOutputStream()), true);
          writer.println(message);
          

          Json消息格式如下:

          (1) 服務端接收消息實體類

          @Data
          public class ServerReceiveDto implements Serializable {
           private static final long serialVersionUID=6600253865619639317L;
           /**
           * 功能碼 0 心跳 1 登陸 2 登出 3 發送消息
           */
           private Integer functionCode;
           /**
           * 用戶id
           */
           private String userId;
           /**
           * 這邊假設是string的消息體
           */
           private String message;
          }
          

          (2) 服務端發送消息實體類

          @Data
          public class ServerSendDto implements Serializable {
           private static final long serialVersionUID=-7453297551797390215L;
           /**
           * 狀態碼 20000 成功,否則有errorMessage
           */
           private Integer statusCode;
           private String message;
           /**
           * 功能碼
           */
           private Integer functionCode;
           /**
           * 錯誤消息
           */
           private String errorMessage;
          }
          

          (3) 客戶端發送消息實體類

          @Data
          public class ClientSendDto implements Serializable {
           private static final long serialVersionUID=97085384412852967L;
           /**
           * 功能碼 0 心跳 1 登陸 2 登出 3 發送消息
           */
           private Integer functionCode;
           /**
           * 用戶id
           */
           private String userId;
           /**
           * 這邊假設是string的消息體
           */
           private String message;
          }
          

          2. 客戶端或服務端掉線檢測功能

          2.1 實現思路

          通過自定義心跳包來實現掉線檢測功能,具體思路如下:

          客戶端連接上服務端后,在服務端會維護一個在線客戶端列表。客戶端每隔一段時間,向服務端發送一個心跳包,服務端受收到包以后,會更新客戶端最近一次在線時間。一旦服務端超過規定時間沒有接收到客戶端發來的包,則視為掉線。

          2.2 代碼實現

          維護一個客戶端map,其中key代表用戶的唯一id(用戶唯一id的身份驗證下面會說明),value代表用戶對應的一個實體

          /**
           * 存儲當前由用戶信息活躍的的socket線程
           */
          private ConcurrentMap<String, Connection> existSocketMap=new ConcurrentHashMap<>();
          

          其中Connection對象包含的信息如下:

          @Slf4j
          @Data
          public class Connection {
           /**
           * 當前的socket連接實例
           */
           private Socket socket;
           /**
           * 當前連接線程
           */
           private ConnectionThread connectionThread;
           /**
           * 當前連接是否登陸
           */
           private boolean isLogin;
           /**
           * 存儲當前的user信息
           */
           private String userId;
           /**
           * 創建時間
           */
           private Date createTime;
           /**
           * 最后一次更新時間,用于判斷心跳
           */
           private Date lastOnTime;
          }
          

          主要關注其中的lastOnTime字段,每次服務端接收到標識是心跳數據,會更新當前的lastOnTime字段,代碼如下:

          if (functionCode.equals(FunctionCodeEnum.HEART.getValue())) {
           //心跳類型
           connection.setLastOnTime(new Date());
           //發送同樣的心跳數據給客戶端
           ServerSendDto dto=new ServerSendDto();
           dto.setFunctionCode(FunctionCodeEnum.HEART.getValue());
           connection.println(JSONObject.toJSONString(dto));
          }
          

          額外會有一個監測進程,以一定頻率來監測上述維護的map中的每一個Connection對象,如果當前時間與lastOnTime的時間間隔超過自定義的長度,則自動將其對應的socket連接關閉,代碼如下:

          Date now=new Date();
          Date lastOnTime=connectionThread.getConnection().getLastOnTime();
          long heartDuration=now.getTime() - lastOnTime.getTime();
          if (heartDuration > SocketConstant.HEART_RATE) {
           //心跳超時,關閉當前線程
           log.error("心跳超時");
           connectionThread.stopRunning();
          }
          

          在上面代碼中,服務端收到標識是心跳數據的時候,除了更新該socket對應的lastOnTime,還會同樣同樣心跳類型的數據給客戶端,客戶端收到標識是心跳數據的時候也會更新自己的lastOnTime字段,同時也有一個心跳監測線程在監測當前的socket連接心跳是否超時

          3. 客戶端身份獲知、強制身份驗證

          3.1 實現思路

          通過代碼socket=serverSocket.accept()獲得的一個socket連接我們僅僅只能知道其客戶端的ip以及端口號,并不能獲知這個socket連接對應的到底是哪一個客戶端,因此必須得先獲得客戶端的身份并且驗證通過其身份才能讓其正常連接。

          具體的實現思路是:

          自定義一個登陸處理接口,當server端受到標識是用戶登陸的時候(此時會攜帶用戶信息或者token,此處簡化為用戶id),調用用戶的登陸驗證,驗證通過的話則將該socket連接與用戶信息綁定,設置其為已登錄,并且封裝對應的對象放入前面提的客戶端map中,由此可獲得具體用戶對應的哪一個socket連接。

          為了實現socket連接的強制驗證,在監測線程中,也會判斷當前用戶多長時間內沒有實現登錄態,若超時則認為該socket連接為非法連接,主動關閉該socket連接。

          3.2 代碼實現

          自定義登陸處理接口,這邊簡單以userId來判斷是否允許登陸:

          public interface LoginHandler {
           /**
           * client登陸的處理函數
           *
           * @param userId 用戶id
           *
           * @return 是否驗證通過
           */
           boolean canLogin(String userId);
          }
          

          收到客戶端發來的數據時候的處理:

          if (functionCode.equals(FunctionCodeEnum.LOGIN.getValue())) {
           //登陸,身份驗證
           String userId=receiveDto.getUserId();
           if (socketServer.getLoginHandler().canLogin(userId)) {
           //設置用戶對象已登錄狀態
           connection.setLogin(true);
           connection.setUserId(userId);
           if (socketServer.getExistSocketMap().containsKey(userId)) {
           //存在已登錄的用戶,發送登出指令并主動關閉該socket
           Connection existConnection=socketServer.getExistSocketMap().get(userId);
           ServerSendDto dto=new ServerSendDto();
           dto.setStatusCode(999);
           dto.setFunctionCode(FunctionCodeEnum.MESSAGE.getValue());
           dto.setErrorMessage("force logout");
           existConnection.println(JSONObject.toJSONString(dto));
           existConnection.getConnectionThread().stopRunning();
           log.error("用戶被客戶端重入踢出,userId:{}", userId);
           }
           //添加到已登錄map中
           socketServer.getExistSocketMap().put(userId, connection);
          }
          

          監測線程判斷用戶是否完成身份驗證:

          if (!connectionThread.getConnection().isLogin()) {
           //還沒有用戶登陸成功
           Date createTime=connectionThread.getConnection().getCreateTime();
           long loginDuration=now.getTime() - createTime.getTime();
           if (loginDuration > SocketConstant.LOGIN_DELAY) {
           //身份驗證超時
           log.error("身份驗證超時");
           connectionThread.stopRunning();
           }
          }
          

          4. socket異常處理與垃圾線程回收

          4.1 實現思路

          socket在讀取數據或者發送數據的時候會出現各種異常,比如客戶端的socket已斷開連接(正常斷開或物理連接斷開等),但是服務端還在發送數據或者還在接受數據的過程中,此時socket會拋出相關異常,對于該異常的處理需要將自身的socket連接關閉,避免資源的浪費,同時由于是多線程方案,還需將該socket對應的線程正常清理。

          4.2 代碼實現

          下面以server端發送數據為例,該代碼中加入了重試機制:

          public void println(String message) {
           int count=0;
           PrintWriter writer;
           do {
           try {
           writer=new PrintWriter(new OutputStreamWriter(socket.getOutputStream()), true);
           writer.println(message);
           break;
           } catch (IOException e) {
           count++;
           if (count >=RETRY_COUNT) {
           //重試多次失敗,說明client端socket異常
           this.connectionThread.stopRunning();
           }
           }
           try {
           Thread.sleep(2 * 1000);
           } catch (InterruptedException e1) {
           log.error("Connection.println.IOException interrupt,userId:{}", userId);
           }
           } while (count < 3);
          }
          

          上述調用的this.connectionThread.stopRunning()代碼如下:

          public void stopRunning() {
           //設置線程對象狀態,便于線程清理
           isRunning=false;
           try {
           //異常情況需要將該socket資源釋放
           socket.close();
           } catch (IOException e) {
           log.error("ConnectionThread.stopRunning failed.exception:{}", e);
           }
          }
          

          上述代碼中設置了線程對象的狀態,下述代碼在監測線程中執行,將沒有運行的線程給清理掉

          /**
           * 存儲只要有socket處理的線程
           */
          private List<ConnectionThread> existConnectionThreadList=Collections.synchronizedList(new ArrayList<>());
          /**
           * 中間list,用于遍歷的時候刪除
           */
          private List<ConnectionThread> noConnectionThreadList=Collections.synchronizedList(new ArrayList<>());
          //...
          //刪除list中沒有用的thread引用
          existConnectionThreadList.forEach(connectionThread -> {
           if (!connectionThread.isRunning()) {
           noConnectionThreadList.add(connectionThread);
           }
          });
          noConnectionThreadList.forEach(connectionThread -> {
           existConnectionThreadList.remove(connectionThread);
           if (connectionThread.getConnection().isLogin()) {
           //說明用戶已經身份驗證成功了,需要刪除map
           this.existSocketMap.remove(connectionThread.getConnection().getUserId());
           }
          });
          noConnectionThreadList.clear();
          

          四、項目結構

          由于使用了springboot框架來實現該demo,所以項目結構如下:

          整體項目結構圖

          socket工具包目錄如下:

          socket工具包目錄

          pom文件主要添加了springboot的相關依賴,以及json工具和lombok工具等,依賴如下:

          <parent>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-parent</artifactId>
           <version>2.0.3.RELEASE</version>
           <relativePath/>
          </parent>
          <dependencies>
           <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
           </dependency>
           <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-test</artifactId>
           </dependency>
           <dependency>
           <groupId>org.projectlombok</groupId>
           <artifactId>lombok</artifactId>
           </dependency>
           <dependency>
           <groupId>com.alibaba</groupId>
           <artifactId>fastjson</artifactId>
           <version>1.2.36</version>
           </dependency>
          </dependencies>
          

          自己寫的socket工具包的使用方式如下:

          @Configuration
          @Slf4j
          public class SocketServerConfig {
          @Bean
          public SocketServer socketServer() {
           SocketServer socketServer=new SocketServer(60000);
           socketServer.setLoginHandler(userId -> {
           log.info("處理socket用戶身份驗證,userId:{}", userId);
           //用戶名中包含了dingxu則允許登陸
           return userId.contains("dingxu");
           });
           socketServer.setMessageHandler((connection, receiveDto) -> log
           .info("處理socket消息,userId:{},receiveDto:{}", connection.getUserId(),
           JSONObject.toJSONString(receiveDto)));
           socketServer.start();
           return socketServer;
          }
          }
          

          該demo中主要提供了以下幾個接口進行測試:

          • 服務端:獲得當前用戶列表,發送一個消息客戶端:開始一個socket客戶端,發送一個消息,關閉一個socket客戶端,查看已開啟的客戶端

          具體的postman文件也放已在項目中,具體可點此鏈接獲得

          demo中還提供了一個簡單壓測函數,如下:

          @Slf4j
          public class SocketClientTest {
           public static void main(String[] args) {
           ExecutorService clientService=Executors.newCachedThreadPool();
           String userId="dingxu";
           for (int i=0; i < 1000; i++) {
           int index=i;
           clientService.execute(() -> {
           try {
           SocketClient client;
           client=new SocketClient(InetAddress.getByName("127.0.0.1"), 60000);
           //登陸
           ClientSendDto dto=new ClientSendDto();
           dto.setFunctionCode(FunctionCodeEnum.LOGIN.getValue());
           dto.setUserId(userId + index);
           client.println(JSONObject.toJSONString(dto));
           ScheduledExecutorService clientHeartExecutor=Executors.newSingleThreadScheduledExecutor(
           r -> new Thread(r, "socket_client+heart_" + r.hashCode()));
           clientHeartExecutor.scheduleWithFixedDelay(() -> {
           try {
           ClientSendDto heartDto=new ClientSendDto();
           heartDto.setFunctionCode(FunctionCodeEnum.HEART.getValue());
           client.println(JSONObject.toJSONString(heartDto));
           } catch (Exception e) {
           log.error("客戶端異常,userId:{},exception:{}", userId, e.getMessage());
           client.close();
           }
           }, 0, 5, TimeUnit.SECONDS);
           while (true){
           }
           } catch (Exception e) {
           log.error(e.getMessage());
           }
           });
           }
           }
          }
          

          源碼地址如下,僅供學習參考

          github.com/DavidDingXu/springboot-socket-demo

          五、參考

          本樣式對齊文本text-align屬性用于指定文本塊的對齊方式,可選值包括: 1)start:內容對齊開始邊界,默認; 2)end:內容對齊結束邊界; 3)left:內容左對齊; 4)right:內容右對齊; 5)center:內容居中對齊; 6)justify:內容兩端對齊。當text-align屬性使用了justify值時,可以使用text-justify屬性指定文本添加空白的方式,這個屬性...
          了解了包的概念,就可以系統的介紹Java中的訪問控制級別。在Java中,針對類、成員方法和屬性提供了四種訪問級別,分別是private、default、protected和public。 權限訪問修飾符(權限從大到小依次往右排) public(公共) protected(受保護) default(缺省) private(私有) 同一個類 √ √...
          Rust 提供了代碼封裝的機制。可以通過crate (等同于Java中的package)創建相對獨立的module模塊,模塊中封裝了可以重復使用的功能函數。當創建了自己的 lib 庫或者要使用第三方的庫的時候(這些庫就是一些事先寫好的crate)需要將這些庫中的module 模塊引用到當前的環境中。Rust提供了以下幾種引用方式:一、使用 extern crate在使用這些Module的文件中,通過...
          填空題: 他______犧牲生命_______出賣組織? 據數據統計,不同年代的同學回復的最多的是….. 60后,他寧可犧牲生命,也不出賣組織。 70后,他害怕犧牲生命,所以出賣組織。 80后,他與其犧牲生命,不如出賣組織。 90后,他即使犧牲生命,也要出賣組織。 00后,他白白犧牲了生命,忘了出賣組織。 上邊的案例,引發了大家對”自我與企業關系的思考”. 能力與欲望...
          歷屆試題 國王的煩惱 時間限制:1.0s 內存限制:256.0MB 問題描述 C國由n個小島組成,為了方便小島之間聯絡,C國在小島間建立了m座大橋,每座大橋連接兩座小島。兩個小島間可能存在多座橋連接。然而,由于海水沖刷,有一些大橋面臨著不能使用的危險。 如果兩個小島間的所有大橋都不能使用,則這兩座小島就不能直接到達了。然而,只要這兩座...
          go test命令參數問題在使用go test對go代碼進行單元測試的時候,遇到關于命令參數的問題,google了一下,沒有找到很好的說明,其實就是一些細節而已。問題是這樣的,在進行單元測試的時候,我希望輸入一些命令行參數來控制程序的運行。 參考go官方文檔,只需要在go test后面加上-args和參數就可以了 例如 go test -args -classpath E:\testcase...
          阿里云OSS-使用經驗總結,存儲,賬號-權限,分頁,縮略圖,賬號切換最近項目中,需要使用云存儲,最后選擇了阿里云-對象存儲服務OSS。總的來說,比較簡單,但是仍然遇到了幾個問題,需要總結下。1.OSS總的使用介紹 https://help.aliyun.com/document_detail/oss/sdk/java-sdk/manage_object.html?spm=5176.docoss/...
          WEB應用圖片的格式,以及各自的特點和優化(一) by FungLeo前言12年前我入行三天.用table布局做了一個非常粗糙的網頁.我說了一句話,”網頁就是表格加文字加圖片,圖片分兩種,插入圖片和背景圖片”.這句話在今天看來,當然是一個笑話.但是當時我說出這句話的時候,當時的那些前輩都非常認可我的總結,并且認為我很有從事網絡發展的潛力啊.哎,要不是他們的鼓勵,說不定我早轉行了……扯遠了.說回正題,...
          1. 單表數據的導出針對單表數據的導出操作,MongoDB 提供了 mongoexport 命令。mongoexport 既可以將數據導出為 CSV 格式的文件,也可以導出 JSON 格式的文件。這兩者之間的區別是:JSON 是 mongoexport 默認的導出格式,不需要指定,而要導出 CSV 格式的話需要明確指定;導出 CSV 格式必須顯式指定各屬性名,而導出 JSON 格式不需要。由此可見...
          商業智能對于中小企業來說,由于其高昂的費用和運行維護技術水平要求高,往往難以承受,商業智能SAAS系統平臺+模塊的創新模式的出現能幫助中小企業走上商業智能之路。...
          stack.sh給出了一個非常好的例子,關于學習openstack創建 1.檢查devstack文件,檢查bash4.2以上,檢查用戶,不能是root2.準備環境,導入函數3.檢查local.conf和localrc是否都存在,如果存在使用localrc4.檢查是否已經運行devstack5.代理設置和禁用無效服務6.配置sudo7.配置distro庫8.配置目標目錄,創建目標目錄9.配置主機、日...
          博客地址:http://blog.csdn.net/FoxDave本文介紹如何利用SharePoint客戶端對象模型(.NET)逐級獲取Office 365網站中List的內容,僅僅是示例,沒有講究太多東西。代碼如下:ClientContext ctx=new ClientContext(""); ctx.Credentials=new SharePointOn...
          題外話Atom,風風雨雨走過一年多了.,目前最新版本是V1.7.0 .社區還是相當活躍;體驗也改善了很多;但是性能上還是欠缺;今天我再來介紹自己常用的一款插件git-control插件介紹 官方介紹頁面 作者: jacogr Github地址 我的介紹 就是命令行的GUI版本,,有些類似sourcetree,但是不如它強大,日用滿足使用在編輯器下加載git版本的工作目錄;工具默認啟用快捷鍵...
          安裝devstack后,如果沒有設置參數,執行openstack命令是不成功的。1.登錄到horizon頁面,使用admin登入,進入project->compute-> Access&Security -> API Access,記錄下Service Endpoint。或選擇download OpenStack RC File按鈕,下載demo-openrc.sh文件2.將demo-openrc...
          對于這樣的問題,看到第一眼就是暴力破解,所以也就遞歸找到所有情況,再篩選出合格的小明被劫持到X賭城,被迫與其他3人玩牌。 一副撲克牌(去掉大小王牌,共52張),均勻發給4個人,每個人13張。 這時,小明腦子里突然冒出一個問題: 如果不考慮花色,只考慮點數,也不考慮自己得到的牌的先后順序,自己手里能拿到的初始牌型組合一共有多少種呢?思路: 首先無論怎么取,手牌為13張的時候結束.也就是遞歸結束標...
          網紅和粉絲經濟,是最近幾年流行起來的概念。 截至目前,有一些初步的認識,整理成文。 粉絲,最早是明星的跟隨者比較多。 我的理解是,對于一個人物、動物、運動等,有著共同的興趣,從而建立多個人和一個人之間的關系,比如粉絲和明星。 粉絲經濟,大獲成功的標志是,雷軍和小米科技。在創業早期,就把粉絲經濟和社交傳播結合在一起,低成本地實現了全網營銷。從此以后,各大手機廠商等很多領域的企業,都...
          關于android端apk退出方式的設計,現在大體只有下面幾種:1,有退出和取消按鈕;2,一定時間內兩次返回為退出;3,一次返回就是退出。首先可以看到這兩個用按鈕的,退出都在左側,設計者肯定沒有看過十年前雅虎研究院出的web端設計指導,下一步的操作一定是在右側,而返回上一步的操作是在左側。但是到了移動端應該考慮用戶是左手還是右手使用,也就是說,如果是左手使用,這個位置設計沒有問題,反之就不用說了。...
          寫在最前:本文主要描述在網站的不同的并發訪問量級下,Mysql架構的演變可擴展性架構的可擴展性往往和并發是息息相關,沒有并發的增長,也就沒有必要做高可擴展性的架構,這里對可擴展性進行簡單介紹一下,常用的擴展手段有以下兩種Scale-up : 縱向擴展,通過替換為更好的機器和資源來實現伸縮,提升服務能力Scale-out : 橫向擴展, 通過加節點(機器)來實現伸縮,提升服務能力對于互聯網的高并...
          angular.js中,指令是最基礎的也是最重要的工具之一。angular.js指令指的是以ng為前綴的HTML屬性。在之前的ng-app、ng-model等,都屬于指令。 angular.js中的基本指令包括如下內容: · 1.ng-app/ng-model ng-app指令用于聲明angular,js的作用范圍,ng-model用于聲明模型。這些在之前都已經進行過詳細介紹。 2.ng-...
          java編碼 當你的字節序列是某種編碼時,這個時候想把字節序列變成 字符串,也需要用這種編碼方式,否則會出現亂碼 文本文件就是字節序列 可以是任意編碼的序列,如果在中文機器上直接創建文本文件,那么該文本文件 只認識ANSI編碼 案例: public class Bianma { public static void main(Strin...
          調試JDK源碼-一步一步看HashMap怎么Hash和擴容調試JDK源碼-ConcurrentHashMap實現原理調試JDK源碼-HashSet實現原理調試JDK源碼-調試JDK源碼-Hashtable實現原理以及線程安全的原因 ConcurrentHashMap線程安全的總結是我從源碼分析出來的:ConcurrentHashMap所謂線程安全是哈希沖突的時候新增的節點是線程安全的,而 Conc...
          對于后臺系統的搜索進行UI自動化,主要是比對頁面查詢結果是否與預期一致(即數據庫查詢結果) search.py# -*- coding:utf8 -*- import HTMLTestRunner import time import unittest import public from selenium import webdriver class Search(unittest.TestCa...
          ajax 的全稱是Asynchronous(異步的意思) JavaScript and XML,是一種創建交互式網頁應用的網頁開發技術 ajax技術的流行得益于google的大力推廣,正是由于google產品對ajax技術的廣泛應用,使得ajax流行起來了。 Ajax其核心有JavaScript、XMLHTTPRequest、DOM對象組成,通過XmlHttpRequest對象來向服務器發異步請求,從服務器獲得數據,然后用JavaScript來操作DOM而更新頁面。這其中最關鍵的一步就是從服務器獲得請...
          一、SpringMVChttp://blog.csdn.net/evankaka/article/details/45501811Spring Web MVC是一種基于Java的實現了Web MVC設計模式的請求驅動類型的輕量級Web框架,即使用了MVC架構模式的思想,將web層進行職責解耦,基于請求驅動指的就是使用請求-響應模型,框架的目的就是幫助我們簡化開發,Spring Web MVC也是要簡...
          概念: 優化策略:字段選擇性 選擇性較低索引 可能帶來的性能問題索引選擇性=索引列唯一值/表記錄數;選擇性越高索引檢索價值越高,消耗系統資源越少;選擇性越低索引檢索價值越低,消耗系統資源越多;查詢條件含有多個字段時,不要在選擇性很低字段上創建索引可通過創建組合索引來增強低字段選擇性和避免選擇性很低字段創建索引帶來副作用;盡量減少possible_keys,正確索引會提高sql查詢速度,過多索引...
          一. 什么是Spark? Spark是UC Berkeley AMP lab所開源的類Hadoop MapReduce的通用的并行計算框架,Spark基于map reduce算法實現的分布式計算,擁有Hadoop MapReduce所具有的優點;但不同于MapReduce的是Job中間輸出和結果可以保存在內存中,從而不再需要讀寫HDFS,因此Spark能更好地適用于數據挖掘與機器學習等需...
          相比之前的增改查,刪除就顯得簡單的多了。 這里的request的type為delete,刪除成功的status為204,404則是要刪除的記錄不存在 var id='BAD90A95-7FEA-E511-9414-ADA183AB6249'; $.ajax({ async: false, type: "DELETE ", co...
          關于JPush極光推送是國內的服務廠商提供的一站式push服務(同時支持iOS、android),后面也加入了即時通訊的能力供app使用。致力于打造簡單、可靠、價格有競爭力的服務(簡單功能全免費,高級版才收費),讓應用開發商可以聚焦業務開發,push相關的技術實現全部通過極光推送來解決,僅需調用極光推送的api即可。正因為如此,開發者小伙伴們對其的評價相當不錯。筆者的app新增了從服務器往移動客戶端...
          Mapreduce初析 Mapreduce是一個計算框架,既然是做計算的框架,那么表現形式就是有個輸入(input),mapreduce操作這個輸入(input),通過本身定義好的計算模型,得到一個輸出(output),這個輸出就是我們所需要的結果。 重點就是這個計算模型的運行規則。在運行一個mapreduce計算任務時候,任務過程被分為兩個階段:map階段...
          Jquery對象常用的方法:$(”p”).addClass(css中定義的樣式類型); 給某個元素添加樣式 $(”img”).attr({src:”test.jpg”,alt:”test Image”}); 給某個元素添加屬性/值,參數是map $(”img”).attr(”src”,”test.jpg”); 給某個元素添加屬性/值 $(”img”).attr(”title”, function(...

          隆匯6月29日丨極光(JG.US)盤前漲逾9%,報1.19美元。近日,極光的核心產品極光推送(JPush)順利通過亞馬遜云科技的多項測試及審核,正式上線亞馬遜云科技Marketplace。當前,亞馬遜云科技Marketplace上的用戶,通過其中國區網站,即可直接購買和體驗極光推送(JPush)。

          本文源自格隆匯


          主站蜘蛛池模板: 成人h动漫精品一区二区无码| 中文字幕无线码一区| 国产成人av一区二区三区在线| 精品国产一区二区三区| 国产在线第一区二区三区| 无码精品人妻一区二区三区漫画| 国产成人无码精品一区二区三区| 精品无码国产一区二区三区AV| 亚洲高清一区二区三区| 国产精品一区二区AV麻豆| 亚洲国产精品成人一区| 亚洲图片一区二区| 欧美激情国产精品视频一区二区| 夜夜精品无码一区二区三区| 美女一区二区三区| 欧美人妻一区黄a片| 日韩精品无码一区二区三区AV | 国产在线步兵一区二区三区| 久久影院亚洲一区| 日本视频一区在线观看免费| 一区五十路在线中出| 麻豆一区二区在我观看| 精品人妻一区二区三区四区 | 一区二区三区在线看| 久久精品道一区二区三区| 日本精品视频一区二区| 无码精品人妻一区二区三区中| 国产乱人伦精品一区二区在线观看| 中文字幕国产一区| 亚洲日韩国产欧美一区二区三区| 中文字幕一区精品| 日本一区二区三区四区视频| 日韩一区精品视频一区二区| 冲田杏梨高清无一区二区| 亚洲性无码一区二区三区 | 精品无码人妻一区二区三区| 一区二区三区四区在线视频| 国产日韩一区二区三区在线播放| 成人免费一区二区三区| 无码精品不卡一区二区三区| 一区二区在线视频|