亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java Socket編程詳解及示例代碼

 更新時(shí)間:2016年09月05日 16:53:27   作者:技術(shù)小黑屋  
本文主要講解Java Socket編程,這里整理了詳細(xì)的技術(shù)資料及簡(jiǎn)單的示例代碼幫助大家學(xué)習(xí)參考,有需要的小伙伴可以參考下本文內(nèi)容

Socket,又稱為套接字,Socket是計(jì)算機(jī)網(wǎng)絡(luò)通信的基本的技術(shù)之一。如今大多數(shù)基于網(wǎng)絡(luò)的軟件,如瀏覽器,即時(shí)通訊工具甚至是P2P下載都是基于Socket實(shí)現(xiàn)的。本文會(huì)介紹一下基于TCP/IP的Socket編程,并且如何寫(xiě)一個(gè)客戶端/服務(wù)器程序。

餐前甜點(diǎn)

Unix的輸入輸出(IO)系統(tǒng)遵循Open-Read-Write-Close這樣的操作范本。當(dāng)一個(gè)用戶進(jìn)程進(jìn)行IO操作之前,它需要調(diào)用Open來(lái)指定并獲取待操作文件或設(shè)備讀取或?qū)懭氲臋?quán)限。一旦IO操作對(duì)象被打開(kāi),那么這個(gè)用戶進(jìn)程可以對(duì)這個(gè)對(duì)象進(jìn)行一次或多次的讀取或?qū)懭氩僮?。Read操作用來(lái)從IO操作對(duì)象讀取數(shù)據(jù),并將數(shù)據(jù)傳遞給用戶進(jìn)程。Write操作用來(lái)將用戶進(jìn)程中的數(shù)據(jù)傳遞(寫(xiě)入)到IO操作對(duì)象。 當(dāng)所有的Read和Write操作結(jié)束之后,用戶進(jìn)程需要調(diào)用Close來(lái)通知系統(tǒng)其完成對(duì)IO對(duì)象的使用。

在Unix開(kāi)始支持進(jìn)程間通信(InterProcess Communication,簡(jiǎn)稱IPC)時(shí),IPC的接口就設(shè)計(jì)得類(lèi)似文件IO操作接口。在Unix中,一個(gè)進(jìn)程會(huì)有一套可以進(jìn)行讀取寫(xiě)入的IO描述符。IO描述符可以是文件,設(shè)備或者是通信通道(socket套接字)。一個(gè)文件描述符由三部分組成:創(chuàng)建(打開(kāi)socket),讀取寫(xiě)入數(shù)據(jù)(接受和發(fā)送到socket)還有銷(xiāo)毀(關(guān)閉socket)。

在Unix系統(tǒng)中,類(lèi)BSD版本的IPC接口是作為T(mén)CP和UDP協(xié)議之上的一層進(jìn)行實(shí)現(xiàn)的。消息的目的地使用socket地址來(lái)表示。一個(gè)socket地址是由網(wǎng)絡(luò)地址和端口號(hào)組成的通信標(biāo)識(shí)符。

進(jìn)程間通信操作需要一對(duì)兒socket。進(jìn)程間通信通過(guò)在一個(gè)進(jìn)程中的一個(gè)socket與另一個(gè)進(jìn)程中得另一個(gè)socket進(jìn)行數(shù)據(jù)傳輸來(lái)完成。當(dāng)一個(gè)消息執(zhí)行發(fā)出后,這個(gè)消息在發(fā)送端的socket中處于排隊(duì)狀態(tài),直到下層的網(wǎng)絡(luò)協(xié)議將這些消息發(fā)送出去。當(dāng)消息到達(dá)接收端的socket后,其也會(huì)處于排隊(duì)狀態(tài),直到接收端的進(jìn)程對(duì)這條消息進(jìn)行了接收處理。

TCP和UDP通信

關(guān)于socket編程我們有兩種通信協(xié)議可以進(jìn)行選擇。一種是數(shù)據(jù)報(bào)通信,另一種就是流通信。

數(shù)據(jù)報(bào)通信

數(shù)據(jù)報(bào)通信協(xié)議,就是我們常說(shuō)的UDP(User Data Protocol 用戶數(shù)據(jù)報(bào)協(xié)議)。UDP是一種無(wú)連接的協(xié)議,這就意味著我們每次發(fā)送數(shù)據(jù)報(bào)時(shí),需要同時(shí)發(fā)送本機(jī)的socket描述符和接收端的socket描述符。因此,我們?cè)诿看瓮ㄐ艜r(shí)都需要發(fā)送額外的數(shù)據(jù)。

