1. 程式人生 > >Android學習筆記三十六:android之socket程式設計例項

Android學習筆記三十六:android之socket程式設計例項

注意點:註冊訪問的網路許可權;android中UI執行緒不能有訪問網路的操作,否則會報android.os.NetworkOnMainThreadException的異常

    <uses-permission 
        android:name="android.permission.INTERNET"/>
Android開發聯盟③ 433233634

例項一

客戶端


package com.android.xiong.simplesocket;

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

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
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 {
	Socket socket = null;
	String buffer = "";
	TextView txt1;
	Button send;
	EditText ed1;
	String geted1;
	public Handler myHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			if (msg.what == 0x11) {
				Bundle bundle = msg.getData();
				txt1.append("server:"+bundle.getString("msg")+"\n");
			}
		}

	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		txt1 = (TextView) findViewById(R.id.txt1);
		send = (Button) findViewById(R.id.send);
		ed1 = (EditText) findViewById(R.id.ed1);
		send.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				geted1 = ed1.getText().toString();
				txt1.append("client:"+geted1+"\n");
				//啟動執行緒 向伺服器傳送和接收資訊
				new MyThread(geted1).start();
			}
		});

	}

	class MyThread extends Thread {

		public String txt1;

		public MyThread(String str) {
			txt1 = str;
		}

		@Override
		public void run() {
			//定義訊息
			Message msg = new Message();
			msg.what = 0x11;
			Bundle bundle = new Bundle();
			bundle.clear();
			try {
				//連線伺服器 並設定連線超時為5秒
				socket = new Socket();
				socket.connect(new InetSocketAddress("1.1.9.30", 30000), 5000);
				//獲取輸入輸出流
				OutputStream ou = socket.getOutputStream();
				BufferedReader bff = new BufferedReader(new InputStreamReader(
						socket.getInputStream()));
				//讀取發來伺服器資訊
				String line = null;
				buffer="";
				while ((line = bff.readLine()) != null) {
					buffer = line + buffer;
				}
				
				//向伺服器傳送資訊
				ou.write("android 客戶端".getBytes("gbk"));
				ou.flush();
				bundle.putString("msg", buffer.toString());
				msg.setData(bundle);
				//傳送訊息 修改UI執行緒中的元件
				myHandler.sendMessage(msg);
				//關閉各種輸入輸出流
				bff.close();
				ou.close();
				socket.close();
			} catch (SocketTimeoutException aa) {
				//連線超時 在UI介面顯示訊息
				bundle.putString("msg", "伺服器連線失敗!請檢查網路是否開啟");
				msg.setData(bundle);
				//傳送訊息 修改UI執行緒中的元件
				myHandler.sendMessage(msg);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	@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;
	}

}

<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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <EditText 
        android:id="@+id/ed1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="給伺服器傳送資訊"/>
    <Button 
        android:id="@+id/send"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/ed1"
        android:text="傳送"/>
    <TextView 
        android:id="@+id/txt1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/send"/>
    
    


</RelativeLayout>

服務端

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 AndroidService {


	public static void main(String[] args) throws IOException {
		ServerSocket serivce = new ServerSocket(30000);
		while (true) {
			//等待客戶端連線
			Socket socket = serivce.accept();
			new Thread(new AndroidRunable(socket)).start();
		}
	}

}

package com.android.net;

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

public class AndroidRunable implements Runnable {

	Socket socket = null;

	public AndroidRunable(Socket socket) {
		this.socket = socket;
	}

	@Override
	public void run() {
		// 向android客戶端輸出hello worild
		String line = null;
		InputStream input;
		OutputStream output;
		String str = "hello world!";
		try {
			//向客戶端傳送資訊
			output = socket.getOutputStream();
			input = socket.getInputStream();
			BufferedReader bff = new BufferedReader(
					new InputStreamReader(input));
			output.write(str.getBytes("gbk"));
			output.flush();
			//半關閉socket  
			socket.shutdownOutput();
			//獲取客戶端的資訊
			while ((line = bff.readLine()) != null) {
				System.out.print(line);
			}
			//關閉輸入輸出流
			output.close();
			bff.close();
			input.close();
			socket.close();

		} catch (IOException e) {
			e.printStackTrace();
		}

	}
}

例項二

客戶端

package com.android.xiong.sockettwotest;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
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) {
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

}
package com.android.xiong.sockettwotest;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
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;

	public ClientThread(Handler handler) {
		this.handler = handler;
	}

	@Override
	public void run() {
		s = new Socket();
		try {
			s.connect(new InetSocketAddress("1.1.9.30", 3000), 5000);
			br = new BufferedReader(new InputStreamReader(s.getInputStream()));
			os = s.getOutputStream();
			// 啟動一條子執行緒來讀取伺服器相應的資料
			new Thread() {

				@Override
				public void run() {
					String content = null;
					// 不斷的讀取Socket輸入流的內容
					try {
						while ((content = br.readLine()) != null) {
							// 每當讀取到來自伺服器的資料之後,傳送的訊息通知程式
							// 介面顯示該資料
							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 {
							os.write((msg.obj.toString() + "\r\n")
									.getBytes("gbk"));
						} 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();
		}

	}
}

<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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <EditText
        android:id="@+id/input"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/input" />
    <Button 
        android:id="@+id/send"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/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"/>

</RelativeLayout>

服務端


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 {
		ServerSocket server = new ServerSocket(3000);
		while(true){
			Socket s=server.accept();
			socketList.add(s);
			//每當客戶端連線之後啟動一條ServerThread執行緒為該客戶端服務
			new Thread(new ServiceThreada(s)).start();
			
		}
	}

}
package com.android.net;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
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){
				OutputStream os;
				try {
					os = s.getOutputStream();
					os.write((content+"\n").getBytes("gbk"));
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			}
		}

	}

	// 定義讀取客戶端的資訊
	public String readFromClient() {
		try {
			return br.readLine();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

}