最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java實(shí)現(xiàn)基于UDP協(xié)議網(wǎng)絡(luò)Socket編程(C/S通信)

 更新時(shí)間:2020年10月29日 10:14:19   作者:Charzous  
這篇文章主要介紹了java實(shí)現(xiàn)基于UDP協(xié)議網(wǎng)絡(luò)Socket編程(C/S通信),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

一、前言:認(rèn)識(shí)UDP

UDP,全稱User Datagram Protocol(用戶數(shù)據(jù)報(bào)協(xié)議),是Internet 協(xié)議集支持一個(gè)無(wú)連接的傳輸協(xié)議。UDP 為應(yīng)用程序提供了一種無(wú)需建立連接就可以發(fā)送封裝的 IP 數(shù)據(jù)包的方法。

UDP主要用于不要求分組順序到達(dá)的傳輸中,分組傳輸順序的檢查與排序由應(yīng)用層完成,提供面向報(bào)文的簡(jiǎn)單不可靠信息傳送服務(wù)。UDP 協(xié)議基本上是IP協(xié)議與上層協(xié)議的接口,適用端口分別運(yùn)行在同一臺(tái)設(shè)備上的多個(gè)應(yīng)用程序。

二、UDP的特點(diǎn)(與TCP相比)

正是UDP提供不可靠服務(wù),具有了TCP所沒(méi)有的優(yōu)勢(shì)。無(wú)連接使得它具有資源消耗小,處理速度快的優(yōu)點(diǎn),所以音頻、視頻和普通數(shù)據(jù)在傳送時(shí)經(jīng)常使用UDP,偶爾丟失一兩個(gè)數(shù)據(jù)包,也不會(huì)對(duì)接收結(jié)果產(chǎn)生太大影響。

UDP有別于TCP,有自己獨(dú)立的套接字(IP+Port),它們的端口號(hào)不沖突。和TCP編程相比,UDP在使用前不需要進(jìn)行連接,沒(méi)有流的概念。

如果說(shuō)TCP協(xié)議通信與電話通信類似,那么UDP通信就與郵件通信類似:不需要實(shí)時(shí)連接,只需要目的地址;

UDP通信前不需要建立連接,只要知道地址(ip地址和端口號(hào))就可以給對(duì)方發(fā)送信息;

基于用戶數(shù)據(jù)報(bào)文(包)讀寫(xiě);

UDP通信一般用于線路質(zhì)量好的環(huán)境,如局域網(wǎng)內(nèi),如果是互聯(lián)網(wǎng),往往應(yīng)用于對(duì)數(shù)據(jù)完整性不是過(guò)于苛刻的場(chǎng)合,例如語(yǔ)音傳送等。

以上是對(duì)UDP的基本認(rèn)識(shí),與以前學(xué)習(xí)的理論相比,接下來(lái)的實(shí)踐更加有趣,實(shí)踐出真知。

三、UDP網(wǎng)絡(luò)Socket編程(Java實(shí)現(xiàn))

首先,熟悉java中UDP編程的幾個(gè)關(guān)鍵類:DatagramSocket(套接字類),DatagramPacket(數(shù)據(jù)報(bào)類),MulticastSocket。本篇主要使用前兩個(gè)。

1、創(chuàng)建客戶端

第一步,實(shí)例化一個(gè)數(shù)據(jù)報(bào)套接字,用于與服務(wù)器端進(jìn)行通信。與TCP不同,UDP中只有DatagramSocket一種套接字,不區(qū)分服務(wù)端和客戶端,創(chuàng)建的時(shí)候并不需要指定目的地址,這也是TCP協(xié)議和UDP協(xié)議最大的不同點(diǎn)之一。

public UDPClient(String remoteIP,String remotePort) throws IOException{
    this.remoteIP=InetAddress.getByName(remoteIP);
    this.remotePort=Integer.parseInt(remotePort);
    //創(chuàng)建UDP套接字,系統(tǒng)隨機(jī)選定一個(gè)未使用的UDP端口綁定
    socket=new DatagramSocket();
}

