JAVA總結之一:SOCKET通信(代碼篇)


前言:這是我第一次開始總結我的編程之路,那么就從socket通信開始吧,本片是我原引自網絡總結篇文章,我覺得比較具體精煉,代碼干練,是我想要總結的類型,因此就“借鑒”以自用。如果還有更好的我會繼續總結,也當是我的繼續學習啦。

——levy

 

一、SOCKET原理


   1.什么是socket
   所謂socket通常也稱作"套接字",用於描述IP地址和端口,是一個通信鏈的句柄。應用程序通常通過"套接字"向網絡發出請求或者應答網絡請求。
   以J2SDK-1.3為例,Socket和ServerSocket類庫位於java.net包中。ServerSocket用於服務器端,Socket是建立網絡連接時使用的。在連接成功時,應用程序兩端都會產生一個Socket實例,操作這個實例,完成所需的會話。對於一個網絡連接來說,套接字是平等的,並沒有差別,不因為在服務器端或在客戶端而產生不同級別。不管是Socket還是ServerSocket它們的工作都是通過SocketImpl類及其子類完成的。
   2.重要的Socket API:
   java.net.Socket繼承於java.lang.Object,有八個構造器,其方法並不多,下面介紹使用最頻繁的三個方法,其它方法大家可以見JDK-1.3文檔。
   . Accept方法用於產生"阻塞",直到接受到一個連接,並且返回一個客戶端的Socket對象實例。"阻塞"是一個術語,它使程序運行暫時"停留"在這個地方,直到一個會話產生,然后程序繼續;通常"阻塞"是由循環產生的。
   . getInputStream方法獲得網絡連接輸入,同時返回一個IutputStream對象實例,。
   . getOutputStream方法連接的另一端將得到輸入,同時返回一個OutputStream對象實例。
   注意:其中getInputStream和getOutputStream方法均會產生一個IOException,它必須被捕獲,因為它們返回的流對象,通常都會被另一個流對象使用。
   3.如何開發一個Server-Client模型的程序
   開發原理:


   服務器,使用ServerSocket監聽指定的端口,端口可以隨意指定(由於1024以下的端口通常屬於保留端口,在一些操作系統中不可以隨意使用,所以建議使用大於1024的端口),等待客戶連接請求,客戶連接后,會話產生;在完成會話后,關閉連接。


   客戶端,使用Socket對網絡上某一個服務器的某一個端口發出連接請求,一旦連接成功,打開會話;會話完成后,關閉Socket。客戶端不需要指定打開的端口,通常臨時的、動態的分配一個1024以上的端口。

 

二、建立模型


      

       1.基本Server-Client模型

 

   {建立服務器} 

   1: import java.net.*;
   2: import java.io.*;
   3:  
   4: public class Server {
   5:     private ServerSocket ss;
   6:     private Socket socket;
   7:     private BufferedReader in;
   8:     private PrintWriter out;
   9:  
  10:     public Server() {
  11:       try {
  12:           ss = new ServerSocket(10000);
  13:  //進入循環,這是由socket的特性決定的,進行循環監聽
  14:           while (true) {
  15:               socket = ss.accept(); //accept() 監聽方法
  16:               in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  17:               out = new PrintWriter(socket.getOutputStream(),true);
  18:  
  19:               String line = in.readLine();
  20:               out.println("you input is :" + line);
  21:               out.close();
  22:               in.close();
  23:               socket.close(); //socket流必須關閉!
  24:             }
  25:           ss.close();
  26:         } catch (IOException e) {}
  27:     }
  28:  
  29:     public static void main(String[] args) {
  30:       new Server();
  31:     }
  32:   }

 

這個程序建立了一個服務器,它一直監聽10000端口,等待用戶連接。在建立連接后給客戶端返回一段信息,然后結束會話。這個程序一次只能接受一個客戶連接。

