Android基礎入門教程——7.6.2 基於TCP協議的Socket通訊(1)

來源:互聯網
上載者:User

Android基礎入門教程——7.6.2 基於TCP協議的Socket通訊(1)
Android基礎入門教程——7.6.2 基於TCP協議的Socket通訊(1)

標籤(空格分隔): Android基礎入門教程

本節引言:

上一節的概念課枯燥無味是吧,不過總有點收穫是吧,本節開始我們來研究基於TCP協議的Socket
通訊,先來瞭解下Socket的概念,以及Socket通訊的模型,實現Socket的步驟,以及作為Socket服務
端與用戶端的兩位各做要做什麼事情!好的,我們由淺入深來扣這個Socket吧!

1.什麼是Socket?

2.Socket通訊模型:

Socket通訊實現步驟解析:

Step 1:建立ServerSocket和Socket
Step 2:開啟串連到的Socket的輸入/輸出流
Step 3:按照協議對Socket進行讀/寫操作
Step 4:關閉輸入輸出資料流,以及Socket

好的,我們接下來寫一個簡單的例子,開啟服務端後,用戶端點擊按鈕然後連結服務端,
並向服務端發送一串字串,表示通過Socket連結上伺服器~

3.Socket服務端的編寫:

服務端要做的事有這些:

Step 1:建立ServerSocket對象,綁定監聽的連接埠
Step 2:調用accept()方法監聽用戶端的請求
Step 3:串連建立後,通過輸入資料流讀取用戶端發送的請求資訊
Step 4:通過輸出資料流向用戶端發送響應資訊
Step 5:關閉相關資源

代碼實現:

直接在Eclipse下建立一個Java項目,然後把Java代碼貼進去即可!

