ServerSocket詳解

在客戶/服務(wù)器通信模式中,服務(wù)器端需要創(chuàng)建監(jiān)聽特定端口的ServerSocket擅笔,ServerSocket負責接收客戶連接請求险胰,并生成與客戶端連接的Socket汹押。

1、構(gòu)造ServerSocket

ServerSocket的構(gòu)造方法有以下幾種重載形式:

  • ServerSocket()throws IOException
  • ServerSocket(int port) throws IOException
  • ServerSocket(int port, int backlog) throws IOException
  • ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException

在以上構(gòu)造方法中起便,參數(shù)port指定服務(wù)器要綁定的端口(服務(wù)器要監(jiān)聽的端口)鲸阻,參數(shù)backlog指定客戶連接請求隊列的長度,參數(shù)bindAddr指定服務(wù)器要綁定的IP地址缨睡。

1.1 鸟悴、綁定端口

除不帶參數(shù)的構(gòu)造方法以外,其他構(gòu)造方法都會使服務(wù)器與特定端口綁定奖年,該端口由參數(shù)port指定细诸。如果端口被其他服務(wù)進程占用,或是陋守,在某些系統(tǒng)中震贵,若沒有以超級用戶身份運行服務(wù)器程序,操作系統(tǒng)不允許服務(wù)器綁定到1-1023的端口時水评,會拋出BindException猩系。

1.2、設(shè)定客戶連接請求隊列的長度

當服務(wù)器進程運行時中燥,可能會同時監(jiān)聽到多個客戶的連接請求寇甸。管理客戶端連接請求的任務(wù)是由操作系統(tǒng)來完成的。操作系統(tǒng)將連接請求存儲在一個先進先出隊列中。許多操作系統(tǒng)限定了隊列的最大長度拿霉,一般為50吟秩。當隊列中的連接請求達到了隊列的最大容量時,服務(wù)器進程所在的主機會拒絕新的連接請求绽淘。只有當服務(wù)器進程通過ServerSocket的accept()方法從隊列中取出連接請求涵防,使隊列騰出空位時,隊列才能繼續(xù)加入新的連接請求沪铭。

對于客戶進程壮池,如果它發(fā)出的連接請求被加入到服務(wù)器的隊列中,就意味著客戶與服務(wù)器的連接建立成功杀怠,客戶進程從Socket構(gòu)造方法中正常返回火窒。如果客戶進程發(fā)出的連接請求被服務(wù)器拒絕,Socket構(gòu)造方法就會拋出ConnectionException驮肉。

ServerSocket構(gòu)造方法的backlog參數(shù)用來顯式設(shè)置連接請求隊列的長度,它將覆蓋操作系統(tǒng)限定的隊列的最大長度已骇。

在一下集中情況离钝,仍然采用操作系統(tǒng)限定的隊列最大長度:

  • backlog參數(shù)的值大于操作系統(tǒng)限定的隊列的最大長度;
  • backlog參數(shù)的值小于或等于0褪储;
  • 在ServerSocket構(gòu)造方法中沒有設(shè)置backlog參數(shù)卵渴。

1.3、設(shè)定綁定的IP地址

若主機只有一個地址鲤竹,則服務(wù)器默認綁定該地址浪读;若主機有多個地址,則可以調(diào)用ServerSocket(int port, int backlog, InetAddress bindAddr)構(gòu)造方法設(shè)置主機ip地址辛藻。

1.4碘橘、默認構(gòu)造方法的作用

ServerSocket有一個不帶參數(shù)的默認構(gòu)造方法。通過該方法創(chuàng)建的ServerSocket不與任何端口綁定吱肌,接下來還需要通過bind()方法與特定端口綁定痘拆。

這個默認構(gòu)造方法的用途是,允許服務(wù)器在綁定到特定端口之前氮墨,先設(shè)置ServerSocket的一些選項纺蛆。因為一旦服務(wù)器與特定端口綁定,有些選項就不能再改變了规揪。

2桥氏、接收和關(guān)閉與客戶的連接

