Android網路應用之Socket(一)

來源:互聯網
上載者:User

標籤:

socket編程是網路通訊的一個基礎應用,無論是手機端還是PC端都需要socket技術來建立網路通訊。在本章小編主要從以下幾個方面來介紹socket的相關知識:

分別是“什麼是socket?”,“socket有什麼特點?”,“socket與Http以及TCP的區別”,“移動端socket的Demo”。寫的不好的地方請大家批評指正。

一、何為socket?socket也被稱為“通訊端”,它是一種網路通訊的方式,它不是一種協議,而是提供給程式員實現TCP/IP封裝與資料轉送的介面。用於在用戶端和服務端之間建立一個通訊管道,使得應用程式/用戶端可以通過這個通訊管道向伺服器/另一台主機發送請求,同時伺服器也可以進行相應,建立兩者之間的資料轉送與交換。在Android中,我們知道每個應用程式都可以使用多線程來進行操作,用於網路傳輸的app的多個線程可以都建立一個socket串連,每個線程維護自己的socket管道,從而實現並發的網路通訊。socket的組成部分主要包括5個:串連使用的協議(TCP/UDP),用戶端IP,用戶端連接埠號碼,伺服器端IP地址,伺服器端的連接埠號碼。在Android中,serverSocket用於伺服器端而socket是用於建立網路連接時用的,在串連成功時兩端都會產生一個socket對象。二、socket的特點及通訊原理我們可以看到,一個socket建立時所使用的協議可以是TCP的,也可以是UDP的。TCP是可靠的而UDP是不可靠的,原因就是TCP建立時需要三向交握,雙方建立通訊管道才可以資料轉送,且是雙向的。而UDP在資料轉送時只是把應用程式層發來的資料進行打包並且附上目的的地址,不負責對方是否接收到。一個Socket的通訊建立可以分為用戶端和服務端兩部分: 服務端:1、建立伺服器通訊端並綁定到自己的一個連接埠上,這個連接埠最好大於1024,因為0~1023連接埠號碼是被系統預留的,會被一些系統功能所調用。2、建立通訊端的監聽器,監聽是否有別的用戶端程式來請求訪問本連接埠的serverSocket。3、如果接受到,則接受請求建立串連通訊

用戶端:1、建立一個用戶端通訊端,綁定要訪問的目標伺服器的IP地址及連接埠號碼2、串連服務端(這裡與PC上的socket串連不同,不需要connect(),因為Android上的用戶端socket在建立時,如果建立成功會自動內部調用串連方法)                3、與服務端進行通訊4、主動關閉用戶端socket瞭解了用戶端與服務端的通訊過程,我們都能瞭解到:服務端其實一直保持著監聽用戶端請求的狀態,socket串連只能由發起請求的用戶端主動關閉。兩端在進行通訊的時候,資料是通過InputStream和OutputStream來實現的,且首先是服務端收到輸入資料流,再將結果通過輸出資料流返回給用戶端。而用戶端方面是先發送輸出資料流,再接收到輸入資料流。大致模式如下:                      伺服器和用戶端的串連:伺服器監聽------->用戶端請求------->建立串連三、socket與HTTP、TCP的區別首先需要知道HTTP是應用程式層協議,主要解決的是如何封裝資料。而TCP是傳輸層協議,主要解決的是如何傳輸資料。socket是TCP/IP協議的封裝,本身並不是協議。socket的串連模式與HTTP、TCP的串連模式不一致。從上節已經瞭解到socket的串連是從伺服器監聽開始的,而在TCP方面,用戶端與伺服器的串連需要經過三向交握之後才正式開始資料的傳輸,而HTTP則是基於"要求-回應"才能建立資料轉送,什麼意思呢?只有先請求,伺服器才能對外發資料,不能主動建立傳輸。在HTTP經過了0.9、1.0和1.1時代,這種串連模式可以在一次TCP串連建立時一直保持,響應多次請求。當socket是傳輸層的一個封裝,傳輸層主要由TCP和UDP協議,當socket使用的是TCP協議而不是UDP協議時,一個socket串連其實就是TCP串連。四、Demo這裡我們將建立一個demo,在Android上使用socket。我們的Demo主要功能是在編輯框中編寫一段文字,然後按發送按鈕,最後內部實現通過socket的通訊方式,反饋到textview上進行顯示編輯的內容。裡面的細節重點會在末尾處分析。下面是xml布局檔案:
        android:id="@+id/btn_conn"/>    <EditText         android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:hint="請在這裡編輯要發送的內容"        android:id="@+id/et_message"/>        <Button         android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:text="發送"        android:id="@+id/btn_sent"/>        <TextView         android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:id="@+id/tv"        android:hint="接收發來的資料"/></LinearLayout>
布局效果如下:

