成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Java Socke 探究

Imfan / 588人閱讀

摘要:在設(shè)定時(shí)間內(nèi)接收到相應(yīng)操作的請(qǐng)求則返回可以處理請(qǐng)求的數(shù)量,否則在超時(shí)后返回,程序繼續(xù)執(zhí)行。使用接收請(qǐng)求并處理接收到請(qǐng)求后調(diào)用返回的集合。保存了處理當(dāng)前請(qǐng)求的和,并提供了不同的操作類型。默認(rèn)值為且其值必須小于的值。

Java中的Socket可以分為普通Socket和NioSocket兩種。 普通Socket的用法

Java中的網(wǎng)絡(luò)通信是通過(guò)Socket實(shí)現(xiàn)的,Socket分為ServerSocket和Socket兩大類,ServerSocket用于服務(wù)端,可以通過(guò)accept方法監(jiān)聽請(qǐng)求,監(jiān)聽到請(qǐng)求后返回Socket,Socket用于具體完成數(shù)據(jù)傳輸,客戶端直接使用Socket發(fā)起請(qǐng)求并傳輸數(shù)據(jù)。

一個(gè)簡(jiǎn)單的交互介紹ServerSocket及Socket的使用: 1. 創(chuàng)建ServerSocket。
ServerSocket的構(gòu)造方法一共有5個(gè)。最方便的是傳入一個(gè)端口參數(shù)的方法。
2. 調(diào)用創(chuàng)建出來(lái)的ServerSocket的accept方法進(jìn)行監(jiān)聽
accept方法是阻塞方法,也就是說(shuō)調(diào)用accept方法后程序會(huì)停下來(lái)等待連接請(qǐng)求,在接收到請(qǐng)求之前程序?qū)⒉粫?huì)繼續(xù)執(zhí)行,當(dāng)接收到請(qǐng)求之后,accept方法會(huì)返回一個(gè)Socket。
3. 使用accept方法返回的Socket與客戶端進(jìn)行通信。