public class SocketServer {    public static void main(String[] args) throws IOException {        //1.建立一個伺服器端Socket,即ServerSocket,指定綁定的連接埠,並監聽此連接埠        ServerSocket serverSocket = new ServerSocket(12345);        InetAddress address = InetAddress.getLocalHost();        String ip = address.getHostAddress();        Socket socket = null;        //2.調用accept()等待用戶端串連        System.out.println(~~~服務端已就緒,等待用戶端接入~,服務端ip地址:  + ip);        socket = serverSocket.accept();        //3.串連後擷取輸入資料流,讀取用戶端資訊        InputStream is=null;        InputStreamReader isr=null;        BufferedReader br=null;        OutputStream os=null;        PrintWriter pw=null;        is = socket.getInputStream();     //擷取輸入資料流        isr = new InputStreamReader(is,UTF-8);        br = new BufferedReader(isr);        String info = null;        while((info=br.readLine())!=null){//迴圈讀取用戶端的資訊            System.out.println(用戶端發送過來的資訊 + info);        }        socket.shutdownInput();//關閉輸入資料流        socket.close();    }}

然後我們把代碼run起來,控制台會列印:

好的,接下來到Android用戶端了!

4.Socket用戶端的編寫:

用戶端要做的事有這些:

Step 1:建立Socket對象,指明需要連結的伺服器的地址和端號
Step 2:連結建立後,通過輸出資料流向伺服器發送請求資訊
Step 3:通過輸出資料流擷取伺服器響應的資訊
Step 4:關閉相關資源

代碼實現:

MainActivity.java:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Button btn_accept = (Button) findViewById(R.id.btn_accept);        btn_accept.setOnClickListener(this);    }    @Override    public void onClick(View v) {        new Thread() {            @Override            public void run() {                try {                    acceptServer();                } catch (IOException e) {                    e.printStackTrace();                }            }        }.start();    }    private void acceptServer() throws IOException {        //1.建立用戶端Socket,指定伺服器位址和連接埠        Socket socket = new Socket(172.16.2.54, 12345);        //2.擷取輸出資料流,向伺服器端發送資訊        OutputStream os = socket.getOutputStream();//位元組輸出資料流        PrintWriter pw = new PrintWriter(os);//將輸出資料流封裝為列印流        //擷取用戶端的IP地址        InetAddress address = InetAddress.getLocalHost();        String ip = address.getHostAddress();        pw.write(用戶端:~ + ip + ~ 接入伺服器!!);        pw.flush();        socket.shutdownOutput();//關閉輸出資料流        socket.close();    }}

因為Android不允許在主線程(UI線程)中做網路操作,所以這裡需要我們自己
另開一個線程來串連Socket!

運行結果:

點擊按鈕後,服務端控制台列印:

5.增強版案例:小豬簡易聊天室

只是點擊個按鈕,然後伺服器返回一串資訊,肯定是很無趣的是吧,接下來我們來
搭建一個超簡單的聊天室,我們需要用到線程池,儲存Socket連結的集合,我們還需要
位元組寫一個線程,具體的我們在代碼中來體會!

實現的:

先把我們的服務端跑起來:

接著把我們的程式分別跑到兩台模擬器上:

接下來我們來寫代碼:

首先是服務端,就是將讀寫socket的操作放到自訂線程當中,建立ServerSocket後,迴圈
調用accept方法,當有新用戶端接入,將socket加入集合當中,同時線上程池建立一個線程!
另外,在讀取資訊的方法中,對輸入字串進行判斷,如果為bye字串,將socket從集合中
移除,然後close掉!

Server.java:

public class Server {    //定義相關的參數,連接埠,儲存Socket串連的集合,ServerSocket對象    //以及線程池    private static final int PORT = 12345;    private List mList = new ArrayList();    private ServerSocket server = null;    private ExecutorService myExecutorService = null;    public static void main(String[] args) {        new Server();    }    public Server()    {        try        {            server = new ServerSocket(PORT);            //建立線程池            myExecutorService = Executors.newCachedThreadPool();            System.out.println(服務端運行中...);            Socket client = null;            while(true)            {                client = server.accept();                mList.add(client);                myExecutorService.execute(new Service(client));            }        }catch(Exception e){e.printStackTrace();}    }    class Service implements Runnable    {        private Socket socket;        private BufferedReader in = null;        private String msg = ;        public Service(Socket socket) {            this.socket = socket;            try            {                in = new BufferedReader(new InputStreamReader(socket.getInputStream()));                 msg = 使用者: +this.socket.getInetAddress() + ~加入了聊天室                              +當前線上人數: +mList.size();                  this.sendmsg();            }catch(IOException e){e.printStackTrace();}        }        @Override        public void run() {            try{                while(true)                {                    if((msg = in.readLine()) != null)                    {                        if(msg.equals(bye))                        {                            System.out.println(~~~~~~~~~~~~~);                            mList.remove(socket);                            in.close();                            msg = 使用者: + socket.getInetAddress()                                      + 退出: +當前線上人數:+mList.size();                              socket.close();                              this.sendmsg();                              break;                        }else{                            msg = socket.getInetAddress() +    說:  + msg;                              this.sendmsg();                         }                    }                }            }catch(Exception e){e.printStackTrace();}        }        //為串連上服務端的每個用戶端發送資訊        public void sendmsg()        {            System.out.println(msg);            int num = mList.size();            for(int index = 0;index < num;index++)            {                Socket mSocket = mList.get(index);                  PrintWriter pout = null;                  try {                      pout = new PrintWriter(new BufferedWriter(                              new OutputStreamWriter(mSocket.getOutputStream(),UTF-8)),true);                      pout.println(msg);                  }catch (IOException e) {e.printStackTrace();}              }        }    }}

接著到用戶端,用戶端的痛點在於要另外開闢線程的問題,因為Android不允許直接在
主線程中做網路操作,而且不允許在主線程外的線程操作UI,這裡的做法是自己建立
一個線程,以及通過Hanlder來更新UI,實際開發不建議直接這樣做!!!

布局檔案:activity_main.xml:

                

MainActivity.java:

public class MainActivity extends AppCompatActivity implements Runnable {    //定義相關變數,完成初始化    private TextView txtshow;    private EditText editsend;    private Button btnsend;    private static final String HOST = 172.16.2.54;    private static final int PORT = 12345;    private Socket socket = null;    private BufferedReader in = null;    private PrintWriter out = null;    private String content = ;    private StringBuilder sb = null;    //定義一個handler對象,用來重新整理介面    public Handler handler = new Handler() {        public void handleMessage(Message msg) {            if (msg.what == 0x123) {                sb.append(content);                txtshow.setText(sb.toString());            }        }        ;    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        sb = new StringBuilder();        txtshow = (TextView) findViewById(R.id.txtshow);        editsend = (EditText) findViewById(R.id.editsend);        btnsend = (Button) findViewById(R.id.btnsend);        //當程式一開始啟動並執行時候就執行個體化Socket對象,與服務端進行串連,擷取輸入輸出資料流        //因為4.0以後不能再主線程中進行網路操作,所以需要另外開闢一個線程        new Thread() {            public void run() {                try {                    socket = new Socket(HOST, PORT);                    in = new BufferedReader(new InputStreamReader(socket.getInputStream(), UTF-8));                    out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(                            socket.getOutputStream())), true);                } catch (IOException e) {                    e.printStackTrace();                }            }        }.start();        //為發送按鈕設定點擊事件        btnsend.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                String msg = editsend.getText().toString();                if (socket.isConnected()) {                    if (!socket.isOutputShutdown()) {                        out.println(msg);                    }                }            }        });        new Thread(MainActivity.this).start();    }    //重寫run方法,在該方法中輸入資料流的讀取    @Override    public void run() {        try {            while (true) {                if (socket.isConnected()) {                    if (!socket.isInputShutdown()) {                        if ((content = in.readLine()) != null) {                            content += ;                            handler.sendEmptyMessage(0x123);                        }                    }                }            }        } catch (Exception e) {            e.printStackTrace();        }    }}
本節小結:

好的,本節給大家講解了基於TCP的Socket通訊,文中介紹了Socket通訊的模型,實現了
一個簡單的Socket通訊例子,以及寫了一個增強版的執行個體:小豬聊天室,相信會對剛涉及
Socket編程的你帶來便利~,謝謝~

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.