淺談Socket通信

1文章來由:突然被問到會不會APP和PC進行通信,當時也是一臉懵逼,然後百度下,發現是用Socekt來進行通信的,沒錯,就是當初我們學java基礎篇的時候做聊天的Socket。

2。下面就直接上demo,一個客戶端和服務器通信的例子,具體安卓和pc通信的過程類似,因爲沒有測試,下次再進行上傳。

a.首先寫客戶端
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;

public class TClient{
    //服務端ip地址,這裏用本地進行測試
    private static final String IP_ADDR = "127.0.0.1";
    private static final int PORT = 8099;//使用的端口號
    private Socket chart;//建立一個Socket
    private BufferedReader burf;//使用緩衝流來讀從服務器返回的數據
    private PrintWriter pw;//標準的String類型,向服務端發送數據

    public void go() {
    //使用while可以讓本次連接一直進行,直到客戶端判斷手動結束線程,不然,本次通信只能進行一次,就會自動關閉。
        while(true){                
        try {
            chart = new Socket(IP_ADDR,PORT);//向服務端請求
            //從socket中獲取獲取返回的流
            burf = new BufferedReader(new InputStreamReader(chart.getInputStream(),"utf-8"));
            //向socket寫入輸出流,true表示強行輸出緩存
            pw = new PrintWriter(new OutputStreamWriter(chart.getOutputStream(),"utf-8"),true);

            //從鍵盤輸入,給服務器發送數據
            System.out.println("請輸入: \t");
            //讀鍵盤輸入的數據
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));                               
            String line_ = br.readLine();           
            //發送給服務器
            pw.println(line_);
            //pw.flush();(如果上面沒有true,這裏必須手動輸出緩存)

            //讀取服務器文件
            String line = burf.readLine();
            System.out.println("服務器返回的數據"+line);

            //關閉連接(返回的字符是end的時候,關閉本次連接)           
                try {
                    if ("end".equals(line)) {  
                      System.out.println("客戶端將關閉連接");
                        Thread.sleep(500);//讓這個線程sleep
                        break; //跳出while循環,連接關閉
                    }
                } catch (InterruptedException e) {                  
                    e.printStackTrace();
                }  
             //關閉流   
            pw.close();
            burf.close();   
        } catch (IOException e) {   

        System.out.println("無法連接服務器"+e.getMessage());

        }finally{
                //關閉流和Socket
                try {
                    if(chart != null){
                        chart.close();
                    }
                } catch (IOException e) {

            System.out.println("客戶端異常"+e.getMessage());
                }
            }
        }
    }

    public static void main(String[] args){
        System.out.println("客戶端啓動");
        TClient tc = new TClient();
        tc.go();    
    }
}   
//客戶端方面,(或者說APP方面),因爲一般一個用戶一個客戶端,所以在客戶端方面使用的是單一線程。

2.下面是重點方,服務器端

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class T1Server{
    private static final int PORT = 8099;//與客戶端相同的端口

    public void go(){

        try {
            ServerSocket sot = new ServerSocket(PORT);//讓服務器監聽來自改端口的客戶的請求
            while(true){
                Socket client = sot.accept();//服務器創建一個新的Socket與客服端進行通信
                new DealSockets(client);//一個新的線程處理這次通信
            }           

        } catch (IOException e) {

    System.out.println("服務器監聽客戶端失敗"+e.getMessage());
        }
    }   

    public static void main(String[] args) {
        System.out.println("服務端啓動");
        T1Server ts = new T1Server();
        ts.go();

    }   

}

    //建立一個新的線程處理通信
    class DealSockets implements Runnable{
        private Socket client;
        private BufferedReader bufr;
        private PrintWriter bufw;

        public DealSockets(Socket client){              
            this.client = client;                           
            new Thread(this).start();
        }

        public void run() {
            try {
                //讀取客戶端返回的數據                
                bufr = new BufferedReader(new InputStreamReader(client.getInputStream(),"utf-8"));              
                String line_ = bufr.readLine();
                System.out.println("客戶端發送的數據"+line_);

    //向客戶端發送數據(這裏寫死了,可以用流從鍵盤輸入,和客戶端的一樣)
            bufw = new PrintWriter(new OutputStreamWriter(client.getOutputStream(),"utf-8"));               
            bufw.println("ends");
//在使用bufw後直接調用close();,也可以直接把緩存寫出去

                //關閉流               
                bufw.close();
                bufr.close();
            } catch (IOException e) {

    System.out.println("客戶端輸入流異常:"+e.getMessage());
            }finally{

                    try {
                        if(client != null){
                            client.close();
                        }

                    } catch (IOException e) {

                        e.printStackTrace();
                    }
                }
            }

}

客戶端處理的時候,(默認的是多個用戶同時要使用服務器),所以加上了while循環,可以讓多個用戶進入,一直監聽客戶端,後面處理通信用了一個新的線程,是爲了讓用戶可以同時和服務端通信,不然的情況就(不使用多線程)是一個用戶使用完本次連接,第二個用戶才能進入。這樣就會出現問題了。

3.這個demo很簡陋,具體實際應用還要看業務需求,比如我這個通訊,寫死了是客戶端發消息,服務器才能返回消息,然後服務器在發送消息。真正在寫聊天的時候,客戶端需要一個新的線程專門從socket中讀取服務器的消息來進行顯示。這樣實用性就會高一點了。

4.如有不當的地方,敬請指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章