欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JAVA實(shí)現(xiàn)SOCKET多客戶端通信的案例

 更新時(shí)間:2020年12月01日 11:25:26   作者:黎明的影  
這篇文章主要介紹了JAVA實(shí)現(xiàn)SOCKET多客戶端通信的案例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧

一、ServerSocket

1.為了方便調(diào)試,先創(chuàng)建一個(gè)界面用于顯示客戶端連接信息

基于javafx包寫的一個(gè)簡(jiǎn)單界面!

 javafx.scene.control.TextArea ta = new javafx.scene.control.TextArea();
 @Override
 public void start(Stage primaryStage) throws Exception {
  scene = new Scene(ta,450,200);
  primaryStage.setTitle("SocketServer");
  primaryStage.setScene(scene);
  primaryStage.show();
  pStage = primaryStage;
  new Thread(new MyServer()).start(); //創(chuàng)建線程啟動(dòng)Socket服務(wù)
  }

2.啟動(dòng)Socket服務(wù)

public class MyServer implements Runnable{
  @Override
  public void run() {
   try{
    java.net.ServerSocket serverSocket = new java.net.ServerSocket(8000);
    ta.appendText("Server started at " + new Date()+"\n");
    while(true){
     Socket socket = serverSocket.accept(); //程序會(huì)在這里阻塞,直到等到客戶端連接
     clientNumber++;
     /*
     這里就是在界面中輸出一些服務(wù)器、和連接的客戶端信息
      */
     Platform.runLater(()->{
      ta.appendText("Starting thread for client " + clientNumber + " at " +
        new Date() +"\n");
      InetAddress inetAddress = socket.getInetAddress();
      ta.appendText("Client "+clientNumber + "'s host name is" +inetAddress.getHostName()
      +"\n");
      ta.appendText("Client"+clientNumber + "'s IP address is "+ inetAddress.getHostAddress()+"\n");
     });
     /*
     每有一個(gè)客戶端連接服務(wù)器就創(chuàng)建一個(gè)線程,進(jìn)行通信處理
      */
     new Thread(new HandleServer(socket)).start();
     try{
      Thread.sleep(100); //多個(gè)客戶端連續(xù)快速連接服務(wù)器時(shí),可能出現(xiàn)問題,這里設(shè)置延時(shí)
     }catch (InterruptedException e){
      e.printStackTrace();
     }
    }

   }catch (IOException e){
    e.printStackTrace();
   }
  }
 }

這一段代碼主要作用就是循環(huán)等待客戶端連接服務(wù)器:

Socket socket = serverSocket.accept();

在寫這篇博客時(shí),突然想知道阻塞的原理就去查了一下。。。。

然而并沒有看懂。。這個(gè)應(yīng)該涉及到操作系統(tǒng)層面,等之后把操作系統(tǒng)搞明白了在來補(bǔ)充吧。

3.服務(wù)器處理類HandleServer

class HandleServer implements Runnable {
  private Socket socket;
  private int name;
  private int toClientID;
  private DataOutputStream outputStream;
  private DataInputStream inputStream;
  public HandleServer(Socket socket){
   this.socket = socket;
   ServerTools.Tools().add(this);
   this.name = clientNumber;
  }
  @Override
  public void run() {
   try{
    inputStream = new DataInputStream(socket.getInputStream());
    outputStream = new DataOutputStream(socket.getOutputStream());
    outputStream.writeUTF("Your ID is:"+clientNumber);
    while (true){
     toClientID = inputStream.readInt();
     String messageGET = inputStream.readUTF();
     int err = ServerTools.Tools().MyWriteUTF(messageGET,toClientID); //MyWriteUTF 是一個(gè)自定義方法,serverTools.Tools()是一個(gè)工具類,一個(gè)靜態(tài)對(duì)象。
     if (err==0){
      outputStream.writeUTF("No have this ID!");
     }
     Platform.runLater(()->{
      ta.appendText(socket.getInetAddress().getHostName()+" Message received from client:" + messageGET +"\n" );
     });
     System.out.println(clientNumber);
    }
   }catch (IOException e){
    clientNumber--;
    System.out.println(clientNumber);
    System.err.println("Client is closed!");
   }

  }

這一塊的代碼主要就是創(chuàng)建輸入輸出數(shù)據(jù)流了

inputStream = new DataInputStream(socket.getInputStream());

outputStream = new DataOutputStream(socket.getOutputStream());

4.一些方法方便ServerTools類實(shí)現(xiàn)