ServerSocket的accept()方法從連接請求隊列中取出一個客戶的連接請求,然后創(chuàng)建與客戶連接的Socket對象猛铅,并將它返回字支。如果隊列中沒有連接請求,accept()方法就會一直等待,直到接收到了連接請求才返回祥款。

服務(wù)器從Socket對象中獲得輸入流和輸出流

清笨,就能與客戶交換數(shù)據(jù)。當服務(wù)器正在進行發(fā)送數(shù)據(jù)的操作時刃跛,如果客戶端斷開了連接抠艾,那么服務(wù)器端會拋出一個IOException的子類SocketException異常:java.net.SocketException: Connection reset by peer。

3桨昙、關(guān)閉ServerSocket

ServerSocket的close()方法使服務(wù)器釋放占用的端口检号,并且斷開與所有客戶的連接。當一個服務(wù)器程序運行結(jié)束時蛙酪,即使沒有執(zhí)行ServerSocket的close()方法齐苛,操作系統(tǒng)也會釋放這個服務(wù)器占用的端口。因此桂塞,服務(wù)器程序并不一定要在結(jié)束之前執(zhí)行ServerSocket的close()方法凹蜂。

在某些情況下,如果希望及時釋放服務(wù)器的端口阁危,以便讓其他程序能占用該端口玛痊,則可以顯式調(diào)用ServerSocket的close()方法。

ServerSocket的isClosed()方法判斷ServerSocket是否關(guān)閉狂打,只有執(zhí)行了ServerSocket的close()方法擂煞,isClosed()方法才返回true;否則趴乡,即使ServerSocket還沒有和特定端口綁定对省,isClosed()方法也會返回false。

ServerSocket的isBound()方法判斷ServerSocket是否已經(jīng)與一個端口綁定晾捏,只要ServerSocket已經(jīng)與一個端口綁定蒿涎,即使它已經(jīng)被關(guān)閉,isBound()方法也會返回true惦辛。

4同仆、獲取ServerSocket的信息

  • public InetAddress getInetAddress():獲取服務(wù)器綁定的ip地址;
  • public int getLocalPort():獲取服務(wù)器綁定的端口裙品;

在構(gòu)造ServerSocket時俗批,如果把端口設(shè)為0,那么將由操作系統(tǒng)為服務(wù)器分配一個端口(稱為匿名端口)市怎,程序只要調(diào)用getLocalPort()方法就能獲知這個端口號岁忘。多數(shù)服務(wù)器會監(jiān)聽固定的端口,這樣才便于客戶程序訪問服務(wù)器区匠。匿名端口一般適用于服務(wù)器與客戶之間的臨時通信干像,通信結(jié)束帅腌,就斷開連接,并且ServerSocket占用的臨時端口也被釋放麻汰。

5速客、ServerSocket選項

ServerSocket有以下3個選項。

  • SO_TIMEOUT:表示等待客戶連接的超時時間五鲫。
  • SO_REUSEADDR:表示是否允許重用服務(wù)器所綁定的地址溺职。
  • SO_RCVBUF:表示接收數(shù)據(jù)的緩沖區(qū)的大小。

5.1位喂、SO_TIMEOUT選項

  • 設(shè)置該選項:public void setSoTimeout(int timeout) throws SocketException
  • 讀取該選項:public int getSoTimeout () throws IOException

SO_TIMEOUT表示ServerSocket的accept()方法等待客戶連接的超時時間浪耘,以毫秒為單位。 如果SO_TIMEOUT的值為0塑崖,表示永遠不會超時七冲,這是SO_TIMEOUT的默認值。

當服務(wù)器執(zhí)行ServerSocket的accept()方法時规婆,如果連接請求隊列為空澜躺,服務(wù)器就會一直等待,直到接收到了客戶連接才從accept()方法返回抒蚜。如果設(shè)定了超時時間掘鄙,那么當服務(wù)器等待的時間超過了超時時間,就會拋出SocketTimeoutException削锰,它是InterruptedException的子類。

