国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Java Socke 探究

Imfan / 578人閱讀

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

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

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

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

服務(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)建一個ServeSocket,設(shè)置端口為8080
            ServerSocket serverSocket = new ServerSocket(8080);
            //運行Socket監(jiān)聽,等待請求  此方法會阻塞線程,當(dāng)有請求時才會繼續(xù)執(zhí)行
            Socket socket = serverSocket.accept();
            //接收到請求之后使用Socket進行通信,創(chuàng)建BufferedReader用于讀取請求的數(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) {
        //需要先啟動Server否則報錯java.net.ConnectException: Connection refused
        try {
            String msg="你好,ServerSocket!";
            //創(chuàng)建一個Socket,與本機8080端口連接
            Socket socket=new Socket("127.0.0.1",8080);
            //使用Socket創(chuàng)建PrintWriter和BufferedReader進行數(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提供了相對應(yīng)的類:ServerSocketChannel和SocketChannel,分別對應(yīng)原來的ServerSocket和Socket。

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

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

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

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

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

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

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

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

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

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

mark默認值為-1,且其值必須小于position的值。
例如,Buffer中一共保存了20個數(shù)據(jù),position為10,現(xiàn)在想讀取15到20之間的數(shù)據(jù),這時就可以調(diào)用Buffer的mark方法將目前的position保存到mark中,然后調(diào)用Buffer的position(15)將position指向第15個元素,這時就可以讀取。讀取完成之后使用Buffer的reset就可以將position恢復(fù)到10.
如果調(diào)用Buffer的position方法時傳入的值小于mark當(dāng)前的值,則會將mark設(shè)為-1。
這四個屬性大小關(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) {
        /**
         * 啟動監(jiān)聽
         * 當(dāng)監(jiān)聽到請求時根據(jù)SelectionKey的操作類型交給內(nèi)部類Handler進行處理
         */
        try {
            //創(chuàng)建ServerSocketChannel
            ServerSocketChannel ssc = ServerSocketChannel.open();
            //設(shè)置監(jiān)聽8080端口
            ssc.socket().bind(new InetSocketAddress(8080));
            //設(shè)置為非阻塞模式
            ssc.configureBlocking(false);
            //為ServerSocketChannel注冊Selector
            Selector selector = Selector.open();
            ssc.register(selector, SelectionKey.OP_ACCEPT);
            //創(chuàng)建Handler
            Handler handler = new Handler(1024);
            while (true) {
                //等待請求,每次等待阻塞3s,超過3秒后線程繼續(xù)運行,如果傳入0或使用無參重載方法,將一直阻塞
                if (selector.select(3000) == 0) {
                    System.out.println("等待請求超時~~~~~");
                    continue;
                }
                System.out.println("處理請求~~~~~");
                //獲取等待處理的SelectionKey
                Iterator keyIterator = selector.selectedKeys().iterator();
                while (keyIterator.hasNext()) {
                    SelectionKey key = keyIterator.next();
                    try {
                        //根據(jù)不同請求操作選擇對應(yīng)的處理方法
                        if (key.isAcceptable()) {
                            handler.handleAccept(key);
                        }
                        if (key.isReadable()) {
                            handler.handleRead(key);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                        //如果異常就說明連接結(jié)束,移除
                        keyIterator.remove();
                        continue;
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }

    }

    /**
     * 請求處理類
     */
    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;
        }

        /**
         * 處理請求操作
         *
         * @param key
         * @throws IOException
         */
        public void handleAccept(SelectionKey key) throws IOException {
            //獲取Channel
            SocketChannel sc = ((ServerSocketChannel) key.channel()).accept();
            //設(shè)置非阻塞
            sc.configureBlocking(false);
            //注冊讀操作的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專門用于存儲數(shù)據(jù),有四個極為重要的屬性:
             * 1. capacity:容量。
             *  Buffer最多可以保存元素的數(shù)量,創(chuàng)建時設(shè)置,使用過程中不可修改。
             * 2. limit:可以使用的上限。
             *  剛創(chuàng)建Buffer時limit等于capacity。如果給limit設(shè)置【不能超過capacity】之后,limit就成了最大可訪問的值。
             *  例如,一個Buffer的capacity為100,表示最多可以保存100個數(shù)據(jù),只寫入20個之后就要讀取,在讀取時limit就會設(shè)置為20。
             * 3. position:當(dāng)前所操作元素所在索引位置。
             *  position從0開始,隨著get和put方法自動更新。
             * 4. mark:用來暫時保存position的值。
             *  position保存到mark之后就可以修改并進行相關(guān)的操作,操作完成后可以通過reset方法將mark的值恢復(fù)到position。
             *  mark默認值為-1,且其值必須小于position的值。
             *  例如,Buffer中一共保存了20個數(shù)據(jù),position為10,現(xiàn)在想讀取15到20之間的數(shù)據(jù),這時就可以調(diào)用Buffer的mark方法將目前的position保存到mark中,然后調(diào)用Buffer的position(15)將position指向第15個元素,這時就可以讀取。讀取完成之后使用Buffer的reset就可以將position恢復(fù)到10.
             *  如果調(diào)用Buffer的position方法時傳入的值小于mark當(dāng)前的值,則會將mark設(shè)為-1。
             */
            ByteBuffer buffer = (ByteBuffer) key.attachment();
            //重置ByteBuffer。設(shè)置limit=capacity、position=0、mark=-1
            buffer.clear();
            //沒有獲取到內(nèi)容則關(guān)閉
            if (sc.read(buffer) == -1) {
                sc.close();
            } else {
                /**
                 * flip()作用:
                 * 在保存數(shù)據(jù)時保存一個數(shù)據(jù)position加1,保存完成后要讀取數(shù)據(jù)
                 * 就得設(shè)置limit=position,position=0
                 **/
                buffer.flip();
                //返回數(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)在報名有優(yōu)惠噢

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

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

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

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/67234.html

相關(guān)文章

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

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

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

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

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

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

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

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

    番茄西紅柿 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<