  public void MyWriteUTF(String message){
   try {
    outputStream.writeUTF(message);
   } catch (IOException e) {
    ServerTools.Tools().remove(this);
    e.printStackTrace();
   }
  }

  public int getName() {
   return name;
  }

二、ServerTools

1.實(shí)現(xiàn)指定服務(wù)器ID輸出信息的工具

public class ServerTools {

 private static final ServerTools servertools = new ServerTools();
 public static ServerTools Tools(){
  return servertools;
 }

 Vector<MyServerSocket.HandleServer> vector = new Vector<MyServerSocket.HandleServer>();
 public void add(MyServerSocket.HandleServer cs){
  vector.add(cs);
 }
 public void remove(MyServerSocket.HandleServer cs){
  vector.remove(cs);
 }

 public int MyWriteUTF(String message,int target) {
  for (int i = 0; i <= target; i++){
   try {
    if (vector.get(i).getName() == target) {
     MyServerSocket.HandleServer MSSHC = vector.get(i);
     MSSHC.MyWriteUTF(message);
     return 1;
    }
   }catch (ArrayIndexOutOfBoundsException e){
    e.printStackTrace();
    return 0;
   }
  }
  return 0;

 }
}

vector用于保存客戶端連接信息

一個(gè)粗糙的處理方式,邏輯上缺陷還很嚴(yán)重,主要我好像沒找到這樣的框架???

缺陷:因?yàn)榉?wù)器要返回客戶端的ID讓客戶端將ID顯示到交互界面,所以存在情況客戶端多次連接斷開后會(huì)使返回的ID出現(xiàn)重復(fù)

三、ClientSocket

1.同樣的先建一個(gè)簡(jiǎn)單的界面用于輸出信息和顯示信息

第一個(gè)編輯框就是 輸入要發(fā)送指定客戶端的ID 例如:1 或 2 這樣的???

第二個(gè)編輯框就是 輸入你要發(fā)送的信息了,很清楚

下面的就是顯示框,嗯!

public class MyClientSocket extends Application {

 private Socket socket;
 private DataOutputStream toServer = null;
 private DataInputStream fromServer = null;
 private String ID;
 private int targetID = 0;
 private TextArea ta;

 @Override
 public void start(Stage primaryStage) throws Exception {
  BorderPane paneForTextField = new BorderPane();
  paneForTextField.setPadding(new Insets(5,5,5,5));
  paneForTextField.setStyle("-fx-border-color: green");
  paneForTextField.setLeft(new Label("Enter a Message:"));

  TextField tf = new TextField();
  tf.setAlignment(Pos.BOTTOM_RIGHT);
  paneForTextField.setCenter(tf);

  BorderPane ID_lable = new BorderPane();
  ID_lable.setPadding(new Insets(5,5,5,5));
  ID_lable.setStyle("-fx-border-color: green");
  ID_lable.setLeft(new Label("Enter a ID for send message:"));

  TextField getId = new TextField();
  getId.setAlignment(Pos.BOTTOM_RIGHT);
  ID_lable.setCenter(getId);
  paneForTextField.setTop(ID_lable);


  BorderPane mainPane = new BorderPane();
  ta = new TextArea();
  mainPane.setCenter(new ScrollPane(ta));
  mainPane.setTop(paneForTextField);


  Scene scene = new Scene(mainPane,450,200);
  primaryStage.setTitle("SocketClient");
  primaryStage.setScene(scene);
  primaryStage.show();

  tf.setOnAction(new EventHandler<ActionEvent>() {
   @Override
   public void handle(ActionEvent event) {
    targetID = Integer.parseInt(getId.getText().trim());
    if (targetID > 0 || targetID!=Integer.parseInt(ID));
    else return;
    try {
     String putMessage = tf.getText().trim();
     toServer.writeInt(targetID);
     toServer.writeUTF(putMessage);
     toServer.flush();
     ta.appendText("PUT message is :"+ putMessage +"\n");
     tf.setText("");
    }catch (IOException ex ){
     System.err.println(ex);
    }
   }
  });

  try{
   socket = new Socket("localhost",8000);
   fromServer = new DataInputStream(socket.getInputStream());
   toServer = new DataOutputStream(socket.getOutputStream());
   ID = fromServer.readUTF();
   paneForTextField.setRight(new Label("Your ID is:"+ID));
   new Thread(new getMessage(socket,fromServer)).start();
  }catch (IOException ex){
   ta.appendText(ex.toString() +"\n");
  }
 }
}