{建立客戶端}

   1: import java.io.*;
   2: import java.net.*;
   3: public class Client {
   4:     Socket socket;
   5:     BufferedReader in;
   6:     PrintWriter out;
   7:     public Client() {
   8:       try {
   9:           socket = new Socket("xxx.xxx.xxx.xxx", 10000);  //服務器地址和端口號
  10:           in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  11:           out = new PrintWriter(socket.getOutputStream(),true);
  12:           BufferedReader line = new BufferedReader(new InputStreamReader(System.in));
  13:           out.println(line.readLine());
  14:           line.close();
  15:           out.close();
  16:           in.close();
  17:           socket.close();
  18:         } catch (IOException e) {}
  19:     }
  20:     public static void main(String[] args) {
  21:       new Client();
  22:     }
  23:   }

 

這個客戶端連接到地址為xxx.xxx.xxx.xxx的服務器,端口為10000,並從鍵盤輸入一行信息,發送到服務器,然后接受服務器的返回信息,最后結束會話。

 

       2.Serverd端多線程模型(解決多客戶同時連接)


   在實際的網絡環境里,同一時間只對一個用戶服務是不可行的。一個優秀的網絡服務程序除了能處理用戶的輸入信息,還必須能夠同時響應多個客戶端的連接請求。在java中,實現以上功能特點是非常容易的。


   設計原理:


   主程序監聽一端口,等待客戶接入;同時構造一個線程類,准備接管會話。當一個Socket會話產生后,將這個會話交給線程處理,然后主程序繼續監聽。運用Thread類或Runnable接口來實現是不錯的辦法。
  

{實現消息共性} 

 

   1: import java.io.*;
   2: import java.net.*;
   3: public class Server extends ServerSocket {
   4:     private static final int SERVER_PORT = 10000;
   5:     public Server() throws IOException {
   6:         super(SERVER_PORT);
   7:         try {
   8:             while (true) {
   9:                 Socket socket = accept();
  10:                 new CreateServerThread(socket);
  11:               }
  12:           } catch (IOException e) {} finally {
  13:             close();
  14:           }
  15:       }
  16: //--- CreateServerThread
  17:     class CreateServerThread extends Thread {
  18:         private Socket client;
  19:         private BufferedReader in;
  20:         private PrintWriter out;
  21:         public CreateServerThread(Socket s) throws IOException {
  22:             client = s;
  23:             in = new BufferedReader(new InputStreamReader(client.getInputStream(), "GB2312"));
  24:             out = new PrintWriter(client.getOutputStream(), true);
  25:             out.println("--- Welcome ---");
  26:             start();
  27:           }
  28:         public void run() {
  29:           try {
  30:               String line = in.readLine();
  31:               while (!line.equals("bye")) {
  32:                   String msg = createMessage(line);
  33:                   out.println(msg);
  34:                   line = in.readLine();
  35:                 }
  36:               out.println("--- See you, bye! ---");
  37:               client.close();
  38:             } catch (IOException e) {}
  39:         }
  40:         private String createMessage(String line) {
  41:           xxxxxxxxx;
  42:         }
  43:       }
  44:     public static void main(String[] args) throws IOException {
  45:         new Server();
  46:       }
  47:   }

   

這個程序監聽10000端口,並將接入交給CreateServerThread線程運行。CreateServerThread線程接受輸入,並將輸入回應客戶,直到客戶輸入"bye",線程結束。我們可以在createMessage方法中,對輸入進行處理,並產生結果,然后把結果返回給客戶。 第三步 實現信息共享:在Socket上的實時交流

 

        2.信息共享模型


   網絡的偉大之一也是信息共享,Server可以主動向所有Client廣播消息,同時Client也可以向其它Client發布消息。下面看看如何開發一個可以實時傳遞消息的程序。