流通信

流通信協(xié)議,也叫做TCP(Transfer Control Protocol,傳輸控制協(xié)議)。和UDP不同,TCP是一種基于連接的協(xié)議。在使用流通信之前,我們必須在通信的一對(duì)兒socket之間建立連接。其中一個(gè)socket作為服務(wù)器進(jìn)行監(jiān)聽(tīng)連接請(qǐng)求。另一個(gè)則作為客戶端進(jìn)行連接請(qǐng)求。一旦兩個(gè)socket建立好了連接,他們可以單向或雙向進(jìn)行數(shù)據(jù)傳輸。

讀到這里,我們多少有這樣的疑問(wèn),我們進(jìn)行socket編程使用UDP還是TCP呢。選擇基于何種協(xié)議的socket編程取決于你的具體的客戶端-服務(wù)器端程序的應(yīng)用場(chǎng)景。下面我們簡(jiǎn)單分析一下TCP和UDP協(xié)議的區(qū)別,或許可以幫助你更好地選擇使用哪種。

在UDP中,每次發(fā)送數(shù)據(jù)報(bào)時(shí),需要附帶上本機(jī)的socket描述符和接收端的socket描述符。而由于TCP是基于連接的協(xié)議,在通信的socket對(duì)之間需要在通信之前建立連接,因此會(huì)有建立連接這一耗時(shí)存在于TCP協(xié)議的socket編程。

在UDP中,數(shù)據(jù)報(bào)數(shù)據(jù)在大小上有64KB的限制。而TCP中也不存在這樣的限制。一旦TCP通信的socket對(duì)建立了連接,他們之間的通信就類(lèi)似IO流,所有的數(shù)據(jù)會(huì)按照接受時(shí)的順序讀取。

UDP是一種不可靠的協(xié)議,發(fā)送的數(shù)據(jù)報(bào)不一定會(huì)按照其發(fā)送順序被接收端的socket接受。然后TCP是一種可靠的協(xié)議。接收端收到的包的順序和包在發(fā)送端的順序是一致的。

簡(jiǎn)而言之,TCP適合于諸如遠(yuǎn)程登錄(rlogin,telnet)和文件傳輸(FTP)這類(lèi)的網(wǎng)絡(luò)服務(wù)。因?yàn)檫@些需要傳輸?shù)臄?shù)據(jù)的大小不確定。而UDP相比TCP更加簡(jiǎn)單輕量一些。UDP用來(lái)實(shí)現(xiàn)實(shí)時(shí)性較高或者丟包不重要的一些服務(wù)。在局域網(wǎng)中UDP的丟包率都相對(duì)比較低。

Java中的socket編程

下面的部分我將通過(guò)一些示例講解一下如何使用socket編寫(xiě)客戶端和服務(wù)器端的程序。

注意:在接下來(lái)的示例中,我將使用基于TCP/IP協(xié)議的socket編程,因?yàn)檫@個(gè)協(xié)議遠(yuǎn)遠(yuǎn)比UDP/IP使用的要廣泛。并且所有的socket相關(guān)的類(lèi)都位于java.net包下,所以在我們進(jìn)行socket編程時(shí)需要引入這個(gè)包。

客戶端編寫(xiě)

開(kāi)啟Socket

如果在客戶端,你需要寫(xiě)下如下的代碼就可以打開(kāi)一個(gè)socket。

String host = "127.0.0.1";
int port = 8919;
Socket client = new Socket(host, port);

上面代碼中,host即客戶端需要連接的機(jī)器,port就是服務(wù)器端用來(lái)監(jiān)聽(tīng)請(qǐng)求的端口。在選擇端口時(shí),需要注意一點(diǎn),就是0~1023這些端口都已經(jīng)被系統(tǒng)預(yù)留了。這些端口為一些常用的服務(wù)所使用,比如郵件,F(xiàn)TP和HTTP。當(dāng)你在編寫(xiě)服務(wù)器端的代碼,選擇端口時(shí),請(qǐng)選擇一個(gè)大于1023的端口。

寫(xiě)入數(shù)據(jù)

接下來(lái)就是寫(xiě)入請(qǐng)求數(shù)據(jù),我們從客戶端的socket對(duì)象中得到OutputStream對(duì)象,然后寫(xiě)入數(shù)據(jù)后。很類(lèi)似文件IO的處理代碼。