一樣的要new一個(gè)Socket 去連接服務(wù)器,socket(),括號(hào)里的就是服務(wù)器的IP,和程序的端口號(hào)了,這種基于tcp協(xié)議的好像都是一個(gè)樣???

2.創(chuàng)建一個(gè)線程用于循環(huán)獲取信息并顯示

 class getMessage implements Runnable{
  private Socket socket;
  private DataInputStream formServer;
  public getMessage(Socket socket,DataInputStream formServer){
   this.socket = socket;
   this.formServer = formServer;
  }
  @Override
  public void run() {
   try {
    while (true) {
     String Message = formServer.readUTF();
     try{
      Thread.sleep(100);
     }catch (InterruptedException e) {
      e.printStackTrace();
     }
     ta.appendText("GET message from server is:" + Message + "\n");

    }
   }catch (IOException e){
    System.err.println(e);
   }

  }
 }

很簡(jiǎn)單了,依舊是輸入輸出數(shù)據(jù)流,然后循環(huán)等待信息并輸出。

3.新建一個(gè)TestClient類 這個(gè)類 和ClientSocket 一模一樣 就是拿來測(cè)試的

四、總結(jié)

java寫socket 是真的簡(jiǎn)單!??!^_ ^!

以上這篇JAVA實(shí)現(xiàn)SOCKET多客戶端通信的案例就是小編分享給大家的全部內(nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 從面試中的問題分析ThreadLocal

    從面試中的問題分析ThreadLocal

    這篇文章主要介紹了從面試中的問題分析ThreadLocal,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,下面我們來一起學(xué)習(xí)一下吧
    2019-06-06
  • springboot中一些比較常用的注解總結(jié)

    springboot中一些比較常用的注解總結(jié)

    今天給大家?guī)淼氖顷P(guān)于Java的相關(guān)知識(shí),文章圍繞著springboot中一些比較常用的注解展開,文中有非常詳細(xì)的總結(jié),需要的朋友可以參考下
    2021-06-06
  • Java自帶定時(shí)任務(wù)ScheduledThreadPoolExecutor實(shí)現(xiàn)定時(shí)器和延時(shí)加載功能

    Java自帶定時(shí)任務(wù)ScheduledThreadPoolExecutor實(shí)現(xiàn)定時(shí)器和延時(shí)加載功能

    今天小編就為大家分享一篇關(guān)于Java自帶定時(shí)任務(wù)ScheduledThreadPoolExecutor實(shí)現(xiàn)定時(shí)器和延時(shí)加載功能,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • IntelliJ Idea 2020.1 正式發(fā)布,官方支持中文(必看)

    IntelliJ Idea 2020.1 正式發(fā)布,官方支持中文(必看)

    這篇文章主要介紹了IntelliJ Idea 2020.1 正式發(fā)布,官方支持中文了,本文通過截圖的形式給大家展示,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • springboot接收別人上傳的本地視頻實(shí)例代碼

    springboot接收別人上傳的本地視頻實(shí)例代碼

    本文通過實(shí)例代碼給大家介紹了springboot接收別人上傳的本地視頻,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2018-07-07
  • Java微信支付之服務(wù)號(hào)支付代碼示例

    Java微信支付之服務(wù)號(hào)支付代碼示例

    這篇文章主要介紹了Java微信支付之服務(wù)號(hào)支付代碼示例,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-11-11
  • 關(guān)于webLucene 安裝方法

    關(guān)于webLucene 安裝方法

    webLucene是一個(gè)基于開源項(xiàng)目lucene實(shí)現(xiàn)站內(nèi)搜索的工具,關(guān)于它的安裝,百度得到的大多是一樣的,按照步驟也能正確安裝并運(yùn)行,需要注意的問題是
    2009-06-06
  • Java日期工具類DateUtils實(shí)例詳解

    Java日期工具類DateUtils實(shí)例詳解

    這篇文章主要為大家詳細(xì)介紹了Java日期工具類DateUtils實(shí)例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • 解決JavaMail附件名字過長導(dǎo)致的亂碼問題

    解決JavaMail附件名字過長導(dǎo)致的亂碼問題

    這篇文章主要介紹了解決JavaMail附件名字過長導(dǎo)致的亂碼問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-10-10
  • Java實(shí)現(xiàn)窗體程序顯示日歷

    Java實(shí)現(xiàn)窗體程序顯示日歷

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)窗體程序顯示日歷,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06

最新評(píng)論