Android Socket編程實例

最近一段時間在斷斷續續地學習Android應用開發的一些知識,許多APP運行時都要服務器進行通信,socket可以很好完成這樣一個功能。我在網上找到了一些手機和服務器通過socket通信的例子,然後挑了其中兩個進行整合,供給像我一樣的Android socket初學者進行參考。

兩個例子的鏈接:

例子一:http://blog.csdn.net/wuchuanpingstone/article/details/6617276

例子二:http://blog.csdn.net/x605940745/article/details/17001641

我把兩個例子整合成以下內容:


一、Android socket使用時要注意的地方

1、在Android主線程中不能有訪問socket的操作,否則會報異常。

2、在Android工程配置文件中要進行網絡權限聲明: <uses-permission   android:name="android.permission.INTERNET"/>

      3、對數據進行發送接收操作時,首先獲取socket流,然後可以封裝成BufferedWriter和BufferedReader:

     br = new BufferedReader(new InputStreamReader(s.getInputStream()));//把socket輸入流封裝成BufferedReader
     os=new PrintWriter(new BufferedWriter(new OutputStreamWriter(s.getOutputStream())), true);//把socket輸出流封裝成PrintWriter
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">4、對socket進行讀寫之前還要判斷,連接是否還存在:</span>
		if(!s.isClosed()&&s.isConnected()){
	           //進行socket讀寫操作<span style="white-space:pre">								
                 }
     

5、由於在主線程中不能訪問網絡的操作,所以socket通信還涉及到多線程的知識點;同樣,UI控件的更新只能在主線程中進行,所以還涉及到Android消息處理機制相關知識點。


二、實例代碼

Android客戶端代碼:

AndroidManifest.xml配置文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.client"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-permission   
    android:name="android.permission.INTERNET"/> 
    
    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="21" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>


activity_main:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
   >

   <EditText  
        android:id="@+id/input"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:hint="to send to the server" />  
    <Button   
        android:id="@+id/send"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:text="send"  
        android:layout_below="@id/input"/>  
    <TextView   
        android:id="@+id/show"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:layout_below="@id/send"/>
    
    
    

</LinearLayout>



MainActivity.java:

package com.example.client;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;


public class MainActivity extends Activity {

	// 定義界面上的兩個文本框  
    EditText input;  
    TextView show;  
    // 定義界面上的一個按鈕  
    Button send;  
    Handler handler;  
    // 定義與服務器通信的子線程  
    ClientThread clientThread; 
	
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        input = (EditText) findViewById(R.id.input);  
        show = (TextView) findViewById(R.id.show);  
        send = (Button) findViewById(R.id.send);  
        
        
        handler = new Handler() {  
  
            @Override  
            public void handleMessage(Message msg) {  
                // 如果消息來自子線程  
                if (msg.what == 0x123) {  
                    // 將讀取的內容追加顯示在文本框中  
                    show.append("\n" + msg.obj.toString());  
                }  
            }  
        };  
        
        clientThread = new ClientThread(handler);  
        // 客戶端啓動ClientThread線程創建網絡連接、讀取來自服務器的數據  
        new Thread(clientThread).start();  
        
        
        send.setOnClickListener(new OnClickListener() {  
  
            @Override  
            public void onClick(View v) {  
                try {  
                    // 當用戶按下按鈕之後,將用戶輸入的數據封裝成Message  
                    // 然後發送給子線程Handler  
                    Message msg = new Message();  
                    msg.what = 0x345;  
                    msg.obj = input.getText().toString();  
                    clientThread.revHandler.sendMessage(msg);  
                    input.setText("");  
  
                } catch (Exception e) {  
  
                }  
            }  
        });  
        
        
    }


     
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

ClientThread.java:

package com.example.client;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;

public class ClientThread implements Runnable {

	private Socket s;  
    // 定義向UI線程發送消息的Handler對象  
    Handler handler;  
    // 定義接收UI線程的Handler對象  
    Handler revHandler;  
    // 該線程處理Socket所對用的輸入輸出流  
    BufferedReader br = null;  
    //OutputStream os = null;
    PrintWriter os = null;
    
    public ClientThread(Handler handler) {  
        this.handler = handler;  
    }  

    @Override  
    public void run() {  //接收數據線程是發送數據線程的子線程
        s = new Socket();  
        try {  
            s.connect(new InetSocketAddress("121.248.52.236", 3000), 5000);  
            br = new BufferedReader(new InputStreamReader(s.getInputStream()));  
           // os = s.getOutputStream(); 
            os=new PrintWriter(new BufferedWriter(new OutputStreamWriter(s.getOutputStream())), true);
            // 啓動一條子線程來讀取服務器相應的數據  
            new Thread(new Runnable() {  
  
                @Override  
                public void run() {  
                    String content = null;  
                    // 不斷的讀取Socket輸入流的內容  
                    try {  
                        while ((content = br.readLine()) != null) {  
                            // 每當讀取到來自服務器的數據之後,發送的消息通知程序  
                            // 界面顯示該數據  
                        	if(!s.isClosed()&&s.isConnected()){
                        		Message msg = new Message();  
                        		msg.what = 0x123;  
                            	msg.obj = content;  
                            	handler.sendMessage(msg);  
                        	}
                        }  
                    } catch (IOException io) {  
                        io.printStackTrace();  
                    }  
                }  
  
            }).start();  
            // 爲當前線程初始化Looper  
            Looper.prepare();  
            // 創建revHandler對象  
            revHandler = new Handler() {  
  
                @Override  
                public void handleMessage(Message msg) {  
                    // 接收到UI線程的中用戶輸入的數據  
                    if (msg.what == 0x345) {  
                        // 將用戶在文本框輸入的內容寫入網絡  
                        try { 
                        	if(!s.isClosed()&&s.isConnected()){
                        		//os.write((msg.obj.toString() + "\r\n").getBytes("gbk"));  
                        		os.println(msg.obj.toString());
                        	}
                        } catch (Exception e) {  
                            e.printStackTrace();  
                        }  
                    }
                    
                    
                }  
  
            };   
            // 啓動Looper  
            Looper.loop();  
  
        } catch (SocketTimeoutException e) {  
            Message msg = new Message();  
            msg.what = 0x123;  
            msg.obj = "網絡連接超時!";  
            handler.sendMessage(msg);  
        } catch (IOException io) {  
            io.printStackTrace();  
        }  
  
    }  

	

}

Java服務端代碼:


MyService.java:

package com.android.net;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

public class MyService {

	// 定義保存所有的Socket  
    public static List<Socket> socketList = new ArrayList<Socket>();  
  
    public static void main(String[] args) throws IOException {  
    	System.out.println("Server start...");
        ServerSocket server = new ServerSocket(3000);  
        while(true){  
            Socket s=server.accept();  
            socketList.add(s);  
            //每當客戶端連接之後啓動一條ServerThread線程爲該客戶端服務  
            new Thread(new ServiceThreada(s)).start();  
              
        }  
    }  

}


ServiceThreada.java:

package com.android.net;

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

public class ServiceThreada implements Runnable {

	 // 定義當前線程處理的Socket  
    Socket s = null;  
    // 該線程所處理的Socket所對應的輸入流  
    BufferedReader br = null;  
  
    public ServiceThreada(Socket s) {  
        this.s = s;  
        try {  
            br = new BufferedReader(new InputStreamReader(s.getInputStream()));  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  
  
    @Override  
    public void run() {  
  
        String content = null;  
        //採用循環不斷的從Socket中讀取客戶端發送過來的數據  
        while((content=readFromClient())!=null){  
            //遍歷socketList中的每個Socket  
            //將讀取到的內容每個向Socket發送一次  
           // for(Socket s:MyService.socketList)  
        	if(!s.isClosed()&&s.isConnected()){
                //OutputStream os;
        		PrintWriter os=null;
                try {
                	 //os = s.getOutputStream(); 
                	os=new PrintWriter(new BufferedWriter(new OutputStreamWriter(  
                            s.getOutputStream())), true);
                	if(content.equals("quit")){
                		System.out.println("user"+s.getInetAddress()+"offline");
                		//os.write(("From server:"+"user"+s.getInetAddress()+"offline"+"\n").getBytes("gbk"));
                		os.println("From server:user:"+s.getInetAddress()+"offline");
                		s.close();
                	}else{
                    	System.out.println("From client:"+content);
                    	//os.write(("From server:"+content+"\n").getBytes("gbk"));
                    	os.println("From server:"+content);
                	}
                } catch (IOException e) {  
                    // TODO Auto-generated catch block  
                    e.printStackTrace();  
                }  
                  
            }  
        }  
  
    }  
  
    // 定義讀取客戶端的信息  
    public String readFromClient() {  
        try {  
        	if(!s.isClosed()&&s.isConnected()){
        		return br.readLine();  
        	}
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return null;  
    }  
	

}



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