5.2毕莱、SO_REUSEADDR選項

  • 設(shè)置該選項:public void setResuseAddress(boolean on) throws SocketException
  • 讀取該選項:public boolean getResuseAddress() throws SocketException

這個選項與Socket的SO_REUSEADDR選項相同器贩,用于決定如果網(wǎng)絡(luò)上仍然有數(shù)據(jù)向舊的ServerSocket傳輸數(shù)據(jù),是否允許新的ServerSocket綁定到與舊的ServerSocket同樣的端口上朋截。SO_REUSEADDR選項的默認值與操作系統(tǒng)有關(guān)蛹稍,在某些操作系統(tǒng)中,允許重用端口部服,而在某些操作系統(tǒng)中不允許重用端口唆姐。

當ServerSocket關(guān)閉時,如果網(wǎng)絡(luò)上還有發(fā)送到這個ServerSocket的數(shù)據(jù)廓八,這個ServerSocket不會立刻釋放本地端口奉芦,而是會等待一段時間,確保接收到了網(wǎng)絡(luò)上發(fā)送過來的延遲數(shù)據(jù)剧蹂,然后再釋放端口

許多服務(wù)器程序都使用固定的端口声功。當服務(wù)器程序關(guān)閉后,有可能它的端口還會被占用一段時間宠叼,如果此時立刻在同一個主機上重啟服務(wù)器程序先巴,由于端口已經(jīng)被占用,使得服務(wù)器程序無法綁定到該端口,服務(wù)器啟動失敗伸蚯,并拋出BindException摩渺。

為了確保一個進程關(guān)閉了ServerSocket后,即使操作系統(tǒng)還沒釋放端口剂邮,同一個主機上的其他進程還可以立刻重用該端口摇幻,可以調(diào)用ServerSocket.setResuseAddress(true)方法

5.3、SO_RCVBUF選項

  • 設(shè)置該選項:public void setReceiveBufferSize(int size) throws SocketException
  • 讀取該選項:public int getReceiveBufferSize() throws SocketException

SO_RCVBUF表示服務(wù)器端的用于接收數(shù)據(jù)的緩沖區(qū)的大小抗斤,以字節(jié)為單位囚企。一般說來,傳輸大的連續(xù)的數(shù)據(jù)塊(基于HTTP或FTP協(xié)議的數(shù)據(jù)傳輸)可以使用較大的緩沖區(qū)瑞眼,這可以減少傳輸數(shù)據(jù)的次數(shù)龙宏,從而提高傳輸數(shù)據(jù)的效率。而對于交互式的通信(Telnet和網(wǎng)絡(luò)游戲)伤疙,則應(yīng)該采用小的緩沖區(qū)银酗,確保能及時把小批量的數(shù)據(jù)發(fā)送給對方。

5.4徒像、設(shè)定連接時間黍特、延遲和帶寬的相對重要性

public void setPerformancePreferences(int connectionTime,int latency,int bandwidth)

該方法的作用與Socket的setPerformancePreferences()方法的作用相同,用于設(shè)定連接時間锯蛀、延遲和帶寬的相對重要性灭衷。

6、創(chuàng)建多線程服務(wù)器

許多實際應(yīng)用要求服務(wù)器具有同時為多個客戶提供服務(wù)的能力旁涤。HTTP服務(wù)器就是最明顯的例子翔曲。任何時刻,HTTP服務(wù)器都可能接收到大量的客戶請求劈愚,每個客戶都希望能快速得到HTTP服務(wù)器的響應(yīng)瞳遍。如果長時間讓客戶等待,會使網(wǎng)站失去信譽菌羽,從而降低訪問量掠械。

可以用并發(fā)性能來衡量一個服務(wù)器同時響應(yīng)多個客戶的能力。一個具有好的并發(fā)性能的服務(wù)器注祖,必須符合兩個條件:

  • 能同時接收并處理多個客戶連接猾蒂;
  • 對于每個客戶,都會迅速給予響應(yīng)是晨。

用多個線程來同時為多個客戶提供服務(wù)婚夫,這是提高服務(wù)器的并發(fā)性能的最常用的手段。

