摘要:編程核心是通道和選擇器,選擇器通過不斷輪詢,執(zhí)行對(duì)應(yīng)的函數(shù)。所以我們需要捕獲這個(gè)異常,并且開始不斷重連。如果客戶端關(guān)閉那么服務(wù)器也要主動(dòng)關(guān)閉他數(shù)據(jù)庫代碼及實(shí)體類如果還想實(shí)現(xiàn)數(shù)據(jù)庫方面代碼,私我
物聯(lián)網(wǎng)答辯終于結(jié)束了 記一下自己網(wǎng)絡(luò)編程的代碼 重連代碼寫了好久 try catch原來可以這么用!
學(xué)習(xí)地址:https://www.bilibili.com/video/BV1gz4y1C7RK
項(xiàng)目結(jié)構(gòu):
package Server;import Entiles.User;import Utils.JdbcUtil;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.*;import java.nio.charset.Charset;import java.text.SimpleDateFormat;import java.util.Iterator;import java.util.Scanner;import java.util.Set;public class ChatServer { public void StratServer(int port) throws IOException { //soket通道 客戶通道 //創(chuàng)建服務(wù)端通道 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); //非堵塞模式 serverSocketChannel.configureBlocking(false); //創(chuàng)建buffer ByteBuffer byteBuffer = ByteBuffer.allocate(1024); //綁定端口 serverSocketChannel.bind(new InetSocketAddress(port)); //創(chuàng)建selector 選擇器 Selector selector = Selector.open(); //注冊(cè)通道 serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); //輪播查詢 System.out.println("智能水表服務(wù)端(端口:"+port+")已經(jīng)啟動(dòng)");// 如果有就緒狀態(tài)的通道 則select方法返回1 while(true){ while (selector.select()>0){// 因?yàn)橛卸鄠€(gè)通道 ,所以采用集合 獲取所有就緒的通道 // 得到所有就緒狀態(tài)的通道集合到key中 Set<SelectionKey> selectionKeys = selector.selectedKeys(); //selectedKeys所有已經(jīng)就緒的key集合// 轉(zhuǎn)成集合迭代器 Iterator<SelectionKey> iterator = selectionKeys.iterator(); while(iterator.hasNext()){ SelectionKey selectionKey = iterator.next(); //有人來連 if(selectionKey.isAcceptable()){ acceptOperator(serverSocketChannel,selector); } //發(fā)過來了已經(jīng) else if(selectionKey.isReadable()){ readOperator(selector,selectionKey); } //返回水表數(shù)據(jù) else if(selectionKey.isWritable()){ writeOperator(selector,selectionKey); } iterator.remove(); } } } } //處理服務(wù)器寫事件 private void writeOperator(Selector selector,SelectionKey selectionKey) { try { //有channel可寫,取出可寫的channel SocketChannel socketChannel = (SocketChannel) selectionKey.channel(); // 設(shè)計(jì)非阻塞 socketChannel.configureBlocking(false); socketChannel.write(Charset.forName("UTF-8").encode("數(shù)據(jù)庫存入成功!" )); //重新將channel注冊(cè)到選擇器上,設(shè)計(jì)為監(jiān)聽 socketChannel.register(selector,SelectionKey.OP_READ); }catch (IOException e){ e.printStackTrace(); } } // 處理讀事件 private void readOperator(Selector selector, SelectionKey selectionKey) throws IOException { try { // 獲取就緒通道 SocketChannel socketChannel = (SocketChannel)selectionKey.channel();// 設(shè)計(jì)buffer ByteBuffer buffer = ByteBuffer.allocate(1024);// 循環(huán)讀客戶端數(shù)據(jù) int length=0; String msg=""; if((length=socketChannel.read(buffer))>0){ //讀到buffer里面// 切換模式 buffer.flip(); msg+=Charset.forName("UTF-8").decode(buffer); //從buffer里面取數(shù)據(jù) 解碼 } System.out.println(msg); String str[]=msg.split(":"); String temp=str[1]; String str2[]=temp.split("、"); SimpleDateFormat tempDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String datetime = tempDate.format(new java.util.Date()); JdbcUtil.find(new User(str2[0],str2[1],str2[2],datetime)); //重新將channel注冊(cè)到選擇器上,設(shè)計(jì)為監(jiān)聽 socketChannel.register(selector,SelectionKey.OP_WRITE); }catch (IOException e){ selectionKey.cancel(); selectionKey.channel().close(); System.out.println("有客戶端斷連,我已主動(dòng)關(guān)閉"); } //光廣播到其他用戶上去// if(msg.length()>0){// System.out.println(msg);// castOtherClient(msg,selector,socketChannel);// } } //廣播到其他客戶端// private void castOtherClient(String msg, Selector selector, SocketChannel socketChannel) throws IOException {//// //獲取所有就緒的channel// Set selectionKeySet = selector.keys(); // 循環(huán)處理搜索就緒的channel// for (SelectionKey selectionKey : selectionKeySet){ 獲取每一個(gè)channel// Channel tarChannel = selectionKey.channel();// 不給自己發(fā)信息// if(tarChannel instanceof SocketChannel && tarChannel!=socketChannel){// ((SocketChannel)tarChannel).write(Charset.forName("UTF-8").encode(msg)); //傳輸數(shù)據(jù)是編碼,發(fā)送數(shù)據(jù)是解碼// }// }// } //處理接收狀態(tài)的通道 private void acceptOperator(ServerSocketChannel serverSocketChannel, Selector selector) { try { // 獲取連接 SocketChannel socketChannel = serverSocketChannel.accept();// 設(shè)計(jì)非阻塞 socketChannel.configureBlocking(false);// 注冊(cè)通道 socketChannel.register(selector,SelectionKey.OP_READ); //回復(fù)客戶端消息 socketChannel.write(Charset.forName("UTF-8").encode("您已成功連接到服務(wù)器!")); }catch (IOException e){ e.printStackTrace(); } } public static void main(String[] args) throws IOException { new ChatServer().StratServer(7890); }}
解釋:
其中我的readOperator函數(shù)是負(fù)責(zé)讀取客戶端傳來的信息。Nio編程核心是通道和選擇器,選擇器通過不斷輪詢,執(zhí)行對(duì)應(yīng)的函數(shù)。
此項(xiàng)目我加入了數(shù)據(jù)庫,如果收到客戶端信息,存入數(shù)據(jù)庫。
2.1、負(fù)責(zé)發(fā)送的主客戶端
package Client;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.SocketChannel;import java.nio.charset.Charset;import java.util.Scanner;public class ChatClient { public void startClient(String name ) throws IOException, InterruptedException { // 創(chuàng)建通道 綁定主機(jī)和端口 SocketChannel socketChannel = null; socketChannel = SocketChannel.open(new InetSocketAddress( "127.0.0.1", 7890)); //接受服務(wù)端響應(yīng)的數(shù)據(jù) Selector selector = Selector.open(); socketChannel.configureBlocking(false); socketChannel.register(selector, SelectionKey.OP_READ); //創(chuàng)建線程 new Thread(new ClientThread(selector)).start();//負(fù)責(zé)拿到服務(wù)器端數(shù)據(jù) //向服務(wù)端發(fā)送數(shù)據(jù) System.out.println("請(qǐng)輸入抄水表編號(hào)、抄水量、抄表員(抄水時(shí)間自動(dòng)生成)(請(qǐng)?jiān)?min中內(nèi)完成)"); Scanner scanner = new Scanner(System.in); while (scanner.hasNextLine()){ ByteBuffer byteBuffer = ByteBuffer.allocate(1024); String str = scanner.nextLine(); //鍵盤獲取輸入的內(nèi)容 if(str.length()>0){ socketChannel.write(Charset.forName("UTF-8").encode("客戶端:"+name+":"+str+"(已加載數(shù)據(jù)庫)")); //System.out.println(Charset.forName("UTF-8").encode(name+":"+str)); } //設(shè)計(jì)非堵塞模式 socketChannel.configureBlocking(false); //設(shè)計(jì)buffer } } public static void main(String[] args) throws IOException, InterruptedException { new ChatClient().startClient("gx"); }}
2.2、負(fù)責(zé)接收服務(wù)器信息的客戶端線程
package Client;import java.io.IOException;import java.net.ConnectException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.SocketChannel;import java.nio.charset.Charset;import java.util.Iterator;import java.util.Set;public class ClientThread implements Runnable{ private Selector selector; ClientThread(Selector selector){ this.selector=selector; } @Override public void run() {// while(true){ for(;;){ try { int length=selector.select(); if(length ==0){ continue; } // 得到所有就緒狀態(tài)的通道集合到key中 Set<SelectionKey> selectionKeys = selector.selectedKeys(); //selectedKeys所有已經(jīng)就緒的key集合 // 轉(zhuǎn)成集合迭代器 Iterator<SelectionKey> iterator = selectionKeys.iterator(); while(iterator.hasNext()){ SelectionKey selectionKey = iterator.next(); if(selectionKey.isReadable()){ readOperator(selector,selectionKey); } iterator.remove(); } } catch (IOException | InterruptedException e) { e.printStackTrace(); } } } // 處理接收服務(wù)器信息事件 private void readOperator(Selector selector, SelectionKey selectionKey) throws InterruptedException { try { // 獲取就緒通道 SocketChannel socketChannel = (SocketChannel)selectionKey.channel();// 設(shè)計(jì)buffer ByteBuffer buffer = ByteBuffer.allocate(1024);// 循環(huán)讀客戶端數(shù)據(jù) int length=0; String msg=""; if((length=socketChannel.read(buffer))>0){ //讀到buffer里面// 切換模式 buffer.flip(); msg+= Charset.forName("UTF-8").decode(buffer); //從buffer里面取數(shù)據(jù) 解碼 } System.out.println(msg); //重新將channel注冊(cè)到選擇器上,設(shè)計(jì)為監(jiān)聽 socketChannel.register(selector,SelectionKey.OP_READ); }catch (IOException e){ selectionKey.cancel(); System.out.println("服務(wù)器中斷 開始準(zhǔn)備重連"); while (true){ try { new ChatClient().startClient("gx"); } catch (IOException ioException) { System.out.println("正在重連(5s) "); //ioException.printStackTrace(); Thread.sleep(5000); continue; } } } }}
1 重連代碼解釋
如果服務(wù)器突然關(guān)閉,如果在這里不try catch異常,而是向上拋出的話,隨著服務(wù)器異常關(guān)閉,客戶端也掛了,而且不會(huì)重連。
所以我們需要捕獲這個(gè)異常,并且開始不斷重連。
我寫了一個(gè)死循環(huán),不斷連接,如果連不上他還是會(huì)報(bào)錯(cuò),所以連不上的錯(cuò)也要捕獲異常,不然程序就報(bào)錯(cuò)結(jié)束了,所以捕獲連接沒上的話,continue重新執(zhí)行while循環(huán),直到連接上服務(wù)器。
2 如果客戶端關(guān)閉 那么服務(wù)器也要主動(dòng)關(guān)閉他
如果還想實(shí)現(xiàn)數(shù)據(jù)庫方面代碼,私我
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/125587.html
摘要:阻塞當(dāng)進(jìn)行讀寫時(shí),線程是阻塞的狀態(tài)。當(dāng)任何一個(gè)收到數(shù)據(jù)后,中斷程序?qū)酒疬M(jìn)程。接收數(shù)據(jù)當(dāng)收到數(shù)據(jù)后,中斷程序會(huì)給的就緒列表添加引用。當(dāng)接收到數(shù)據(jù),中斷程序一方面修改,另一方面喚醒等待隊(duì)列中的進(jìn)程,進(jìn)程再次進(jìn)入運(yùn)行狀態(tài)如下圖。 本篇文章目的在于基本概念和原理的解釋,不會(huì)貼過多的使用代碼。 什么是NIO Java NIO (New IO)是 Java 的另一個(gè) IO API (來自 jav...
摘要:阻塞請(qǐng)求結(jié)果返回之前,當(dāng)前線程被掛起。也就是說在異步中,不會(huì)對(duì)用戶線程產(chǎn)生任何阻塞。當(dāng)前線程在拿到此次請(qǐng)求結(jié)果的過程中,可以做其它事情。事實(shí)上,可以只用一個(gè)線程處理所有的通道。 準(zhǔn)備知識(shí) 同步、異步、阻塞、非阻塞 同步和異步說的是服務(wù)端消息的通知機(jī)制,阻塞和非阻塞說的是客戶端線程的狀態(tài)。已客戶端一次網(wǎng)絡(luò)請(qǐng)求為例做簡(jiǎn)單說明: 同步同步是指一次請(qǐng)求沒有得到結(jié)果之前就不返回。 異步請(qǐng)求不會(huì)...
摘要:綁定完成后允許套接字進(jìn)行連接并等待連接。服務(wù)端根據(jù)報(bào)文返回響應(yīng),并關(guān)閉連接。單線程服務(wù)器多進(jìn)程及多線程服務(wù)器復(fù)用服務(wù)器復(fù)用的多線程服務(wù)器單線程服務(wù)器一次只處理一個(gè)請(qǐng)求,直到其完成為止。 前言 本篇文章將涉及以下內(nèi)容: IO實(shí)現(xiàn)Java Socket通信 NIO實(shí)現(xiàn)Java Socket通信 閱讀本文之前最好了解過: Java IO Java NIO Java Concurrenc...
摘要:的異步即是異步的,也是非阻塞的。但是,也可以進(jìn)行一層稍微薄點(diǎn)的封裝,保留這種多路復(fù)用的模型,比如的,是一種同步非阻塞的模型。系統(tǒng)調(diào)用操作系統(tǒng)的系統(tǒng)調(diào)用提供了多路復(fù)用的非阻塞的系統(tǒng)調(diào)用,這也是機(jī)制實(shí)現(xiàn)需要用到的。 異步IO編程在javascript中得到了廣泛的應(yīng)用,之前也寫過一篇博文進(jìn)行梳理。js的異步IO即是異步的,也是非阻塞的。非阻塞的IO需要底層操作系統(tǒng)的支持,比如在linux上...
摘要:的選擇器允許單個(gè)線程監(jiān)視多個(gè)輸入通道。一旦執(zhí)行的線程已經(jīng)超過讀取代碼中的某個(gè)數(shù)據(jù)片段,該線程就不會(huì)在數(shù)據(jù)中向后移動(dòng)通常不會(huì)。 1、引言 很多初涉網(wǎng)絡(luò)編程的程序員,在研究Java NIO(即異步IO)和經(jīng)典IO(也就是常說的阻塞式IO)的API時(shí),很快就會(huì)發(fā)現(xiàn)一個(gè)問題:我什么時(shí)候應(yīng)該使用經(jīng)典IO,什么時(shí)候應(yīng)該使用NIO? 在本文中,將嘗試用簡(jiǎn)明扼要的文字,闡明Java NIO和經(jīng)典IO之...
閱讀 3735·2023-01-11 11:02
閱讀 4244·2023-01-11 11:02
閱讀 3050·2023-01-11 11:02
閱讀 5180·2023-01-11 11:02
閱讀 4737·2023-01-11 11:02
閱讀 5534·2023-01-11 11:02
閱讀 5313·2023-01-11 11:02
閱讀 3989·2023-01-11 11:02