第二步, 創(chuàng)建UDP數(shù)據(jù)報(bào),實(shí)現(xiàn)發(fā)送和接收數(shù)據(jù)的方法。UDP發(fā)送數(shù)據(jù)是基于報(bào)文DatagramPacket,網(wǎng)絡(luò)中傳遞的UDP數(shù)據(jù)都要封裝在這種自包含的報(bào)文中。

實(shí)現(xiàn)DatagramPacket發(fā)送數(shù)據(jù)的方法:

//定義一個(gè)數(shù)據(jù)的發(fā)送方法
public void send(String msg){
  try {
    //將待發(fā)送的字符串轉(zhuǎn)為字節(jié)數(shù)組
    byte[] outData=msg.getBytes("utf-8");
    //構(gòu)建用于發(fā)送的數(shù)據(jù)報(bào)文,構(gòu)造方法中傳入遠(yuǎn)程通信方(服務(wù)器)的ip地址和端口
    DatagramPacket outPacket=new DatagramPacket(outData,outData.length,remoteIP,remotePort);
    //給UDP發(fā)送數(shù)據(jù)報(bào)
    socket.send(outPacket);
  }catch (IOException e){
      e.printStackTrace();
   }
}

 DatagramPacket接收數(shù)據(jù)的方法:

//定義一個(gè)數(shù)據(jù)的發(fā)送方法
public void send(String msg){
  try {
    //將待發(fā)送的字符串轉(zhuǎn)為字節(jié)數(shù)組
    byte[] outData=msg.getBytes("utf-8");
    //構(gòu)建用于發(fā)送的數(shù)據(jù)報(bào)文,構(gòu)造方法中傳入遠(yuǎn)程通信方(服務(wù)器)的ip地址和端口
    DatagramPacket outPacket=new DatagramPacket(outData,outData.length,remoteIP,remotePort);
    //給UDP發(fā)送數(shù)據(jù)報(bào)
    socket.send(outPacket);
  }catch (IOException e){
      e.printStackTrace();
   }
}

 可以看到,發(fā)送和接收數(shù)據(jù)中使用DatagramSocket的實(shí)例的send和receive方法,這就是數(shù)據(jù)報(bào)套接字的兩個(gè)重要方法。

通信結(jié)束,銷毀Socket的方法如下:

public void close(){
  if (socket!=null)
    socket.close();
}

 到這里,客戶端已全部完成,等待接下來(lái)與服務(wù)端的通信...

2、客戶端圖形界面

現(xiàn)在,設(shè)計(jì)客戶端通信的簡(jiǎn)單界面,一方面可以更方便的和服務(wù)器連續(xù)對(duì)話通信,另一方面,有了圖形界面,體驗(yàn)感更加!圖形化界面主要使用JavaFX實(shí)現(xiàn),代碼容易看懂。

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.io.IOException;


public class UDPClientFX extends Application {

  private Button btnExit=new Button("退出");
  private Button btnSend = new Button("發(fā)送");

  private TextField tfSend=new TextField();//輸入信息區(qū)域

  private TextArea taDisplay=new TextArea();//顯示區(qū)域
  private TextField ipAddress=new TextField();//填寫(xiě)ip地址
  private TextField tfport=new TextField();//填寫(xiě)端口
  private Button btConn=new Button("連接");
  private UDPClient UDPClient;

  private String ip;
  private String port;