以下將按照3中方式來實現(xiàn)EchoServer署鸡,它們都使用多線程案糙。

  • 為每個客戶分配一個工作線程限嫌。
  • 創(chuàng)建一個線程池,由其中的工作線程來為客戶服務(wù)时捌。
  • 利用JDK的Java類庫中現(xiàn)成的線程池怒医,由它的工作線程來為客戶服務(wù)。

6.1奢讨、 為每個客戶分配一個線程

服務(wù)器的主線程負責接收客戶的連接稚叹,每次接收到一個客戶連接,就會創(chuàng)建一個工作線程拿诸,由它負責與客戶的通信扒袖。

代碼示例:

public static void start(){
  try{
    ServerSocket serverSocket = new ServerSocket(PORT);
    System.out.println("server listen on port:" + PORT);
    while (true){
      try {
        Socket client = serverSocket.accept();
        System.out.println("receive client connect, localPort=" + client.getPort());
        new Thread(new EchoServer.HandlerServer(client)).start();
      }catch (Exception e){
        System.out.println("client exception,e=" + e.getMessage());
      }
    }
  }catch(Exception e){
    System.out.println("server exception,e=" + e.getMessage());
  }
}

以上工作線程執(zhí)行HandlerServer的run()方法,其負責與單個客戶端通信亩码,通信完畢后斷開連接季率,線程自然終止。

6.2描沟、創(chuàng)建線程池

對每個客戶都分配一個新的工作線程飒泻。當工作線程與客戶通信結(jié)束,這個線程就被銷毀吏廉。這種實現(xiàn)方式有以下不足之處:

  • 服務(wù)器創(chuàng)建和銷毀工作線程的開銷(包括所花費的時間和系統(tǒng)資源)很大泞遗。如果服務(wù)器需要與許多客戶通信,并且與每個客戶的通信時間都很短席覆,那么有可能服務(wù)器為客戶創(chuàng)建新線程的開銷比實際與客戶通信的開銷還要大史辙。
  • 除了創(chuàng)建和銷毀線程的開銷之外,活動的線程也消耗系統(tǒng)資源佩伤。每個線程本身都會占用一定的內(nèi)存(每個線程需要大約1M內(nèi)存)聊倔,如果同時有大量客戶連接服務(wù)器,就必須創(chuàng)建大量工作線程畦戒,它們消耗了大量內(nèi)存方库,可能會導(dǎo)致系統(tǒng)的內(nèi)存空間不足结序。
  • 如果線程數(shù)目固定障斋,并且每個線程都有很長的生命周期,那么線程切換也是相對固定的徐鹤。不同操作系統(tǒng)有不同的切換周期垃环,一般在20毫秒左右。這里所說的線程切換是指在Java虛擬機返敬,以及底層操作系統(tǒng)的調(diào)度下遂庄,線程之間轉(zhuǎn)讓CPU的使用權(quán)。如果頻繁創(chuàng)建和銷毀線程劲赠,那么將導(dǎo)致頻繁地切換線程涛目,因為一個線程被銷毀后秸谢,必然要把CPU轉(zhuǎn)讓給另一個已經(jīng)就緒的線程,使該線程獲得運行機會霹肝。在這種情況下估蹄,線程之間的切換不再遵循系統(tǒng)的固定切換周期,切換線程的開銷甚至比創(chuàng)建及銷毀線程的開銷還大沫换。

線程池為線程生命周期開銷問題和系統(tǒng)資源不足問題提供了解決方案臭蚁。線程池中預(yù)先創(chuàng)建了一些工作線程,它們不斷從工作隊列中取出任務(wù)讯赏,然后執(zhí)行該任務(wù)垮兑。當工作線程執(zhí)行完一個任務(wù)時,就會繼續(xù)執(zhí)行工作隊列中的下一個任務(wù)漱挎。線程池具有以下優(yōu)點

  • 減少了創(chuàng)建和銷毀線程的次數(shù)系枪,每個工作線程都可以一直被重用,能執(zhí)行多個任務(wù)识樱。
  • 可以根據(jù)系統(tǒng)的承載能力嗤无,方便地調(diào)整線程池中線程的數(shù)目,防止因為消耗過量系統(tǒng)資源而導(dǎo)致系統(tǒng)崩潰怜庸。