首先來描述下我們要實現的功能邏輯:1、通過點擊串連先建立socket通訊管道2、在編輯框中輸入我們要發送的內容,按下發送按鈕,資料會顯示到文本控制項中;3、在內部自己建立一個線程,不能在UI線程中更新,會造成ANR;4、本身即作為發送方,又作為接收方,主要過程是把資料打包發送,通過outputstream進行輸出傳輸,建立為訊息的內容;接著被handler收到,扔進訊息佇列,處理的時候再把資料解壓,進行ui更新。主要功能handler.sentmessage()和handler.handmessage()。還有就是outputstream和inputstream時的資料打包,encoding必須一致。中文可以使用GB2312.
代碼如下:
package com.example.mysocketdemo;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.io.UnsupportedEncodingException;import java.net.Socket;import java.net.UnknownHostException;import android.app.Activity;import android.app.ActionBar;import android.app.Fragment;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.text.Editable;import android.view.LayoutInflater;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.view.ViewGroup;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;import android.widget.Toast;import android.os.Build;public class MainActivity extends Activity {private TextView tv;private Button btnsent,btnconn;private EditText ed_message;private OutputStream output;private Socket clientSocket;private Handler mHandler;private MyThread mythread;boolean stop = true;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        if (savedInstanceState == null) {            getFragmentManager().beginTransaction()                    .add(R.id.container, new PlaceholderFragment())                    .commit();        }        init();        //onClickEvent---connect        btnconn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubtry {clientSocket = new Socket("127.0.0.1", 8888);} catch (UnknownHostException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}Toast.makeText(getApplicationContext(), "connect ok", Toast.LENGTH_SHORT).show();//把socket綁定到自己的線程對象try {mythread = new MyThread(clientSocket);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}mythread.start();//啟動線程//更新UI,大部分的資料工作已經交給了mythread對象btnsent.setEnabled(true);btnconn.setEnabled(false);stop = false;}});        //sent Message        btnsent.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stub//當點擊按鈕時,會擷取編輯框中的資料,然後提交給線程//先將發送內容進行打包byte[]  msgBuffer = null;try {msgBuffer = ed_message.getText().toString().getBytes("GB2312");} catch (UnsupportedEncodingException e) {// TODO Auto-generated catch blocke.printStackTrace();}//打包完成之後,添加socket的輸出資料流對象try {output = clientSocket.getOutputStream();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}try {//輸出資料流對象將位元組寫入//無論是輸出資料流還是輸入資料流,操作的都是位元組,如果向變成字串,需要自己構建String對象output.write(msgBuffer);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}Toast.makeText(getApplicationContext(), "發送成功", Toast.LENGTH_SHORT).show();ed_message.setText("");}});                //在串連和發送資料之後,接下來就是處理了,發送的資料會通過message的方式傳遞到訊息佇列,再由handl進行擷取        mHandler = new Handler(){        public void handleMessage(android.os.Message msg) {        tv.setText(msg.obj.toString());        };        };    }    public void init()    {    tv = (TextView) findViewById(R.id.tv);    btnsent = (Button) findViewById(R.id.btn_sent);    ed_message = (EditText) findViewById(R.id.et_message);    btnconn = (Button) findViewById(R.id.btn_conn);    btnconn.setEnabled(true);    btnsent.setEnabled(false);    }    //自訂線程類;    private class MyThread extends Thread{    //構建自己的socket對象,用來線上程內使用    private Socket socket;    private byte[] buf = null;    private InputStream inputstream;    String str = null;    public MyThread(Socket socket) throws IOException    {    this.socket = socket;    inputstream = this.socket.getInputStream();    }    @Override    public void run() {    // TODO Auto-generated method stub    while(!stop)    {    buf = new byte[512];    //將inputstream內的資料讀到buf裡    try {this.inputstream.read(buf);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}    try {    //將buf裡的字元流進行解析,得到this.str = new String(buf, "GB2312").trim();} catch (UnsupportedEncodingException e) {// TODO Auto-generated catch blocke.printStackTrace();}    //線程內擷取了來自socket的Inputstream位元組流,並且轉換成字串後,線程就擷取了訊息的實體內容    //此時線程將執行自己的一個使命,就是建立訊息,並發送出去    Message msg = new Message();    msg.obj = this.str;    mHandler.sendMessage(msg);    }    }    }        @Override    protected void onDestroy() {    // TODO Auto-generated method stub    if (mythread!=null) {mythread.interrupt();}    super.onDestroy();    }



瞭解代碼的邏輯之後,我再理一下整個思路:當我們點擊了connnet之後,就會建立串連目標ip地址及連接埠的socket串連,此時,什麼資料都沒有,socket的Outputstream和InputStream裡面都是空的。儘管我們自訂的線程在串連後就啟動了,並且必須執行run方法,但是此時沒有資料來接收。當我們編輯好文筆點擊了sent按鈕之後,編輯框裡的文本會由字串向位元組的封裝,使用的是String.getbyte()方法,為啥呢,因為outputstream和inputstream只接受位元組流的資料。當socket的getOutputStream擷取了outputstream對象之後,執行了write方法進行資料的寫入,而此時線程依然在執行,它突然發現串連的socket裡有資料了,就使用getIupteStream擷取了inputstream對象,採用了read方法讀取了位元組流,最後打包成字串。打包成字串之後,線程要執行一個自己的使命,就是將其封裝成訊息,以訊息的形式塞給主線程的訊息佇列,此時UI線程的使者Hanlder就完成了sendmessage的任務。最後回到主線程,Handler對象使用handlmessage方法將訊息的內容顯示在了textView上。
以上就是整個邏輯。

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

Android網路應用之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.