JAVA NIO 伺服器與客戶端實現示例
公共類:
package com.stevex.app.nio; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; public class CharsetHelper { private static final String UTF_8 = "UTF-8"; private static CharsetEncoder encoder = Charset.forName(UTF_8).newEncoder(); private static CharsetDecoder decoder = Charset.forName(UTF_8).newDecoder(); public static ByteBuffer encode(CharBuffer in) throws CharacterCodingException{ return encoder.encode(in); } public static CharBuffer decode(ByteBuffer in) throws CharacterCodingException{ return decoder.decode(in); } }
伺服器程式碼:
package com.stevex.app.nio; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.channels.ClosedChannelException; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Iterator; public class XiaoNa { private ByteBuffer readBuffer; private Selector selector; public static void main(String[] args){ XiaoNa xiaona = new XiaoNa(); xiaona.init(); xiaona.listen(); } private void init(){ readBuffer = ByteBuffer.allocate(1024); ServerSocketChannel servSocketChannel; try { servSocketChannel = ServerSocketChannel.open(); servSocketChannel.configureBlocking(false); //繫結埠 servSocketChannel.socket().bind(new InetSocketAddress(8383)); selector = Selector.open(); servSocketChannel.register(selector, SelectionKey.OP_ACCEPT); } catch (IOException e) { e.printStackTrace(); } } private void listen() { while(true){ try{ selector.select(); Iterator ite = selector.selectedKeys().iterator(); while(ite.hasNext()){ SelectionKey key = (SelectionKey) ite.next(); ite.remove();//確保不重複處理 handleKey(key); } } catch(Throwable t){ t.printStackTrace(); } } } private void handleKey(SelectionKey key) throws IOException, ClosedChannelException { SocketChannel channel = null; try{ if(key.isAcceptable()){ ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel(); channel = serverChannel.accept();//接受連線請求 channel.configureBlocking(false); channel.register(selector, SelectionKey.OP_READ); } else if(key.isReadable()){ channel = (SocketChannel) key.channel(); readBuffer.clear(); /*當客戶端channel關閉後,會不斷收到read事件,但沒有訊息,即read方法返回-1 * 所以這時伺服器端也需要關閉channel,避免無限無效的處理*/ int count = channel.read(readBuffer); if(count > 0){ //一定需要呼叫flip函式,否則讀取錯誤資料 readBuffer.flip(); /*使用CharBuffer配合取出正確的資料 String question = new String(readBuffer.array()); 可能會出錯,因為前面readBuffer.clear();並未真正清理資料 只是重置緩衝區的position, limit, mark, 而readBuffer.array()會返回整個緩衝區的內容。 decode方法只取readBuffer的position到limit資料。 例如,上一次讀取到緩衝區的是"where", clear後position為0,limit為 1024, 再次讀取“bye"到緩衝區後,position為3,limit不變, flip後position為0,limit為3,前三個字元被覆蓋了,但"re"還存在緩衝區中, 所以 new String(readBuffer.array()) 返回 "byere", 而decode(readBuffer)返回"bye"。 */ CharBuffer charBuffer = CharsetHelper.decode(readBuffer); String question = charBuffer.toString(); String answer = getAnswer(question); channel.write(CharsetHelper.encode(CharBuffer.wrap(answer))); } else{ //這裡關閉channel,因為客戶端已經關閉channel或者異常了 channel.close(); } } } catch(Throwable t){ t.printStackTrace(); if(channel != null){ channel.close(); } } } private String getAnswer(String question){ String answer = null; switch(question){ case "who": answer = "我是小娜\n"; break; case "what": answer = "我是來幫你解悶的\n"; break; case "where": answer = "我來自外太空\n"; break; case "hi": answer = "hello\n"; break; case "bye": answer = "88\n"; break; default: answer = "請輸入 who, 或者what, 或者where"; } return answer; } }
客戶端程式碼:
package com.stevex.app.nio; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.util.Iterator; import java.util.Random; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; public class Client implements Runnable{ private BlockingQueue<String> words; private Random random; public static void main(String[] args) { //種多個執行緒發起Socket客戶端連線請求 for(int i=0; i<10; i++){ Client c = new Client(); c.init(); new Thread(c).start(); } } @Override public void run() { SocketChannel channel = null; Selector selector = null; try { channel = SocketChannel.open(); channel.configureBlocking(false); //請求連線 channel.connect(new InetSocketAddress("localhost", 8383)); selector = Selector.open(); channel.register(selector, SelectionKey.OP_CONNECT); boolean isOver = false; while(! isOver){ selector.select(); Iterator ite = selector.selectedKeys().iterator(); while(ite.hasNext()){ SelectionKey key = (SelectionKey) ite.next(); ite.remove(); if(key.isConnectable()){ if(channel.isConnectionPending()){ if(channel.finishConnect()){ //只有當連線成功後才能註冊OP_READ事件 key.interestOps(SelectionKey.OP_READ); channel.write(CharsetHelper.encode(CharBuffer.wrap(getWord()))); sleep(); } else{ key.cancel(); } } } else if(key.isReadable()){ ByteBuffer byteBuffer = ByteBuffer.allocate(128); channel.read(byteBuffer); byteBuffer.flip(); CharBuffer charBuffer = CharsetHelper.decode(byteBuffer); String answer = charBuffer.toString(); System.out.println(Thread.currentThread().getId() + "---" + answer); String word = getWord(); if(word != null){ channel.write(CharsetHelper.encode(CharBuffer.wrap(word))); } else{ isOver = true; } sleep(); } } } } catch (IOException e) { e.printStackTrace(); } finally{ if(channel != null){ try { channel.close(); } catch (IOException e) { e.printStackTrace(); } } if(selector != null){ try { selector.close(); } catch (IOException e) { e.printStackTrace(); } } } } private void init() { words = new ArrayBlockingQueue<String>(5); try { words.put("hi"); words.put("who"); words.put("what"); words.put("where"); words.put("bye"); } catch (InterruptedException e) { e.printStackTrace(); } random = new Random(); } private String getWord(){ return words.poll(); } private void sleep() { try { TimeUnit.SECONDS.sleep(random.nextInt(3)); } catch (InterruptedException e) { e.printStackTrace(); } } private void sleep(long l) { try { TimeUnit.SECONDS.sleep(l); } catch (InterruptedException e) { e.printStackTrace(); } } }
相關推薦
JAVA NIO 伺服器與客戶端實現示例(程式碼1)
公共類: [java] view plain copy print? package com.stevex.app.nio; import java.nio.ByteBuffer; import java.nio.CharBuffer; import j
JAVA NIO 伺服器與客戶端實現示例
公共類: package com.stevex.app.nio; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharacterCodingExcepti
Java NIO 伺服器與客戶端實現檔案下載
import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.chann
Java網路 伺服器與客戶端的簡單通訊
不登高山,不知天之高也。不臨深淵,不知地之厚也。 Java中的封裝類(Socket),在實現這個功能的時候,需要對Java中的Socket套接字的一些用法熟悉,伺服器與客戶端之間主要通過的Java中的IO流通訊。需要理解IO流的流出,流入問題。 接下來,
Android與Java NIO實現簡單Echo伺服器與客戶端
上一篇用Java IO來做了個Demo,於是乎進一步,用Java NIO來做一個。NIO的優勢在於非阻塞。使用了Selector在一個執行緒裡進行輪詢,就能夠完成接入、收\發訊息的操作,不需要每建立一個連線都新啟動一個執行緒的方式。Server端程式碼:public clas
Vue+Java servlet 通過websocket實現伺服器與客戶端雙向通訊
1. vue程式碼 methods: { //在方法裡呼叫 this.websocketsend()傳送資料給伺服器 onConfirm () { //需要傳輸的資料 let data = { cod
JAVA整合WebSocket,實現伺服器與客戶端握手
WebSocket實現伺服器與客戶端握手 自學的WebSocket途中遇到很多坑,希望需要使用的朋友可以少走彎路, 使用的環境:tomcat7.0,mysql,springMvc,spring,M
java Nio 使用 NioSocket 客戶端與服務端互動實現
NioSocket 客戶端與服務端互動實現 java Nio是jdk1.4新增的io方式—–nio(new IO),這種方式在目前來說算不算new,更合適的解釋應該是non-block IO。 non-block是相對於傳統的io
Java實現簡單的Socket伺服器與客戶端字串通訊(適合初學者閱讀)
近段時間,頻繁看到很多學生做畢業設計用到了Socket通訊技術,問題非常多,特寫一個小例子,希望對馬上畢業的同學有所幫助。如果希望學習的更加深入,需要掌握的知識有:面向物件、多執行緒、Socket通訊、IO流、異常處理 伺服器端程式碼: import java
二、Netty實現伺服器與客戶端完整互動連線實戰
本節內容是程式碼實現伺服器與客戶端完整連線過程。整體把控netty的工作流程。我們先不要被某個類,某個api的封裝深入挖掘,這樣你會踩很多坑,陷入進去而拔不出來,後面我會一一講解,原始碼剖析工作原理。這就是我個人學習技術的一種方法,深入淺出
【隨堂筆記】unity開發中Socket的用法(一,實現伺服器與客戶端簡單的連結)
實現了簡單的連結,也增加了客戶端沒有連結到伺服器的自動重連 伺服器程式碼 using System; using System.Net; using System.Net.Sockets; namespace SeverSocket { class Program
搭建FTP伺服器與客戶端(1) - Python實現
FTP背景介紹:FTP(File Transfer Protocol)協議,顧名思義為檔案傳輸協議。由已故的Jon Postel與Joyce Reynolds開發,並於1985年10月釋出。其底層基於TCP/IP協議。FTP目前主要用於匿名下載公共檔案,也可以在兩臺跨系統的計算機之間傳輸檔案。為了實現F
【開發筆記】Unity聯網鬥地主的實現(一,伺服器與客戶端的資料傳遞流程)
話不多說,先上我李老師的思維導圖 大致構思了一個框架 1.首先要定義一下伺服器與客戶端的傳輸協議,必須保持一致 2.定義服務於客戶端傳輸的訊息型別,如(申請加入,同意加入,出牌,之類的) 3.定義一下牌的型別,出的牌的型別,在客戶端判斷是否可以出牌,牌型傳給伺服器,伺服器在完成三個玩家的出
C#.網路程式設計 Socket基礎(一)Socket TCP協議 實現端到端(伺服器與客戶端)簡單字串通訊
簡介: 本章節主要討論了Socket的入門知識,還未針對Socket的難點問題(比如TCP的無訊息邊界問題)展開討論,往後在其他章節中進行研究。 注意點: 伺服器(比如臺式電腦)的IP為1.1.1.2,那麼客戶端(其他裝置,比如手機,Ipad)連線的一定是
C#.網路程式設計 Socket基礎(三) 基於WinForm系統Socket TCP協議 實現端到端(伺服器與客戶端).txt.word.png等不同型別檔案傳輸
一、簡介: 前面的兩篇介紹了字串傳輸、圖片傳輸: 其實,本文針對Socket基礎(二)進一步完成,以便可以進行多種檔案傳輸。 二、基於不同的流(檔案流、記憶體流、網路等)讀寫。 1、圖片傳輸 方法一:(在客戶端用檔案流傳送(即將圖片寫到檔案流去,以便傳送),
Java伺服器與客戶端的通訊中物件流的使用
在使用java物件流的時候,首先要保證通訊雙方各有一個公用的包,裡面的內容相同,注意異常的丟擲。 相同的包 package common; public class User implements
Qt實現伺服器與客戶端傳輸文字和圖片(Qt②)
初學者記錄學習內容,如有錯誤請各位前輩指點。 此次工程完成過程借鑑了下面得兩個帖子,附上鍊接,並致以感謝: qt 寫的tcp客戶端程式實現簡單的連線接受和傳送訊息 qt寫的一個簡單的tcp伺服器程式,可以接受訊息傳送資料 好了閒話少說進入正題。 瞭解C
socket程式設計(一),實現伺服器與客戶端簡單通訊
本節主講客戶端向服務傳送資訊,伺服器轉發給客戶端,當然也可以稍微改一下程式碼可以實現互傳訊息,不再贅述。 難點在於伺服器端的程式碼思路: (1)主程式Socket socket=server.acc
C語言實現基本伺服器與客戶端
伺服器程式碼: #include<sys/socket.h> #include<netinet/in.h> #include<sys/types.h> #include<stdlib.h> #include<stdio
C#Socket通訊基礎(非同步Socket通訊TCP)伺服器與客戶端
一、效果圖 二、伺服器端程式碼(原始碼下載地址:https://download.csdn.net/download/xiaochenxihua/10748789) using System; using System.Collections.Generic; using System