6.3当犯、使用JDK類庫提供的線程池

java.util.concurrent包提供了現(xiàn)成的線程池的實現(xiàn),其比自己實現(xiàn)的線程池更加健壯割疾,且功能也更加強大嚎卫。

Executor接口繼承圖.png

Executor接口表示線程池,它的execute(Runnable task)方法用來執(zhí)行Runnable類型的任務(wù)宏榕。Executor的子接口ExecutorService中聲明了管理線程池的一些方法拓诸,比如用于關(guān)閉線程池的shutdown()方法等。Executors類中包含一些靜態(tài)方法麻昼,它們負責生成各種類型的線程池ExecutorService實例奠支。


Executors類的靜態(tài)方法.png

6.4、使用線程池注意事項

雖然線程池能大大提高服務(wù)器的并發(fā)性能抚芦,但使用它也會存在一定風險倍谜。與所有多線程應(yīng)用程序一樣,用線程池構(gòu)建的應(yīng)用程序容易產(chǎn)生各種并發(fā)問題叉抡,如對共享資源的競爭和死鎖尔崔。此外,如果線程池本身的實現(xiàn)不健壯褥民,或者沒有合理地使用線程池季春,還容易導(dǎo)致與線程池有關(guān)的死鎖、系統(tǒng)資源不足和線程泄漏等問題消返。

6.4.1载弄、死鎖

任何多線程應(yīng)用程序都有死鎖風險耘拇。造成死鎖的最簡單的情形是,線程A持有對象X的鎖宇攻,并且在等待對象Y的鎖驼鞭,而線程B持有對象Y的鎖,并且在等待對象X的鎖尺碰。線程A與線程B都不釋放自己持有的鎖挣棕,并且等待對方的鎖,這就導(dǎo)致兩個線程永遠等待下去亲桥,死鎖就這樣產(chǎn)生了洛心。

雖然任何多線程程序都有死鎖的風險,但線程池還會導(dǎo)致另外一種死鎖题篷。在這種情形下词身,假定線程池中的所有工作線程都在執(zhí)行各自任務(wù)時被阻塞,它們都在等待某個任務(wù)A的執(zhí)行結(jié)果番枚。而任務(wù)A依然在工作隊列中法严,由于沒有空閑線程,使得任務(wù)A一直不能被執(zhí)行葫笼。這使得線程池中的所有工作線程都永遠阻塞下去深啤,死鎖就這樣產(chǎn)生了。

6.4.2路星、系統(tǒng)資源不足

如果線程池中的線程數(shù)目非常多溯街,這些線程會消耗包括內(nèi)存和其他系統(tǒng)資源在內(nèi)的大量資源,從而嚴重影響系統(tǒng)性能洋丐。

6.4.3.并發(fā)錯誤

線程池的工作隊列依靠wait()和notify()方法來使工作線程及時取得任務(wù)呈昔,但這兩個方法都難于使用。

如果編碼不正確友绝,可能會丟失通知堤尾,導(dǎo)致工作線程一直保持空閑狀態(tài),無視工作隊列中需要處理的任務(wù)迁客。因此使用這些方法時郭宝,必須格外小心,即便是專家也可能在這方面出錯哲泊。最好使用現(xiàn)有的剩蟀、比較成熟的線程池催蝗。例如切威,直接使用java.util.concurrent包中的線程池類。

6.4.4.線程泄漏

使用線程池的一個嚴重風險是線程泄漏丙号。對于工作線程數(shù)目固定的線程池先朦,如果工作線程在執(zhí)行任務(wù)時拋出RuntimeException 或Error缰冤,并且這些異常或錯誤沒有被捕獲喳魏,那么這個工作線程就會異常終止棉浸,使得線程池永久失去了一個工作線程。如果所有的工作線程都異常終止刺彩,線程池就最終變?yōu)榭彰灾#瑳]有任何可用的工作線程來處理任務(wù)。