  @Override
  public void start(Stage primaryStage) {
    BorderPane mainPane=new BorderPane();

    //連接服務(wù)器區(qū)域
    HBox hBox1=new HBox();
    hBox1.setSpacing(10);
    hBox1.setPadding(new Insets(10,20,10,20));
    hBox1.setAlignment(Pos.CENTER);
    hBox1.getChildren().addAll(new Label("ip地址:"),ipAddress,new Label("端口:"),tfport,btConn);
    mainPane.setTop(hBox1);

    VBox vBox=new VBox();
    vBox.setSpacing(10);

    vBox.setPadding(new Insets(10,20,10,20));
    vBox.getChildren().addAll(new Label("信息顯示區(qū)"),taDisplay,new Label("信息輸入?yún)^(qū)"),tfSend);

    VBox.setVgrow(taDisplay, Priority.ALWAYS);
    mainPane.setCenter(vBox);


    HBox hBox=new HBox();
    hBox.setSpacing(10);
    hBox.setPadding(new Insets(10,20,10,20));
    hBox.setAlignment(Pos.CENTER_RIGHT);
    hBox.getChildren().addAll(btnSend,btnExit);
    mainPane.setBottom(hBox);

    Scene scene =new Scene(mainPane,700,500);
    primaryStage.setScene(scene);
    primaryStage.show();

    //連接服務(wù)器之前,發(fā)送bye后禁用發(fā)送按鈕,禁用Enter發(fā)送信息輸入?yún)^(qū)域,禁用下載按鈕
    btnSend.setDisable(true);
    tfSend.setDisable(true);

    //連接按鈕
    btConn.setOnAction(event -> {
      ip=ipAddress.getText().trim();
      port=tfport.getText().trim();

      try {
        UDPClient = new UDPClient(ip,port);
        //連接服務(wù)器之后未結(jié)束服務(wù)前禁用再次連接
        btConn.setDisable(true);
        //重新連接服務(wù)器時(shí)啟用輸入發(fā)送功能
        tfSend.setDisable(false);
        btnSend.setDisable(false);
      } catch (IOException e) {
        e.printStackTrace();
      }
    });

    //發(fā)送按鈕事件
    btnSend.setOnAction(event -> {
      String msg=tfSend.getText();
      UDPClient.send(msg);//向服務(wù)器發(fā)送一串字符
      taDisplay.appendText("客戶端發(fā)送:"+msg+"\n");

      String Rmsg=null;
      Rmsg=UDPClient.receive();
//      System.out.println(Rmsg);
      taDisplay.appendText(Rmsg+"\n");

      if (msg.equals("bye")){
        btnSend.setDisable(true);//發(fā)送bye后禁用發(fā)送按鈕
        tfSend.setDisable(true);//禁用Enter發(fā)送信息輸入?yún)^(qū)域
        //結(jié)束服務(wù)后再次啟用連接按鈕
        btConn.setDisable(false);
      }
      tfSend.clear();
    });
    //對(duì)輸入?yún)^(qū)域綁定鍵盤(pán)事件
    tfSend.setOnKeyPressed(new EventHandler<KeyEvent>() {
      @Override
      public void handle(KeyEvent event) {
        if(event.getCode()==KeyCode.ENTER){
          String msg=tfSend.getText();
          UDPClient.send(msg);//向服務(wù)器發(fā)送一串字符
          taDisplay.appendText("客戶端發(fā)送:"+msg+"\n");


          String Rmsg=null;
          Rmsg=UDPClient.receive();
          taDisplay.appendText(Rmsg+"\n");

          if (msg.equals("bye")){
            tfSend.setDisable(true);//禁用Enter發(fā)送信息輸入?yún)^(qū)域
            btnSend.setDisable(true);//發(fā)送bye后禁用發(fā)送按鈕
            //結(jié)束服務(wù)后再次啟用連接按鈕
            btConn.setDisable(false);
          }
          tfSend.clear();
        }
      }
    });
    
    btnExit.setOnAction(event -> {
      try {
        exit();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }

    });
    //窗體關(guān)閉響應(yīng)的事件,點(diǎn)擊右上角的×關(guān)閉,客戶端也關(guān)閉
    primaryStage.setOnCloseRequest(event -> {
      try {
        exit();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    });


    //信息顯示區(qū)鼠標(biāo)拖動(dòng)高亮文字直接復(fù)制到信息輸入框,方便選擇文件名
    //taDispaly為信息選擇區(qū)的TextArea,tfSend為信息輸入?yún)^(qū)的TextField
    //為taDisplay的選擇范圍屬性添加監(jiān)聽(tīng)器,當(dāng)該屬性值變化(選擇文字時(shí)),會(huì)觸發(fā)監(jiān)聽(tīng)器中的代碼
    taDisplay.selectionProperty().addListener(((observable, oldValue, newValue) -> {
      //只有當(dāng)鼠標(biāo)拖動(dòng)選中了文字才復(fù)制內(nèi)容
      if(!taDisplay.getSelectedText().equals(""))
        tfSend.setText(taDisplay.getSelectedText());
    }));
  }

  private void exit() throws InterruptedException {
    if (UDPClient!=null){
      //向服務(wù)器發(fā)送關(guān)閉連接的約定信息
      UDPClient.send("bye");
      UDPClient.close();
    }
    System.exit(0);
  }

  
  public static void main (String[] args) {
      launch(args);
  }
}

重點(diǎn)在各個(gè)控件的事件處理邏輯上,需避免要一些誤操作導(dǎo)致異常拋出,如:連接服務(wù)器前禁用發(fā)送按鈕,在連接服務(wù)器成功后禁用連接按鈕,禁用輸入?yún)^(qū)等。另外,實(shí)現(xiàn)了回車發(fā)送的快捷功能,詳見(jiàn)代碼的鍵盤(pán)事件綁定部分。