設計原理:
   服務器端接受客戶端的連接請求,同時啟動一個線程處理這個連接,線程不停的讀取客戶端輸入,然后把輸入加入隊列中,等候處理。在線程啟動的同時將線程加入隊列中,以便在需要的時候定位和取出。


  {源碼}

 

   1: import java.io.*;
   2: import java.net.*;
   3: import java.util.*;
   4: import java.lang.*;
   5: public class Server extends ServerSocket {
   6:     private static ArrayList User_List = new ArrayList();
   7:     private static ArrayList Threader = new ArrayList();
   8:     private static LinkedList Message_Array = new LinkedList();
   9:     private static int Thread_Counter = 0;
  10:     private static boolean isClear = true;
  11:     protected static final int SERVER_PORT = 10000;
  12:     protected FileOutputStream LOG_FILE = new FileOutputStream("d:/connect.log", true);
  13:     public Server() throws FileNotFoundException, IOException {
  14:         super(SERVER_PORT);
  15:         new Broadcast();
  16: //append connection log
  17:         Calendar now = Calendar.getInstance();
  18:         String str = "[" + now.getTime().toString() + "] Accepted a connection\015\012";
  19:         byte[] tmp = str.getBytes();
  20:         LOG_FILE.write(tmp);
  21:         try {
  22:             while (true) {
  23:                 Socket socket = accept();
  24:                 new CreateServerThread(socket);
  25:               }
  26:           } finally {
  27:             close();
  28:           }
  29:       }
  30:     public static void main(String[] args) throws IOException {
  31:         new Server();
  32:       }
  33: //--- Broadcast
  34:     class Broadcast extends Thread {
  35:         public Broadcast() {
  36:           start();
  37:         }
  38:         public void run() {
  39:           while (true) {
  40:               if (!isClear) {
  41:                   String tmp = (String)Message_Array.getFirst();
  42:                   for (int i = 0; i < Threader.size(); i++) {
  43:                       CreateServerThread client = (CreateServerThread)Threader.get(i);
  44:                       client.sendMessage(tmp);
  45:                     }
  46:                   Message_Array.removeFirst();
  47:                   isClear = Message_Array.size() > 0 ? false : true;
  48:                 }
  49:             }
  50:         }
  51:       }
  52: //--- CreateServerThread
  53:     class CreateServerThread extends Thread {
  54:         private Socket client;
  55:         private BufferedReader in;
  56:         private PrintWriter out;
  57:         private String Username;
  58:         public CreateServerThread(Socket s) throws IOException {
  59:             client = s;
  60:             in = new BufferedReader(new InputStreamReader(client.getInputStream()));
  61:             out = new PrintWriter(client.getOutputStream(), true);
  62:             out.println("--- Welcome to this chatroom ---");
  63:             out.println("Input your nickname:");
  64:             start();
  65:           }
  66:         public void sendMessage(String msg) {
  67:           out.println(msg);
  68:         }
  69:         public void run() {
  70:           try {
  71:               int flag = 0;
  72:               Thread_Counter++;
  73:               String line = in.readLine();
  74:               while (!line.equals("bye")) {
  75:                   if (line.equals("l")) {
  76:                       out.println(listOnlineUsers());
  77:                       line = in.readLine();
  78:                       continue;
  79:                     }
  80:                   if (flag++ == 0) {
  81:                       Username = line;
  82:                       User_List.add(Username);
  83:                       out.println(listOnlineUsers());
  84:                       Threader.add(this);
  85:                       pushMessage("[< " + Username + " come on in >]");
  86:                     } else {
  87:                       pushMessage("<" + Username + ">" + line);
  88:                     }
  89:                   line = in.readLine();
  90:                 }
  91:               out.println("--- See you, bye! ---");
  92:               client.close();
  93:             } catch (IOException e) {} finally {
  94:               try {
  95:                   client.close();
  96:                 } catch (IOException e) {}
  97:               Thread_Counter--;
  98:               Threader.remove(this);
  99:               User_List.remove(Username);
 100:               pushMessage("[< " + Username + " left>]");
 101:             }
 102:         }
 103:         private String listOnlineUsers() {
 104:           String s ="-+- Online list -+-\015\012";
 105:           for (int i = 0; i < User_List.size(); i++) {
 106:               s += "[" + User_List.get(i) + "]\015\012";
 107:             }
 108:           s += "-+---------------------+-";
 109:           return s;
 110:         }
 111:         private void pushMessage(String msg) {
 112:           Message_Array.addLast(msg);
 113:           isClear = false;
 114:         }
 115:       }
 116:   }

 

  B6A494567D91378454178B95B7A2D37C

 