服務(wù)端代碼示例:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Server {

    public static void main(String[] args) {

        try {
            //創(chuàng)建一個(gè)ServeSocket,設(shè)置端口為8080
            ServerSocket serverSocket = new ServerSocket(8080);
            //運(yùn)行Socket監(jiān)聽,等待請(qǐng)求  此方法會(huì)阻塞線程,當(dāng)有請(qǐng)求時(shí)才會(huì)繼續(xù)執(zhí)行
            Socket socket = serverSocket.accept();
            //接收到請(qǐng)求之后使用Socket進(jìn)行通信,創(chuàng)建BufferedReader用于讀取請(qǐng)求的數(shù)據(jù)
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            PrintWriter out = new PrintWriter(socket.getOutputStream());
            String line = in.readLine();
            System.out.println(line);
            //創(chuàng)建PrintlnWriter,用于發(fā)送數(shù)據(jù)
            out.println("已經(jīng)接受到了數(shù)據(jù)");
            out.flush();
            System.out.println("Server關(guān)閉" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.sss").format(new Date()));
            //關(guān)閉資源
            out.close();
            in.close();
            socket.close();
            serverSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
    }
}

客戶端代碼示例:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;


/**
 * 客戶端
 * @author sanchan
 */
public class Client {
    public static void main(String[] args) {
        //需要先啟動(dòng)Server否則報(bào)錯(cuò)java.net.ConnectException: Connection refused
        try {
            String msg="你好,ServerSocket!";
            //創(chuàng)建一個(gè)Socket,與本機(jī)8080端口連接
            Socket socket=new Socket("127.0.0.1",8080);
            //使用Socket創(chuàng)建PrintWriter和BufferedReader進(jìn)行數(shù)據(jù)的讀寫
            PrintWriter out=new PrintWriter(socket.getOutputStream());
            out.println(msg);
            out.flush();
            BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String line=in.readLine();
            System.out.println(line);
            //關(guān)閉資源
            in.close();
            out.close();
            socket.close();
            System.out.println("client關(guān)閉"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.sss").format(new Date()));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }
    }
}
NioSocket的使用

nio(new IO)是JDK1.4新增加的IO模式,nio在底層采用了與新的處理方式大大的提高了Java IO的效率。Socket也屬于IO的一種,nio提供了相對(duì)應(yīng)的類:ServerSocketChannel和SocketChannel,分別對(duì)應(yīng)原來(lái)的ServerSocket和Socket。

理解nio三基礎(chǔ): 1. Buffer 2. Channel 3. Selector 小故事里有大智慧:

試想一下如果電商是只要有訂單就派人直接取貨去送貨【這種模式就相當(dāng)于之前的Socket方式】,而不是現(xiàn)在的快遞模式:將貨物統(tǒng)一到中轉(zhuǎn)站,分揀員按照配送范圍分配快遞員,然后快遞員統(tǒng)一送貨【這種模式就相當(dāng)于NioSocket模式】。那么你得多長(zhǎng)時(shí)間收到你得快遞/(ㄒoㄒ)/~~
Buffer就是貨物,Channel就是快遞員,Selector就是中轉(zhuǎn)站的分揀員。

NioSocket使用步驟: 1. 創(chuàng)建ServerSocketChannel并設(shè)置相應(yīng)參數(shù)
SerSocketChannel可以使用自身的靜態(tài)工廠方法open創(chuàng)建。
每個(gè)ServerSocketChannel對(duì)應(yīng)一個(gè)ServerSocket,可以調(diào)用其socket方法來(lái)獲取【不過(guò)如果使用該ServerSocket監(jiān)聽請(qǐng)求就又回到原來(lái)的 普通Socket 模式了,一般只用于使用bind方法綁定端口】。
ServerSocketChannel可以通過(guò)`SelectableChannel configureBlocking(boolean block)` 方法來(lái)設(shè)置是否采用阻塞模式。設(shè)置非阻塞模式之后可以調(diào)用register方法注冊(cè)Selector【阻塞模式不可以使用Selector】
2. 創(chuàng)建Selector并注冊(cè)Selector到ServerSocketChannel上
Selector可以使用自身的靜態(tài)工廠方法open創(chuàng)建。
創(chuàng)建后通過(guò)上面所說(shuō)的Channel的register方法注冊(cè)到ServerSocketChannel或者SocketChannel上。
3.調(diào)用Selector的select方法等待請(qǐng)求
通過(guò)select方法等待請(qǐng)求,select方法可傳入代表最長(zhǎng)等待時(shí)間的long型參數(shù)。在設(shè)定時(shí)間內(nèi)接收到相應(yīng)操作的請(qǐng)求則返回可以處理請(qǐng)求的數(shù)量,否則在超時(shí)后返回0,程序繼續(xù)執(zhí)行。如果傳入0或者使用無(wú)參的重載方法,則會(huì)采用阻塞模式直到有相應(yīng)操作的請(qǐng)求出現(xiàn)。
4. 使用Selector接收請(qǐng)求并處理
接收到請(qǐng)求后Selector調(diào)用selectedKeys返回SelectionKey的Set集合。
5. 使用SelectionKey獲取到Channel、Selector和操作類型并進(jìn)行具體操作。
SelectionKey保存了處理當(dāng)前請(qǐng)求的Channel和Selector,并提供了不同的操作類型。前面提到的Channel注冊(cè)Selector的register方法參數(shù)中第二個(gè)參數(shù)就是SelectionKey定義的。共有四種:
SelectionKey.OP_ACCEPT   //請(qǐng)求操作
SelectionKey.OP_CONNECT  //鏈接操作
SelectionKey.OP_READ     //讀操作
SelectionKey.OP_WRITE    //寫操作

只有在register方法中注冊(cè)了對(duì)應(yīng)的操作Selector才會(huì)關(guān)心相應(yīng)類型操作的請(qǐng)求。

Selector和Channel是多對(duì)多關(guān)系。
Selector是按不同的操作類型進(jìn)行分揀,將分揀結(jié)果保存在SelectionKey中,可分別通過(guò)SelectionKey的channel、selector方法來(lái)獲取對(duì)應(yīng)的Channel和Selector??梢允褂肧electionKey的isAcceptable、isConnectable、isReadable和isWritable方法來(lái)判斷是什么類型的操作。
Buffer是專門用于存儲(chǔ)數(shù)據(jù),有四個(gè)極為重要的屬性:

capacity:容量。
Buffer最多可以保存元素的數(shù)量,創(chuàng)建時(shí)設(shè)置,使用過(guò)程中不可修改。

limit:可以使用的上限。
剛創(chuàng)建Buffer時(shí)limit等于capacity。如果給limit設(shè)置【不能超過(guò)capacity】之后,limit就成了最大可訪問(wèn)的值。

例如,一個(gè)Buffer的capacity為100,表示最多可以保存100個(gè)數(shù)據(jù),只寫入20個(gè)之后就要讀取,在讀取時(shí)limit就會(huì)設(shè)置為20。

position:當(dāng)前所操作元素所在索引位置。
position從0開始,隨著get和put方法自動(dòng)更新。

mark:用來(lái)暫時(shí)保存position的值。
position保存到mark之后就可以修改并進(jìn)行相關(guān)的操作,操作完成后可以通過(guò)reset方法將mark的值恢復(fù)到position。

mark默認(rèn)值為-1,且其值必須小于position的值。
例如,Buffer中一共保存了20個(gè)數(shù)據(jù),position為10,現(xiàn)在想讀取15到20之間的數(shù)據(jù),這時(shí)就可以調(diào)用Buffer的mark方法將目前的position保存到mark中,然后調(diào)用Buffer的position(15)將position指向第15個(gè)元素,這時(shí)就可以讀取。讀取完成之后使用Buffer的reset就可以將position恢復(fù)到10.
如果調(diào)用Buffer的position方法時(shí)傳入的值小于mark當(dāng)前的值,則會(huì)將mark設(shè)為-1。
這四個(gè)屬性大小關(guān)系:mark<=position<=limit<=capacity

我們將前面的普通Socket示例的服務(wù)端改寫一下:

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.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;

/**
 * @author sanchan
 * @since 1.0
 */
public class NIOServer {
    public static void main(String[] args) {
        /**
         * 啟動(dòng)監(jiān)聽
         * 當(dāng)監(jiān)聽到請(qǐng)求時(shí)根據(jù)SelectionKey的操作類型交給內(nèi)部類Handler進(jìn)行處理
         */
        try {
            //創(chuàng)建ServerSocketChannel
            ServerSocketChannel ssc = ServerSocketChannel.open();
            //設(shè)置監(jiān)聽8080端口
            ssc.socket().bind(new InetSocketAddress(8080));
            //設(shè)置為非阻塞模式
            ssc.configureBlocking(false);
            //為ServerSocketChannel注冊(cè)Selector
            Selector selector = Selector.open();
            ssc.register(selector, SelectionKey.OP_ACCEPT);
            //創(chuàng)建Handler
            Handler handler = new Handler(1024);
            while (true) {
                //等待請(qǐng)求,每次等待阻塞3s,超過(guò)3秒后線程繼續(xù)運(yùn)行,如果傳入0或使用無(wú)參重載方法,將一直阻塞
                if (selector.select(3000) == 0) {
                    System.out.println("等待請(qǐng)求超時(shí)~~~~~");
                    continue;
                }
                System.out.println("處理請(qǐng)求~~~~~");
                //獲取等待處理的SelectionKey
                Iterator keyIterator = selector.selectedKeys().iterator();
                while (keyIterator.hasNext()) {
                    SelectionKey key = keyIterator.next();
                    try {
                        //根據(jù)不同請(qǐng)求操作選擇對(duì)應(yīng)的處理方法
                        if (key.isAcceptable()) {
                            handler.handleAccept(key);
                        }
                        if (key.isReadable()) {
                            handler.handleRead(key);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                        //如果異常就說(shuō)明連接結(jié)束,移除
                        keyIterator.remove();
                        continue;
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }

    }

    /**
     * 請(qǐng)求處理類
     */
    private static class Handler {
        private int bufferSize = 1024;
        private String localCharset = "UTF-8";

        public Handler() {
        }

        public Handler(int bufferSize) {
            this(bufferSize, null);
        }

        public Handler(String localCharset) {
            this(-1, localCharset);
        }

        public Handler(int bufferSize, String localCharset) {
            if (bufferSize > 0)
                this.bufferSize = bufferSize;
            if (localCharset != null)
                this.localCharset = localCharset;
        }

        /**
         * 處理請(qǐng)求操作
         *
         * @param key
         * @throws IOException
         */
        public void handleAccept(SelectionKey key) throws IOException {
            //獲取Channel
            SocketChannel sc = ((ServerSocketChannel) key.channel()).accept();
            //設(shè)置非阻塞
            sc.configureBlocking(false);
            //注冊(cè)讀操作的Selector
            sc.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(bufferSize));
        }

        /**
         * 處理讀操作
         *
         * @param key
         * @throws IOException
         */
        public void handleRead(SelectionKey key) throws IOException {
            //獲取Channel
            SocketChannel sc = ((SocketChannel) key.channel());
            //獲取ByteBuffer
            /**
             * Buffer專門用于存儲(chǔ)數(shù)據(jù),有四個(gè)極為重要的屬性:
             * 1. capacity:容量。
             *  Buffer最多可以保存元素的數(shù)量,創(chuàng)建時(shí)設(shè)置,使用過(guò)程中不可修改。
             * 2. limit:可以使用的上限。
             *  剛創(chuàng)建Buffer時(shí)limit等于capacity。如果給limit設(shè)置【不能超過(guò)capacity】之后,limit就成了最大可訪問(wèn)的值。
             *  例如,一個(gè)Buffer的capacity為100,表示最多可以保存100個(gè)數(shù)據(jù),只寫入20個(gè)之后就要讀取,在讀取時(shí)limit就會(huì)設(shè)置為20。
             * 3. position:當(dāng)前所操作元素所在索引位置。
             *  position從0開始,隨著get和put方法自動(dòng)更新。
             * 4. mark:用來(lái)暫時(shí)保存position的值。
             *  position保存到mark之后就可以修改并進(jìn)行相關(guān)的操作,操作完成后可以通過(guò)reset方法將mark的值恢復(fù)到position。
             *  mark默認(rèn)值為-1,且其值必須小于position的值。
             *  例如,Buffer中一共保存了20個(gè)數(shù)據(jù),position為10,現(xiàn)在想讀取15到20之間的數(shù)據(jù),這時(shí)就可以調(diào)用Buffer的mark方法將目前的position保存到mark中,然后調(diào)用Buffer的position(15)將position指向第15個(gè)元素,這時(shí)就可以讀取。讀取完成之后使用Buffer的reset就可以將position恢復(fù)到10.
             *  如果調(diào)用Buffer的position方法時(shí)傳入的值小于mark當(dāng)前的值,則會(huì)將mark設(shè)為-1。
             */
            ByteBuffer buffer = (ByteBuffer) key.attachment();
            //重置ByteBuffer。設(shè)置limit=capacity、position=0、mark=-1
            buffer.clear();
            //沒(méi)有獲取到內(nèi)容則關(guān)閉
            if (sc.read(buffer) == -1) {
                sc.close();
            } else {
                /**
                 * flip()作用:
                 * 在保存數(shù)據(jù)時(shí)保存一個(gè)數(shù)據(jù)position加1,保存完成后要讀取數(shù)據(jù)
                 * 就得設(shè)置limit=position,position=0
                 **/
                buffer.flip();
                //返回?cái)?shù)據(jù)到客戶端
                String receivedString = Charset.forName(localCharset).newDecoder().decode(buffer).toString();
                System.out.println("從客戶端獲取到了數(shù)據(jù):" + receivedString);
                String sendString = "服務(wù)端已經(jīng)獲取到了數(shù)據(jù):" + receivedString;
                buffer = ByteBuffer.wrap(sendString.getBytes(localCharset));
                sc.write(buffer);
                //關(guān)閉SocketChannel
                sc.close();
            }

        }
    }
}
我是廣告

本人的直播課程在 7 月份就要開始了,希望小伙伴們支持一下,現(xiàn)在報(bào)名有優(yōu)惠噢

https://segmentfault.com/l/15...

https://segmentfault.com/l/15...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/67234.html

相關(guān)文章

  • JVM 探究(一):JVM內(nèi)存模型概念模型

    摘要:作為一個(gè)程序員,不了解內(nèi)存模型就不能寫出能夠充分利用內(nèi)存的代碼。程序計(jì)數(shù)器是在電腦處理器中的一個(gè)寄存器,用來(lái)指示電腦下一步要運(yùn)行的指令序列。在虛擬機(jī)中,本地方法棧和虛擬機(jī)棧是共用同一塊內(nèi)存的,不做具體區(qū)分。 作為一個(gè) Java 程序員,不了解 Java 內(nèi)存模型就不能寫出能夠充分利用內(nèi)存的代碼。本文通過(guò)對(duì) Java 內(nèi)存模型的介紹,讓讀者能夠了解 Java 的內(nèi)存的分配情況,適合 Ja...

    cnTomato 評(píng)論0 收藏0
  • 深入探究Java中equals()和==的區(qū)別是什么

    摘要:相等判斷符介紹相等判斷符用于比較基本數(shù)據(jù)類型和引用類型數(shù)據(jù)當(dāng)比較基本數(shù)據(jù)類型的時(shí)候比較的是數(shù)值當(dāng)比較引用類型數(shù)據(jù)時(shí)比較的是引用指針判斷基本類型是否相等首先基本數(shù)據(jù)類型指的是中的八大數(shù)據(jù)類型這八大基本數(shù)據(jù)類型有個(gè)共同的特點(diǎn)是它們?cè)趦?nèi)存中是有具相等判斷符==介紹 ? ==相等判斷符用于比較基本數(shù)據(jù)類型和引用類型數(shù)據(jù). 當(dāng)比較基本數(shù)據(jù)類型的時(shí)候比較的是數(shù)值, 當(dāng)比較引用類型數(shù)據(jù)時(shí)比較的是引用(指...

    liaorio 評(píng)論0 收藏0
  • 深入探究Java中equals()和==的區(qū)別是什么

    摘要:相等判斷符介紹相等判斷符用于比較基本數(shù)據(jù)類型和引用類型數(shù)據(jù)當(dāng)比較基本數(shù)據(jù)類型的時(shí)候比較的是數(shù)值當(dāng)比較引用類型數(shù)據(jù)時(shí)比較的是引用指針判斷基本類型是否相等首先基本數(shù)據(jù)類型指的是中的八大數(shù)據(jù)類型這八大基本數(shù)據(jù)類型有個(gè)共同的特點(diǎn)是它們?cè)趦?nèi)存中是有具相等判斷符==介紹 ==相等判斷符用于比較基本數(shù)據(jù)類型和引用類型數(shù)據(jù). 當(dāng)比較基本數(shù)據(jù)類型的時(shí)候比較的是數(shù)值, 當(dāng)比較引用類型數(shù)據(jù)時(shí)比較的是引用(指針...

    番茄西紅柿 評(píng)論0 收藏0
  • 深入探究Java中equals()和==的區(qū)別是什么

    摘要:相等判斷符介紹相等判斷符用于比較基本數(shù)據(jù)類型和引用類型數(shù)據(jù)當(dāng)比較基本數(shù)據(jù)類型的時(shí)候比較的是數(shù)值當(dāng)比較引用類型數(shù)據(jù)時(shí)比較的是引用指針判斷基本類型是否相等首先基本數(shù)據(jù)類型指的是中的八大數(shù)據(jù)類型這八大基本數(shù)據(jù)類型有個(gè)共同的特點(diǎn)是它們?cè)趦?nèi)存中是有具相等判斷符==介紹 ==相等判斷符用于比較基本數(shù)據(jù)類型和引用類型數(shù)據(jù). 當(dāng)比較基本數(shù)據(jù)類型的時(shí)候比較的是數(shù)值, 當(dāng)比較引用類型數(shù)據(jù)時(shí)比較的是引用(指針...

    番茄西紅柿 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<