public class ClientSocket {
 public static void main(String args[]) {
    String host = "127.0.0.1";
    int port = 8919;
    try {
     Socket client = new Socket(host, port);
     Writer writer = new OutputStreamWriter(client.getOutputStream());
     writer.write("Hello From Client");
     writer.flush();
     writer.close();
     client.close();
    } catch (IOException e) {
     e.printStackTrace();
    }
  }
 
}

關(guān)閉IO對(duì)象

類(lèi)似文件IO,在讀寫(xiě)數(shù)據(jù)完成后,我們需要對(duì)IO對(duì)象進(jìn)行關(guān)閉,以確保資源的正確釋放。

服務(wù)器端編寫(xiě)

打開(kāi)服務(wù)器端的socket

int port = 8919;
ServerSocket server = new ServerSocket(port);
Socket socket = server.accept();

上面的代碼創(chuàng)建了一個(gè)服務(wù)器端的socket,然后調(diào)用accept方法監(jiān)聽(tīng)并獲取客戶端的請(qǐng)求socket。accept方法是一個(gè)阻塞方法,在服務(wù)器端與客戶端之間建立聯(lián)系之前會(huì)一直等待阻塞。

讀取數(shù)據(jù)

通過(guò)上面得到的socket對(duì)象獲取InputStream對(duì)象,然后安裝文件IO一樣讀取數(shù)據(jù)即可。這里我們將內(nèi)容打印出來(lái)。

public class ServerClient {
 public static void main(String[] args) {
    int port = 8919;
    try {
      ServerSocket server = new ServerSocket(port);
        Socket socket = server.accept();
      Reader reader = new InputStreamReader(socket.getInputStream());
      char chars[] = new char[1024];
      int len;
      StringBuilder builder = new StringBuilder();
      while ((len=reader.read(chars)) != -1) {
        builder.append(new String(chars, 0, len));
      }
      System.out.println("Receive from client message=: " + builder);
      reader.close();
      socket.close();
      server.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
 }
}

關(guān)閉IO對(duì)象

還是不能忘記的,最后需要正確地關(guān)閉IO對(duì)象,以確保資源的正確釋放。

附注一個(gè)例子

這里我們?cè)黾右粋€(gè)例子,使用socket實(shí)現(xiàn)一個(gè)回聲服務(wù)器,就是服務(wù)器會(huì)將客戶端發(fā)送過(guò)來(lái)的數(shù)據(jù)傳回給客戶端。代碼很簡(jiǎn)單。

import java.io.*;
import java.net.*;
public class EchoServer {
  public static void main(String args[]) {
    // declaration section:
    // declare a server socket and a client socket for the server
    // declare an input and an output stream
    ServerSocket echoServer = null;
    String line;
    DataInputStream is;
    PrintStream os;
    Socket clientSocket = null;
    // Try to open a server socket on port 9999
    // Note that we can't choose a port less than 1023 if we are not
    // privileged users (root)
    try {
      echoServer = new ServerSocket(9999);
    }
    catch (IOException e) {
      System.out.println(e);
    }
    // Create a socket object from the ServerSocket to listen and accept 
    // connections.
    // Open input and output streams
    try {
        clientSocket = echoServer.accept();
        is = new DataInputStream(clientSocket.getInputStream());
        os = new PrintStream(clientSocket.getOutputStream());
        // As long as we receive data, echo that data back to the client.
        while (true) {
         line = is.readLine();
         os.println(line);
        }
    } catch (IOException e) {
        System.out.println(e);
      }
    }
}

編譯運(yùn)行上面的代碼,進(jìn)行如下請(qǐng)求,就可以看到客戶端請(qǐng)求攜帶的數(shù)據(jù)的內(nèi)容。

