亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

java實現基于UDP協議網絡Socket編程的方法

發布時間:2020-10-31 01:20:15 來源:億速云 閱讀:499 作者:Leah 欄目:開發技術

這篇文章運用簡單易懂的例子給大家介紹java實現基于UDP協議網絡Socket編程的方法,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

一、前言:認識UDP

UDP,全稱User Datagram Protocol(用戶數據報協議),是Internet 協議集支持一個無連接的傳輸協議。UDP 為應用程序提供了一種無需建立連接就可以發送封裝的 IP 數據包的方法。

UDP主要用于不要求分組順序到達的傳輸中,分組傳輸順序的檢查與排序由應用層完成,提供面向報文的簡單不可靠信息傳送服務。UDP 協議基本上是IP協議與上層協議的接口,適用端口分別運行在同一臺設備上的多個應用程序。

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

正是UDP提供不可靠服務,具有了TCP所沒有的優勢。無連接使得它具有資源消耗小,處理速度快的優點,所以音頻、視頻和普通數據在傳送時經常使用UDP,偶爾丟失一兩個數據包,也不會對接收結果產生太大影響。

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

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

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

基于用戶數據報文(包)讀寫;

UDP通信一般用于線路質量好的環境,如局域網內,如果是互聯網,往往應用于對數據完整性不是過于苛刻的場合,例如語音傳送等。

以上是對UDP的基本認識,與以前學習的理論相比,接下來的實踐更加有趣,實踐出真知。

三、UDP網絡Socket編程(Java實現)

首先,熟悉java中UDP編程的幾個關鍵類:DatagramSocket(套接字類),DatagramPacket(數據報類),MulticastSocket。本篇主要使用前兩個。

1、創建客戶端

第一步,實例化一個數據報套接字,用于與服務器端進行通信。與TCP不同,UDP中只有DatagramSocket一種套接字,不區分服務端和客戶端,創建的時候并不需要指定目的地址,這也是TCP協議和UDP協議最大的不同點之一。

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

第二步, 創建UDP數據報,實現發送和接收數據的方法。UDP發送數據是基于報文DatagramPacket,網絡中傳遞的UDP數據都要封裝在這種自包含的報文中。

實現DatagramPacket發送數據的方法:

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

 DatagramPacket接收數據的方法:

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

 可以看到,發送和接收數據中使用DatagramSocket的實例的send和receive方法,這就是數據報套接字的兩個重要方法。

通信結束,銷毀Socket的方法如下:

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

 到這里,客戶端已全部完成,等待接下來與服務端的通信...

2、客戶端圖形界面

現在,設計客戶端通信的簡單界面,一方面可以更方便的和服務器連續對話通信,另一方面,有了圖形界面,體驗感更加!圖形化界面主要使用JavaFX實現,代碼容易看懂。

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("發送");

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

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

  private String ip;
  private String port;


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

    //連接服務器區域
    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("信息顯示區"),taDisplay,new Label("信息輸入區"),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();

    //連接服務器之前,發送bye后禁用發送按鈕,禁用Enter發送信息輸入區域,禁用下載按鈕
    btnSend.setDisable(true);
    tfSend.setDisable(true);

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

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

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

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

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


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

          if (msg.equals("bye")){
            tfSend.setDisable(true);//禁用Enter發送信息輸入區域
            btnSend.setDisable(true);//發送bye后禁用發送按鈕
            //結束服務后再次啟用連接按鈕
            btConn.setDisable(false);
          }
          tfSend.clear();
        }
      }
    });
    
    btnExit.setOnAction(event -> {
      try {
        exit();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }

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


    //信息顯示區鼠標拖動高亮文字直接復制到信息輸入框,方便選擇文件名
    //taDispaly為信息選擇區的TextArea,tfSend為信息輸入區的TextField
    //為taDisplay的選擇范圍屬性添加監聽器,當該屬性值變化(選擇文字時),會觸發監聽器中的代碼
    taDisplay.selectionProperty().addListener(((observable, oldValue, newValue) -> {
      //只有當鼠標拖動選中了文字才復制內容
      if(!taDisplay.getSelectedText().equals(""))
        tfSend.setText(taDisplay.getSelectedText());
    }));
  }

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

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

重點在各個控件的事件處理邏輯上,需避免要一些誤操作導致異常拋出,如:連接服務器前禁用發送按鈕,在連接服務器成功后禁用連接按鈕,禁用輸入區等。另外,實現了回車發送的快捷功能,詳見代碼的鍵盤事件綁定部分。

還有,約定發送"bye"或者退出按鈕結束通信關閉Socket。

java實現基于UDP協議網絡Socket編程的方法

成功連接后:

java實現基于UDP協議網絡Socket編程的方法

3、創建服務器端

服務器端為客戶端提供服務,實現通信。這里包括了幾個方法Service(),udpSend()和udpReceive().

首先,我將UDP數據報發送和接收寫成一個方法,作為整體方便多次調用。

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通信不同,需要將數據轉化成字節數據形式,封裝成數據報進行傳輸,接收時解析數據為字節,再進行讀取。

服務器端核心部分為Service()方法,實例化一個DatagramSocket類套接字,實現循環與客戶端的通信。

與客戶端約定的結束標志"bye"進行處理,結束對話。

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);
}

四、服務器端和客戶端完整代碼

服務器端:

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;
  //用于接收數據的報文字節數組緩存最最大容量,字節為單位
  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);
    //創建UDP套接字,系統隨機選定一個未使用的UDP端口綁定
    socket=new DatagramSocket();

  }

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

  public String receive(){
    String msg;
    //準備空的數據報文
    DatagramPacket inPacket=new DatagramPacket(new byte[MAX_PACKET_SIZE],MAX_PACKET_SIZE);
    try {
      //讀取報文,阻塞語句,有數據就裝包在inPacket報文中,以裝完或裝滿為止
      socket.receive(inPacket);
      //將接收到的字節數組轉為對應的字符串
      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();
  }
}

五、效果展示

java實現基于UDP協議網絡Socket編程的方法

關于java實現基于UDP協議網絡Socket編程的方法就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

平山县| 孟州市| 鄂尔多斯市| 习水县| 赫章县| 青阳县| 荔浦县| 乌兰浩特市| 杂多县| 洪泽县| 重庆市| 固始县| 永顺县| 大埔区| 墨脱县| 财经| 车险| 游戏| 桃园县| 南汇区| 上饶县| 宁波市| 杭锦旗| 尖扎县| 古丈县| 灵丘县| 大冶市| 乳源| 武平县| 西藏| 昆山市| 杂多县| 皮山县| 彩票| 池州市| 陆川县| 宜兰市| 牡丹江市| 廉江市| 黔西县| 江口县|