導(dǎo)致線程泄漏的另一種情形是创倔,工作線程在執(zhí)行一個任務(wù)時被阻塞嗡害,如等待用戶的輸入數(shù)據(jù),但是由于用戶一直不輸入數(shù)據(jù)(可能是因為用戶走開了)畦攘,導(dǎo)致這個工作線程一直被阻塞霸妹。這樣的工作線程名存實亡,它實際上不執(zhí)行任何任務(wù)了知押。假如線程池中所有的工作線程都處于這樣的阻塞狀態(tài)叹螟,那么線程池就無法處理新加入的任務(wù)了。

6.4.5.任務(wù)過載

當工作隊列中有大量排隊等候執(zhí)行的任務(wù)時台盯,這些任務(wù)本身可能會消耗太多的系統(tǒng)資源而引起系統(tǒng)資源缺乏罢绽。

綜上所述,線程池可能會帶來種種風險静盅,為了盡可能避免它們有缆,使用線程池時需要遵循以下原則。

(1)如果任務(wù)A在執(zhí)行過程中需要同步等待任務(wù)B的執(zhí)行結(jié)果温亲,那么任務(wù)A不適合加入到線程池的工作隊列中棚壁。如果把像任務(wù)A一樣的需要等待其他任務(wù)執(zhí)行結(jié)果的任務(wù)加入到工作隊列中,可能會導(dǎo)致線程池的死鎖栈虚。

(2)如果執(zhí)行某個任務(wù)時可能會阻塞袖外,并且是長時間的阻塞,則應(yīng)該設(shè)定超時時間魂务,避免工作線程永久的阻塞下去而導(dǎo)致線程泄漏曼验。在服務(wù)器程序中,當線程等待客戶連接粘姜,或者等待客戶發(fā)送的數(shù)據(jù)時鬓照,都可能會阻塞」陆簦可以通過以下方式設(shè)定超時時間:

◆調(diào)用ServerSocket的setSoTimeout(int timeout)方法豺裆,設(shè)定等待客戶連接的超時時間;

◆對于每個與客戶連接的Socket,調(diào)用該Socket的setSoTimeout(int timeout)方法臭猜,設(shè)定等待客戶發(fā)送數(shù)據(jù)的超時時間躺酒。

(3)了解任務(wù)的特點,分析任務(wù)是執(zhí)行經(jīng)常會阻塞的I/O操作蔑歌,還是執(zhí)行一直不會阻塞的運算操作羹应。前者時斷時續(xù)地占用CPU,而后者對CPU具有更高的利用率次屠。預(yù)計完成任務(wù)大概需要多長時間园匹?是短時間任務(wù)還是長時間任務(wù)?

根據(jù)任務(wù)的特點劫灶,對任務(wù)進行分類偎肃,然后把不同類型的任務(wù)分別加入到不同線程池的工作隊列中,這樣可以根據(jù)任務(wù)的特點浑此,分別調(diào)整每個線程池累颂。

(4)調(diào)整線程池的大小。線程池的最佳大小主要取決于系統(tǒng)的可用CPU的數(shù)目凛俱,以及工作隊列中任務(wù)的特點紊馏。假如在一個具有 N 個CPU的系統(tǒng)上只有一個工作隊列,并且其中全部是運算性質(zhì)(不會阻塞)的任務(wù)蒲犬,那么當線程池具有 N 或 N+1 個工作線程時朱监,一般會獲得最大的 CPU 利用率。

如果工作隊列中包含會執(zhí)行I/O操作并常常阻塞的任務(wù)原叮,則要讓線程池的大小超過可用CPU的數(shù)目赫编,因為并不是所有工作線程都一直在工作。選擇一個典型的任務(wù)奋隶,然后估計在執(zhí)行這個任務(wù)的過程中擂送,等待時間(WT)與實際占用CPU進行運算的時間(ST)之間的比例WT/ST。對于一個具有N個CPU的系統(tǒng)唯欣,需要設(shè)置大約N×(1+WT/ST)個線程來保證CPU得到充分利用嘹吨。