15:00 $ curl http://127.0.0.1:9999/?111
GET /?111 HTTP/1.1
User-Agent: curl/7.37.1
Host: 127.0.0.1:9999
Accept: */*

總結(jié)

進(jìn)行客戶端-服務(wù)器端編程還是比較有趣的,同時(shí)在Java中進(jìn)行socket編程要比其他語(yǔ)言(如C)要簡(jiǎn)單快速編寫(xiě)。

java.net這個(gè)包里面包含了很多強(qiáng)大靈活的類(lèi)供開(kāi)發(fā)者進(jìn)行網(wǎng)絡(luò)編程,在進(jìn)行網(wǎng)絡(luò)編程中,建議使用這個(gè)包下面的API。同時(shí)Sun.*這個(gè)包也包含了很多的網(wǎng)絡(luò)編程相關(guān)的類(lèi),但是不建議使用這個(gè)包下面的API,因?yàn)檫@個(gè)包可能會(huì)改變,另外這個(gè)包不能保證在所有的平臺(tái)都有包含。

以上就是對(duì)Java Socket資料的整理,后續(xù)繼續(xù)補(bǔ)充相關(guān)知識(shí),謝謝大家對(duì)本站的支持!

相關(guān)文章

  • java多線程抓取鈴聲多多官網(wǎng)的鈴聲數(shù)據(jù)

    java多線程抓取鈴聲多多官網(wǎng)的鈴聲數(shù)據(jù)

    很容易就能發(fā)現(xiàn)通過(guò)改變 listId和page就能從服務(wù)器獲取鈴聲的json數(shù)據(jù), 通過(guò)解析json數(shù)據(jù), 可以看到都帶有{"hasmore":1,"curpage":1}這樣子的指示,通過(guò)判斷hasmore的值,決定是否進(jìn)行下一頁(yè)的抓取。 但是通過(guò)上面這個(gè)鏈接返回的json中不帶有鈴聲的下載地址
    2016-04-04
  • java控制臺(tái)實(shí)現(xiàn)拼圖游戲

    java控制臺(tái)實(shí)現(xiàn)拼圖游戲

    這篇文章主要為大家詳細(xì)介紹了java控制臺(tái)實(shí)現(xiàn)拼圖游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • Servlet實(shí)現(xiàn)點(diǎn)擊計(jì)數(shù)器的方法

    Servlet實(shí)現(xiàn)點(diǎn)擊計(jì)數(shù)器的方法

    這篇文章主要介紹了Servlet實(shí)現(xiàn)點(diǎn)擊計(jì)數(shù)器的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-08-08
  • 詳解使用Spring Security OAuth 實(shí)現(xiàn)OAuth 2.0 授權(quán)

    詳解使用Spring Security OAuth 實(shí)現(xiàn)OAuth 2.0 授權(quán)

    本篇文章主要介紹了詳解使用Spring Security OAuth 實(shí)現(xiàn)OAuth 2.0 授權(quán),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-01-01
  • 實(shí)例解析Java設(shè)計(jì)模式編程中的適配器模式使用

    實(shí)例解析Java設(shè)計(jì)模式編程中的適配器模式使用

    本篇文章主要通過(guò)實(shí)例對(duì)適配器模式進(jìn)行了詳解,需要的朋友可以參考下
    2017-04-04
  • mybatis使用xml進(jìn)行增刪改查代碼解析

    mybatis使用xml進(jìn)行增刪改查代碼解析

    這篇文章主要介紹了mybatis使用xml進(jìn)行增刪改查代碼解析,分享了相關(guān)配置和代碼示例,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-02-02
  • Java中的this、super、final關(guān)鍵字詳解

    Java中的this、super、final關(guān)鍵字詳解

    這篇文章主要介紹了Java中的this、super、final關(guān)鍵字詳解,它在方法內(nèi)部使用,表示這個(gè)方法所屬對(duì)象的引用,它在構(gòu)造器內(nèi)部使用,表示該構(gòu)造器正在初始化的對(duì)象,this 可以調(diào)用類(lèi)的屬性、方法和構(gòu)造器,需要的朋友可以參考下
    2023-09-09
  • Java常用JVM參數(shù)實(shí)戰(zhàn)

    Java常用JVM參數(shù)實(shí)戰(zhàn)

    本文主要介紹了Java常用JVM參數(shù)實(shí)戰(zhàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • Mybatis關(guān)聯(lián)查詢遇到的坑-無(wú)主鍵的關(guān)聯(lián)數(shù)據(jù)去重問(wèn)題

    Mybatis關(guān)聯(lián)查詢遇到的坑-無(wú)主鍵的關(guān)聯(lián)數(shù)據(jù)去重問(wèn)題

    這篇文章主要介紹了Mybatis關(guān)聯(lián)查詢遇到的坑-無(wú)主鍵的關(guān)聯(lián)數(shù)據(jù)去重問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • MybatisPlus中QueryWrapper常用方法總結(jié)

    MybatisPlus中QueryWrapper常用方法總結(jié)

    MyBatis-Plus是一個(gè)Mybatis增強(qiáng)版工具,在MyBatis上擴(kuò)充了其他功能沒(méi)有改變其基本功能,為了簡(jiǎn)化開(kāi)發(fā)提交效率而存在,queryWrapper是mybatis plus中實(shí)現(xiàn)查詢的對(duì)象封裝操作類(lèi),本文就給大家總結(jié)了MybatisPlus中QueryWrapper的常用方法,需要的朋友可以參考下
    2023-07-07

最新評(píng)論