這就是程序運行后,多用戶登陸並且輸入信息后的屏幕。實現了信息的實時廣播。用戶輸入"l"就可以列出在線人員表。

 

 三、整體直觀代碼塊(socket模型)

 

 {客戶端socket類}

 

   1: import java.io.*;
   2: import java.net.*;
   3:  
   4: public class NovelClient {
   5:  
   6:     
   7:     private ObjectOutputStream output;
   8:     private ObjectInputStream input;
   9:     private Socket socket;
  10:     private Object o;
  11:     
  12:     
  13:     /**
  14:      * socket流聲明
  15:      */
  16:     public NovelClient(){
  17:         try {
  18:             InetAddress addr = InetAddress.getLocalHost();
  19:             String ip=addr.getHostAddress().toString();
  20:             socket=new Socket(ip,8000);
  21:         } catch (UnknownHostException e) {
  22:             e.printStackTrace();
  23:         } catch (IOException e) {
  24:             e.printStackTrace();
  25:         }
  26:     }
  27:  
  28: public Object sendAndRead(Object o){
  29:     try {
  30:         output=new ObjectOutputStream(socket.getOutputStream());
  31:         output.writeObject(o);
  32:         output.flush();
  33:         input=new ObjectInputStream(socket.getInputStream());
  34:         o=(Object) input.readObject();
  35:     } catch (IOException e) {
  36:         e.printStackTrace();
  37:     } catch (ClassNotFoundException e) {
  38:         e.printStackTrace();
  39:     }finally{
  40:           output.close();
  41:           input.close();
  42:     }
  43:     return o;
  44: }

 

{服務器端socket類}

 

   1:  
   2: import java.io.IOException;
   3: import java.net.ServerSocket;
   4: import java.net.Socket;
   5: /**
   6:  * Socket Class
   7:  * @author oracle
   8:  *
   9:  */
  10: public class Server {
  11:  
  12:     private static ServerSocket serversocket;
  13:     private static Socket scoket;
  14:         
  15:     public static void serverStart(){
  16:         try {
  17:             serversocket =new ServerSocket(7566);
  18:             System.out.println("server start...");
  19:             while(true){
  20:                 scoket=serversocket.accept();
  21:                 ServerThread serverthread=new ServerThread(scoket);
  22:                 Thread thread=new Thread(serverthread);
  23:                 thread.start();
  24:             }
  25:         } catch (IOException e) {
  26:             e.printStackTrace();
  27:         }
  28:     }
  29:     
  30:     public static void main(String []args){
  31:         Server.serverStart();
  32:     }
  33:     
  34: }

 

 {服務器端線程類}

 

   1: import java.io.*;
   2: import java.net.Socket;
   3:  
   4: public class ServerThread implements Runnable {
   5:  
   6:     private Socket socket;
   7:     private ObjectInputStream in;
   8:     private ObjectOutputStream out;
   9:     private Objecet o;  
  10:     
  11:     public ServerThread (Socket socket) {
  12:         this.socket=socket;
  13:     }
  14:  
  15:     @Override
  16:     public void run() {
  17:         serverThread();
  18:     }
  19:  
  20:     private void serverThread() {
  21:  
  22:         try {
  23:           in=new ObjectInputStream(socket.getInputStream());
  24:           o=(Object) in.readObject();
  25:  
  26:             out=new ObjectOutputStream(socket.getOutputStream());
  27:             out.writeObject(o);
  28:             out.flush();
  29:         } catch (IOException e) {
  30:             e.printStackTrace();
  31:         } catch (ClassNotFoundException e) {
  32:             e.printStackTrace();
  33:         }        
  34:     }
  35: }

 

聲明:最后這個是我自己寫的,為了以后理解時候用的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM