Android-socket-client 客戶端實現
—————————————————————————————————————————————————————————————————————————————
開發環境:eclipse +4.0android SDK+串列埠除錯工具
前言:這周的任務是為了 完成socket客戶端在安卓平臺的開發,能夠和服務端正常進行收發資訊(還未實現漢字)。開始在網上找了很多程式用來參考,結果都不行,發現android3.0以後就不能在主執行緒(ui執行緒)中進行socket網路通訊!!看來找的程式比較老了,後來有幸找到了極客學院的一個視訊,按照上面的方法直接實現了一下,它的比較簡單,所以我又稍微優化了一下,而且它的程式還是有一點小bug的,我修改了一下,不過還有待加強。
ps:模擬器和手機上都能成功執行
首先附上極客學院的視訊地址:http://www.iqiyi.com/w_19rtlpgvl1.html
效果圖片:
客戶端(介面)
服務端:(串列埠除錯助手)
正常通訊
超時,即socket連線不上
極客學院中的視訊的小bug就是在doInBackground中使用了toast,這個應該是不允許的。
還有就是它的程式碼中用到了非同步通訊AsyncTask,我遇到的困難都是因為對它不瞭解,導致出了很多低階的錯誤,浪費了我很多的時間,給大家一個連結可以學習一下。
自己的錯誤也在程式碼中進行了註釋,希望能幫助到大家。
大家可以參考這個連結學習 http://www.cnblogs.com/devinzhang/archive/2012/02/13/2350070.html
自己程式碼的小特色:
1.可以自己手動輸入ip地址和埠號,特別是埠號我們是需要獲取數字的,所以這裡用了一個Integer.parseInt的方法,當然還增加了一個斷開連線。
2.利用了socket.connect這個介面,來判斷socket是否連線超時,即伺服器連線不上,錯誤的原因有很多,ip不對啊,埠不對,伺服器關閉等等。
個人感覺 android socket客戶端的操作流程大致是:
1.首先new 一個socket,然後用ip和埠去初始化它。
2.然後初始化它的outputstream和inputstream,輸入輸出流,當客戶端發資料是操作它的輸出流,接受資料是操作它的輸入流,將他們放入我們的buf中,最後再對buf進行操作。
ps:其實是比較簡單,對我來說很難的應該就是語法吧,很多類的規則和方法不知道怎麼去呼叫,特別是doinbackground中不能操作主執行緒中的控制元件和變數真是讓我浪費了很久的時間。
附上程式碼:
程式碼中我作了一點註釋
package com.lzj.example.msocketclient;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStreamWriter;import java.net.InetSocketAddress;import java.net.Socket;import android.app.Activity;import android.os.AsyncTask;import android.os.Bundle;import android.text.method.ScrollingMovementMethod;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;import android.widget.Toast;public class MainActivity extends Activity { private EditText ip=null,port=null; private EditText editTest=null; private TextView text=null; private Button send_btn=null,con_btn=null,discon_btn=null; private int port_num=0; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_lmain); ip=(EditText)findViewById(R.id.ip); port=(EditText)findViewById(R.id.port); editTest=(EditText)findViewById(R.id.editText); text=(TextView)findViewById(R.id.textView); text.setMovementMethod(ScrollingMovementMethod.getInstance());//使能textview滾動屬性 con_btn=(Button)findViewById(R.id.con_btn); con_btn.setOnClickListener(new OnClickListener() { public void onClick(View v) { connect(); send_btn.setEnabled(true); editTest.setEnabled(true); } }); send_btn=(Button) findViewById(R.id.send_btn); send_btn.setOnClickListener(new OnClickListener() { public void onClick(View v) { send(); } }); discon_btn=(Button)findViewById(R.id.discon_btn); discon_btn.setOnClickListener(new OnClickListener() { public void onClick(View v) { close(); } }); send_btn.setEnabled(false); editTest.setEnabled(false); } //-------------socket 實現-------------------------- Socket socket=null; BufferedWriter bw=null; BufferedReader br=null; /*android4.0後不能在主執行緒(UI執行緒)中初始化socket,進行socket網路通訊,所以我們用asynctask(非同步)來將這個過程放到後臺*/ public void connect(){ AsyncTask<Void, String, Void> read=new AsyncTask<Void, String, Void>(){ /*doInBackground(Params…) 後臺執行,比較耗時的操作都可以放在這裡。 * 在執行過程中可以呼叫publicProgress(Progress…)來更新任務的進度。*/ protected Void doInBackground(Void... arg0) {//doinbackground該方法中不能對UI當中的空間進行設定和修改 //將輸入埠的editText中獲取的string轉化為int port_num=Integer.parseInt(port.getText().toString().trim()); /*位元組流轉換成字元流可以用 InputSteamReader OutputStreamWriter 轉換成BufferdReader BufferedWriter 他們具有緩衝區 */ socket=new Socket(); String line; //用connect延時3秒來看客戶端是否連線伺服器 try { socket.connect(new InetSocketAddress(ip.getText().toString(),port_num ),3000); bw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); br=new BufferedReader(new InputStreamReader(socket.getInputStream())); publishProgress("@連線成功"); //readline是以\n結尾,所以send函式中的write方法中需要加+\n /*這個地方是我出錯的地方,只是把上面3句用try catch包圍!當第一次輸入錯誤ip的時候 * 程式會退出,是因為我把下面這個迴圈用try catch包圍了,因為下面用到了br變數 * 如果前面出錯那麼這個變數則不會被初始化!! * 同樣不能再catch中用toast,因為不能在非ui執行緒中使用它,doinbackground是在後臺執行 * 切記!花了我太久太久的時間了!*/ while ((line=br.readLine())!=null){ publishProgress(line); } } catch (IOException e1) { try {//異常檢查,如果超時或者斷開連線則則執行下面操作 publishProgress("@連線失敗(超時or斷開)"); socket.close(); } catch (IOException e) { e.printStackTrace(); } e1.printStackTrace(); } return null; } /*onProgressUpdate(Progress…) * 可以使用進度條增加使用者體驗度。 * 此方法在主執行緒執行,用於顯示任務執行的進度。 * 這裡是可以執行主執行緒中的設定,所以可以用toast*/ protected void onProgressUpdate(String... values) { super.onProgressUpdate(values); if(values[0].equals("@連線成功")){ Toast.makeText(MainActivity.this,"連線成功" ,Toast.LENGTH_SHORT).show(); } text.append("伺服器:"+values[0]+"\n"); } }; read.execute();//執行 } /*傳送資訊的函式*/ public void send() { try { text.append("本機:"+editTest.getText().toString()+"\n"); bw.write(editTest.getText().toString()+"\n"); bw.flush(); editTest.setText(""); } catch (IOException e) { e.printStackTrace(); } } /*關閉socket函式,即斷開連線*/ public void close(){ try { socket.close(); Toast.makeText(MainActivity.this,"斷開連線" ,Toast.LENGTH_SHORT).show(); send_btn.setEnabled(false); editTest.setEnabled(false); } catch (IOException e) { e.printStackTrace(); } }}
xml檔案:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/bk" tools:context="${relativePackage}.${activityClass}" > <EditText android:id="@+id/ip" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBottom="@+id/con_btn" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:layout_toLeftOf="@+id/con_btn" android:hint="請輸入伺服器ip地址" android:textColorHint="#ffff" android:ems="10" /> <EditText android:id="@+id/editText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_alignParentRight="true" android:layout_marginBottom="70dp" android:hint="編輯內容" android:textColorHint="#0000" android:ems="10" > <requestFocus /> </EditText> <Button android:id="@+id/send_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_alignParentRight="true" android:layout_marginBottom="28dp" android:text="傳送" android:textStyle="bold" /> <Button android:id="@+id/con_btn" style="?android:attr/buttonStyleSmall" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_toLeftOf="@+id/discon_btn" android:text="連線" android:textStyle="bold" /> <Button android:id="@+id/discon_btn" style="?android:attr/buttonStyleSmall" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBottom="@+id/con_btn" android:layout_alignParentRight="true" android:layout_alignParentTop="true" android:text="斷開" android:textStyle="bold" /> <!-- 設定textview下拉屬性 scrollbars “滾動條出現到消失的時間=5000ms” --> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@+id/editText" android:layout_alignParentLeft="true" android:layout_alignParentRight="true" android:layout_below="@+id/port" android:scrollbarFadeDuration="5000" android:scrollbarStyle="insideOverlay" android:scrollbars="vertical" android:textColorHint="#ffff" android:hint="聊天區域"/> <EditText android:id="@+id/port" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_below="@+id/ip" android:layout_toLeftOf="@+id/con_btn" android:ems="10" android:hint="請輸入伺服器埠號" android:textColorHint="#ffff" android:inputType="number" /></RelativeLayout>
<uses-permission android:name="android.permission.INTERNET"/>
下一篇地址: http://blog.csdn.net/liuzijiang1123/article/details/50365546
再分享一下我老師大神的人工智慧教程吧。零基礎!通俗易懂!風趣幽默!還帶黃段子!希望你也加入到我們人工智慧的隊伍中來!https://blog.csdn.net/jiangjunshow