步步測試完善Java中Socket通訊圖解法(三)

來源:互聯網
上載者:User

目錄

簡介

Java中Socket通訊簡介

單線程一對一伺服器1——>1用戶端

單線程一對一伺服器1<——>1用戶端

多線程一對多伺服器1<——>N用戶端【非聊天室的伺服器通過使用者輸入發送資料】

多線程一對多伺服器1<——>N用戶端【聊天室】

多線程最終伺服器和用戶端整合一體【swing程式】

     【多線程】一對多伺服器1<——>N用戶端(非聊天室的伺服器通過使用者輸入發送資料)      對,解決方案,就是發送資料和接受資料不在同一個進程,這樣,這兩個進程互不影響。      解決方案如下:伺服器端和用戶端如下:                  

      當然,若下文要考慮,多個用戶端串連同一個服務端時,所以,應該對每個sockt串連開啟一個線程。但是對於用戶端而言,只要把發送和接受分離即可。所以在用戶端中,可以把發送資料和主進程放在一塊。如:          

        代碼實現如下:        伺服器端:      
 package com17.tcp;import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;public class MyServer {         public static void main(String[] args) {          try {               ServerSocket ss=new ServerSocket(30000);               while(true)               {                    //此行代碼會阻塞,將一直等待別人的串連                    Socket s=ss.accept();                    if(s.isConnected())                    {                         System.out.println("一個用戶端串連此伺服器"+s.getInetAddress());                    }                    //每當用戶端串連後啟動一條ServerThread線程為該用戶端服務                    new Thread( new ServerThread(s)).start();                  //發送資料到用戶端                    new Thread(new ServerThread2(s)).start();               }          } catch (IOException e) {               // TODO Auto-generated catch block               e.printStackTrace();          }     }}

  

      接受資料的並列印的線程:     
package com17.tcp;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintStream;import java.net.Socket;import java.util.Scanner;public class ServerThread implements Runnable {     //定義當前線程所處理的socket     Socket s=null;     //該線程所處理的socket所對應的輸入資料流     BufferedReader br=null;         public ServerThread(Socket s)     {          try          {               this.s=s;               //初始化socket對應的輸入資料流               br=new BufferedReader(new InputStreamReader(s.getInputStream()));                        }          catch(IOException e)          {               e.printStackTrace();          }         }         @Override     public void run() {         try         {              String content=null;             //採用迴圈不斷從Socket中讀取用戶端發送過來的資料             while((content=readFromClient())!=null)             {                  System.out.println("來自用戶端訊息:"+content);             }             System.out.println("訊息:"+content);             PrintStream ps=new PrintStream(s.getOutputStream());             ps.println(br.readLine());         }catch(Exception e)         {              try              {                   s.close();              }catch(IOException ex)              {                   ex.printStackTrace();              }         }     }         //定義讀取用戶端資料的方法     private String readFromClient()     {          try          {               return br.readLine();          }          //如果捕捉到異常,表明該socket對應的用戶端已經關閉          catch(IOException e)          {              e.printStackTrace();          }        return null;     }}

   

    發送資料到用戶端的線程:    
package com17.tcp;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintStream;import java.net.Socket;public class ServerThread2 implements Runnable {     private Socket s;     //用來處理髮送資料的     private PrintStream ps=null;     public ServerThread2(Socket s)     {          try          {               this.s=s;               ps=new PrintStream(s.getOutputStream());          }          catch(IOException e)          {               try               {                    s.close();               }               catch(IOException ex)               {                    ex.printStackTrace();               }                        }     }     @Override     public void run() {          try          {                 //發送資料到用戶端                  String line=null;                                   //不斷讀取鍵盤的輸入                  BufferedReader br=new BufferedReader(new InputStreamReader(System.in));                  while((line=br.readLine())!=null)                  {                       //將使用者的鍵盤輸入內容寫入socket對應的輸出資料流                       ps.println(line);                  }          }          catch(IOException e)          {               e.printStackTrace();          }     }}

  

    用戶端:   
package com17.tcp;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintStream;import java.net.Socket;//負責讀取使用者的鍵盤輸入,並將使用者輸入的資料寫入socket對應的輸出資料流中//一條負責讀取socket對應輸入資料流中的資料(從伺服器發送過來的資料)//並將這些資料列印輸出。其中負責讀取使用者鍵盤輸入的線程由MyClient負責,也就是由程式的主線程負責。public class MyClient {public static void main(String[] args) {try{   Socket s=new Socket("127.0.0.1",30000);   //用戶端啟動clientThread縣城不斷讀取來自伺服器的資料   new Thread(new ClientThread(s)).start();   //擷取該socket對應的輸出資料流   PrintStream ps=new PrintStream(s.getOutputStream());   String line=null;   //不斷讀取鍵盤的輸入   BufferedReader br=new BufferedReader(new InputStreamReader(System.in));   while((line=br.readLine())!=null)   {   //將使用者的鍵盤輸入內容寫入socket對應的輸出資料流   ps.println(line);   }}catch(IOException e){e.printStackTrace();}       }}
用戶端線程:

  
package com17.tcp;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.net.Socket;public class ClientThread implements Runnable {//該線程負責處理的socketprivate Socket s;//該線程所處理的socket所對應的輸入資料流BufferedReader br=null;public ClientThread(Socket s) throws IOException{this.s=s;br=new BufferedReader(new InputStreamReader(s.getInputStream()));}@Overridepublic void run() {        try        {        String content=null;        //不斷讀取socket輸入資料流中的內容,講這些內容列印輸出        while((content=br.readLine())!=null)        {        System.out.println("來自伺服器端訊息:"+content);        }        }        catch(IOException e)        {        e.printStackTrace();        }}}
    效果如下:       

   但是我們通過以上的代碼,要實現這種如下:    

     雖然上述代碼中使用了多線程,每個用戶端請求,都會產生一個讀線程和寫線程。但是也不能完成的要求。     為什麼呢?     主要在於寫的線程。     因為寫的線程,雖然捕捉了發送的socket通訊端,但是寫線程中是時刻監聽使用者輸入System.in。     這樣,當多個用戶端串連伺服器端時,則伺服器端有多個線程監聽使用者輸入System.in。但是令人頭疼的是,伺服器端只有一個dos視窗,而不像用戶端一個dos視窗監聽一個使用者輸入System.in。      訪問中伺服器端結果如下:            

         所以伺服器想通過使用者輸入形式發送給多個用戶端,這種形式是不可行的。         代碼中,永遠只能發給具有活動的線程。結果不是你想象的那樣,發給你想象的線程。        當然,若是伺服器不是通過監聽使用者輸入則當然可以實現上述的要求的        我們改一下伺服器端:不通過監聽使用者輸入。        伺服器端中,接受線程中,一接受到客戶的資料,則發送資料。        伺服器端,線程              

       接受線程中修改上述的demo      
           //採用迴圈不斷從Socket中讀取用戶端發送過來的資料        while((content=readFromClient ())!=null )        {              System. out.println( "來自用戶端訊息:" +content);              ps.println( "用戶端"+s.getInetAddress()+"訊息已經收入到,訊息為:" +content);        }

        

        如下:           【多線程】一對多伺服器1<——>N用戶端(聊天室)    

      我想通過上述幾個例子,想必對通訊的方式已經瞭解,並且也掌握通訊的原理以及通訊方法。      那我們再說,聊天室通訊,就是類似我們qq群。一人發表了看法,則其他的人都能看到此訊息。      猜想qq實現方式,就是通過伺服器轉寄【僅此個人看法】      那我們這個例子實現方式如:          

     那這個例子 不在貼代碼,我們說一下思路,在伺服器端有個列表,專門用來儲存用戶端的socket。只要用戶端串連伺服器,就把用戶端的socket添加到伺服器列表中。當接受到任何用戶端資料時,就把資料轉寄給列表中任何一個用戶端socket。     部分代碼如下:   
        //採用迴圈不斷從Socket中讀取用戶端發送過來的資料        while((content=readFromClient())!= null)        {              //便利socketList中的每一個socket              //將讀到的內容向每個socket發送一次              for(Socket s:MyServer. socketList)              {                   PrintStream ps= new PrintStream(s.getOutputStream());                   ps.println(content);              }        }

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.