還有,約定發(fā)送"bye"或者退出按鈕結(jié)束通信關(guān)閉Socket。

成功連接后:

3、創(chuàng)建服務(wù)器端

服務(wù)器端為客戶端提供服務(wù),實(shí)現(xiàn)通信。這里包括了幾個(gè)方法Service(),udpSend()和udpReceive().

首先,我將UDP數(shù)據(jù)報(bào)發(fā)送和接收寫(xiě)成一個(gè)方法,作為整體方便多次調(diào)用。

public DatagramPacket udpReceive() throws IOException {
  DatagramPacket receive;
  byte[] dataR = new byte[1024];
  receive = new DatagramPacket(dataR, dataR.length);
  socket.receive(receive);
  return receive;
}

public void udpSend(String msg,InetAddress ipRemote,int portRemote) throws IOException {
  DatagramPacket sendPacket;
  byte[] dataSend = msg.getBytes();
  sendPacket = new DatagramPacket(dataSend,dataSend.length,ipRemote,portRemote);
  socket.send(sendPacket);
}

 與TCP的Socket通信不同,需要將數(shù)據(jù)轉(zhuǎn)化成字節(jié)數(shù)據(jù)形式,封裝成數(shù)據(jù)報(bào)進(jìn)行傳輸,接收時(shí)解析數(shù)據(jù)為字節(jié),再進(jìn)行讀取。

服務(wù)器端核心部分為Service()方法,實(shí)例化一個(gè)DatagramSocket類套接字,實(shí)現(xiàn)循環(huán)與客戶端的通信。

與客戶端約定的結(jié)束標(biāo)志"bye"進(jìn)行處理,結(jié)束對(duì)話。

public DatagramPacket udpReceive() throws IOException {
  DatagramPacket receive;
  byte[] dataR = new byte[1024];
  receive = new DatagramPacket(dataR, dataR.length);
  socket.receive(receive);
  return receive;
}

public void udpSend(String msg,InetAddress ipRemote,int portRemote) throws IOException {
  DatagramPacket sendPacket;
  byte[] dataSend = msg.getBytes();
  sendPacket = new DatagramPacket(dataSend,dataSend.length,ipRemote,portRemote);
  socket.send(sendPacket);
}

四、服務(wù)器端和客戶端完整代碼

服務(wù)器端:

public DatagramPacket udpReceive() throws IOException {
  DatagramPacket receive;
  byte[] dataR = new byte[1024];
  receive = new DatagramPacket(dataR, dataR.length);
  socket.receive(receive);
  return receive;
}

public void udpSend(String msg,InetAddress ipRemote,int portRemote) throws IOException {
  DatagramPacket sendPacket;
  byte[] dataSend = msg.getBytes();
  sendPacket = new DatagramPacket(dataSend,dataSend.length,ipRemote,portRemote);
  socket.send(sendPacket);
}