當然,CPU利用率不是調(diào)整線程池大小過程中唯一要考慮的事項境氢。隨著線程池中工作線程數(shù)目的增長蟀拷,還會碰到內(nèi)存或者其他系統(tǒng)資源的限制,如套接字萍聊、打開的文件句柄或數(shù)據(jù)庫連接數(shù)目等问芬。要保證多線程消耗的系統(tǒng)資源在系統(tǒng)的承載范圍之內(nèi)。

(5)避免任務(wù)過載寿桨。服務(wù)器應(yīng)根據(jù)系統(tǒng)的承載能力此衅,限制客戶并發(fā)連接的數(shù)目印蔬。當客戶并發(fā)連接的數(shù)目超過了限制值挖诸,服務(wù)器可以拒絕連接請求驮捍,并友好地告知客戶:服務(wù)器正忙叁温,請稍后再試漠畜。

相關(guān)閱讀:
Socket詳解 【http://www.reibang.com/p/5a294e08efbc

參考博客:

http://expert.51cto.com/art/200702/40196_all.htm

https://blog.csdn.net/lin49940/article/details/4398364

參考書籍:

孫衛(wèi)琴 《java網(wǎng)絡(luò)編程精解》

代碼示例:

https://github.com/zhaozhou11/java-io.git

com.zhaozhou.demo.serversocket包

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末粤铭,一起剝皮案震驚了整個濱河市渡八,隨后出現(xiàn)的幾起案子迂求,更是在濱河造成了極大的恐慌默伍,老刑警劉巖欢嘿,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異也糊,居然都是意外死亡炼蹦,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門狸剃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來掐隐,“玉大人,你說我怎么就攤上這事钞馁÷鞘。” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵僧凰,是天一觀的道長探颈。 經(jīng)常有香客問我,道長训措,這世上最難降的妖魔是什么伪节? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮绩鸣,結(jié)果婚禮上怀大,老公的妹妹穿的比我還像新娘。我一直安慰自己呀闻,他們只是感情好叉寂,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著总珠,像睡著了一般屏鳍。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上局服,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天钓瞭,我揣著相機與錄音,去河邊找鬼淫奔。 笑死山涡,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播鸭丛,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼竞穷,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了鳞溉?” 一聲冷哼從身側(cè)響起瘾带,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎熟菲,沒想到半個月后看政,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡抄罕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年允蚣,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片呆贿。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡嚷兔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出做入,到底是詐尸還是另有隱情谴垫,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布母蛛,位于F島的核電站翩剪,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏彩郊。R本人自食惡果不足惜前弯,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望秫逝。 院中可真熱鬧恕出,春花似錦、人聲如沸违帆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽刷后。三九已至的畴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間尝胆,已是汗流浹背丧裁。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留含衔,地道東北人煎娇。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓二庵,卻偏偏與公主長得像,于是被迫代替她去往敵國和親缓呛。 傳聞我的和親對象是個殘疾皇子催享,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 對于即時類應(yīng)用或者即時類的游戲,HTTP協(xié)議很多時候無法滿足于我們的需求哟绊。這會因妙,Socket對于我們來說就非常實用...
    育樹凌峰閱讀 1,996評論 0 1
  • Java知識點1、==和equals的區(qū)別基本類型比較==比較內(nèi)容 equals比較地址值引用類型比較==比較地址...
    壓抑的內(nèi)心閱讀 592評論 0 0
  • 多線程匿情、特別是NSOperation 和 GCD 的內(nèi)部原理兰迫。運行時機制的原理和運用場景信殊。SDWebImage的原...
    LZM輪回閱讀 2,007評論 0 12
  • ———————————————回答好下面的足夠了---------------------------------...
    恒愛DE問候閱讀 1,716評論 0 4
  • 最全的iOS面試題及答案 iOS面試小貼士 ———————————————回答好下面的足夠了-----------...
    zweic閱讀 2,699評論 0 73