客戶端:

//UDPClient.java

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class UDPClient {
  private int remotePort;
  private InetAddress remoteIP;
  private DatagramSocket socket;
  //用于接收數(shù)據(jù)的報(bào)文字節(jié)數(shù)組緩存最最大容量,字節(jié)為單位
  private static final int MAX_PACKET_SIZE=512;

  public UDPClient(String remoteIP,String remotePort) throws IOException{
    this.remoteIP=InetAddress.getByName(remoteIP);
    this.remotePort=Integer.parseInt(remotePort);
    //創(chuàng)建UDP套接字,系統(tǒng)隨機(jī)選定一個(gè)未使用的UDP端口綁定
    socket=new DatagramSocket();

  }

  //定義一個(gè)數(shù)據(jù)的發(fā)送方法
  public void send(String msg){
    try {
      //將待發(fā)送的字符串轉(zhuǎn)為字節(jié)數(shù)組
      byte[] outData=msg.getBytes("utf-8");
      //構(gòu)建用于發(fā)送的數(shù)據(jù)報(bào)文,構(gòu)造方法中傳入遠(yuǎn)程通信方(服務(wù)器)的ip地址和端口
      DatagramPacket outPacket=new DatagramPacket(outData,outData.length,remoteIP,remotePort);
      //給UDP發(fā)送數(shù)據(jù)報(bào)
      socket.send(outPacket);
    }catch (IOException e){
      e.printStackTrace();
    }
  }

  public String receive(){
    String msg;
    //準(zhǔn)備空的數(shù)據(jù)報(bào)文
    DatagramPacket inPacket=new DatagramPacket(new byte[MAX_PACKET_SIZE],MAX_PACKET_SIZE);
    try {
      //讀取報(bào)文,阻塞語(yǔ)句,有數(shù)據(jù)就裝包在inPacket報(bào)文中,以裝完或裝滿為止
      socket.receive(inPacket);
      //將接收到的字節(jié)數(shù)組轉(zhuǎn)為對(duì)應(yīng)的字符串
      msg=new String(inPacket.getData(),0,inPacket.getLength(),"utf-8");
    } catch (IOException e) {
      e.printStackTrace();
      msg=null;
    }
    return msg;
  }

  public void close(){
    if (socket!=null)
      socket.close();
  }
}

五、效果展示

六、總結(jié)

這一篇詳細(xì)記錄學(xué)習(xí)運(yùn)用java進(jìn)行網(wǎng)絡(luò)編程,基于UDP套接字(Socket)實(shí)現(xiàn)服務(wù)器與客戶端間的通信,在實(shí)戰(zhàn)案例中更深刻理解UDP的實(shí)現(xiàn)原理,掌握UDP實(shí)踐應(yīng)用步驟。

起初完成UDP通信時(shí),遇到了幾個(gè)問(wèn)題,相比較TCP的實(shí)現(xiàn),確實(shí)體會(huì)到數(shù)據(jù)傳輸?shù)倪^(guò)程的不同,UDP服務(wù)和客戶端共用了一個(gè)DatagramSocket,另外需要DatagramPacket數(shù)據(jù)報(bào)的協(xié)作。另外,UDP沒(méi)有數(shù)據(jù)流的概念,所以讀寫(xiě)不同于TCP,需要以字節(jié)數(shù)據(jù)進(jìn)行讀取。

到此這篇關(guān)于java實(shí)現(xiàn)基于UDP協(xié)議網(wǎng)絡(luò)Socket編程(C/S通信)的文章就介紹到這了,更多相關(guān)java UDP協(xié)議Socket編程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中文亂碼解決方案全解析,讓你的程序“說(shuō)人話”!

    Java中文亂碼解決方案全解析,讓你的程序“說(shuō)人話”!

    探索Java中文亂碼解決方案全解析,讓你的程序終于能“說(shuō)人話”!厭倦了看著一串串的問(wèn)號(hào)或者奇怪符號(hào)嗎?跟著我們的指南,一步步輕松解鎖中文亂碼的秘密,讓你的代碼清晰表達(dá)每一個(gè)字,需要的朋友可以參考下
    2024-02-02
  • java中對(duì)HashMap的put過(guò)程解讀

    java中對(duì)HashMap的put過(guò)程解讀

    這篇文章主要介紹了java中對(duì)HashMap的put過(guò)程解讀,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • jar包的各種啟動(dòng)方式超詳細(xì)總結(jié)

    jar包的各種啟動(dòng)方式超詳細(xì)總結(jié)

    jar文件是一種軟件包文件格式,通常用于聚合大量的JAVA類文件,以jar為文件擴(kuò)展名,下面這篇文章主要給大家介紹了關(guān)于jar包的各種啟動(dòng)方式,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-04-04
  • 詳解SpringBoot的事務(wù)管理

    詳解SpringBoot的事務(wù)管理

    Springboot內(nèi)部提供的事務(wù)管理器是根據(jù)autoconfigure來(lái)進(jìn)行決定的。接下來(lái)通過(guò)本文給大家介紹SpringBoot的事務(wù)管理相關(guān)知識(shí),感興趣的朋友一起學(xué)習(xí)吧
    2017-04-04
  • 詳解如何在SpringBoot中優(yōu)雅地重試調(diào)用第三方API

    詳解如何在SpringBoot中優(yōu)雅地重試調(diào)用第三方API

    作為后端程序員,我們的日常工作就是調(diào)用一些第三方服務(wù),將數(shù)據(jù)存入數(shù)據(jù)庫(kù),返回信息給前端。本文為大家介紹了如何在SpringBoot中優(yōu)雅地重試調(diào)用第三方API,需要的可以參考一下
    2022-12-12
  • SpringBoot熱部署Springloaded實(shí)現(xiàn)過(guò)程解析

    SpringBoot熱部署Springloaded實(shí)現(xiàn)過(guò)程解析

    這篇文章主要介紹了SpringBoot熱部署Springloaded實(shí)現(xiàn)過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • springboot與數(shù)據(jù)庫(kù)返回?cái)?shù)據(jù)中文亂碼

    springboot與數(shù)據(jù)庫(kù)返回?cái)?shù)據(jù)中文亂碼

    大家好,本篇文章主要講的是springboot與數(shù)據(jù)庫(kù)返回?cái)?shù)據(jù)中文亂碼,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽
    2022-01-01
  • Java8 HashMap鍵與Comparable接口小結(jié)

    Java8 HashMap鍵與Comparable接口小結(jié)

    這篇文章主要介紹了Java8 HashMap鍵與Comparable接口小結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • 使用SpringMVC返回json字符串的實(shí)例講解

    使用SpringMVC返回json字符串的實(shí)例講解

    下面小編就為大家分享一篇使用SpringMVC返回json字符串的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03
  • Java設(shè)計(jì)模式之初識(shí)行為型模式

    Java設(shè)計(jì)模式之初識(shí)行為型模式

    今天帶大家學(xué)習(xí)Java設(shè)計(jì)模式的相關(guān)知識(shí)點(diǎn),文中對(duì)Java行為型模式做了非常詳細(xì)的介紹及代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們很有幫助,需要的朋友可以參考下
    2021-06-06

最新評(píng)論

榆树市| 兴安盟| 晋江市| 阳山县| 交口县| 高清| 甘德县| 抚顺市| 广灵县| 乌拉特前旗| 阳西县| 赫章县| 鄂州市| 中卫市| 共和县| 措美县| 西峡县| 扬州市| 社会| 合川市| 广德县| 房产| 紫云| 高密市| 柏乡县| 汶川县| 娄烦县| 扎鲁特旗| 乐山市| 双鸭山市| 林西县| 惠安县| 双牌县| 时尚| 怀柔区| 凤城市| 五大连池市| 紫云| 故城县| 吴桥县| 泗洪县|