編輯:關於Android編程
創建服務器端的步驟:
1,指定端口實例化一個ServerSocket
2,調用ServerSocket的accept方法等待連接期間阻塞
3,獲取位於底層的Socket流進行讀寫操作
4,將數據封裝成流
5,對Socket進行讀寫
6,關閉流
創建客戶端的步驟:
1,通過IP地址和端口實例化Socket,請求連接服務器
2,獲取位於底層的Socket流進行讀寫操作
3,將數據封裝成流(BufferedReader/PrintWriter,DataOutputStream/DataInputStream)的實例
4,對Socket進行讀寫
5,關閉流
使用ServerSocket創建服務器端:
public static void main(String[] args) throws IOException { // TODO Auto-generated method stub //創建一個ServerSo查看特,用於監聽客戶端Socket的連接請求 ServerSocket ss=new ServerSocket(3000); while(true){ //每當接收到客戶端Socket的請求,服務器端也對應產生一個Socket,沒接收到請求就等待。。 Socket s=ss.accept(); OutputStream os=s.getOutputStream();//服務器端產生的Socket獲取輸出流 os.write("您好,您收到了來自服務器的祝福!\n".getBytes()); os.close(); s.close(); } }客戶端使用Socket通信:
package com.example.simpleclient; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; import java.net.UnknownHostException; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.widget.TextView; public class MainActivity extends Activity { TextView text; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); text=(TextView) findViewById(R.id.text); new Thread(){ @Override public void run() { // TODO Auto-generated method stub try { //建立連接到遠程服務器的的Socket,Ip是服務器端PC的IP,測試環境是PC端服務器,手機當客戶端,PC和手機要連接同一個局域網,PC和手機在同一網段 Socket socket = new Socket("192.168.88",3000); //將Socket對應的輸入流包裝秤BufferedReader BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream())); String line=br.readLine(); text.setText("來自服務的數據:"+line); br.close(); socket.close(); } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }.start(); } }
客戶端和服務器端的輸入輸出流的問題容易搞混淆:如下圖
在客戶端:
socket.getInputStream();從socket讀來自服務器的數據
socket.getOutputStream();向socket中寫數據,傳給服務器,服務器在它的socket的輸入流讀這個數據
在服務器端:
socket.getInputStream();從socket讀來自客戶端的數據
socket.getOutputStream();向socket中寫數據,傳給客戶端,客戶端在它的socket的輸入流讀這個數據
就是說客戶端和服務器端的輸入輸出流是對應的,輸入流連接到輸出流輸入輸出流的包裝:
第一種方法:數據二進制流
DataInputStream in=new DataInputStream(socket.getInputStream());//接收客戶端信息 DataOutputStream out=new DataOutputStream(socket.getOutputStream()); //向客戶端發送消息第二種方法:
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
socketClient,java
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.Socket; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class socketClient extends Activity { private Button button; private TextView text; private EditText edit; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); button = (Button) findViewById(R.id.button); edit = (EditText) findViewById(R.id.edit); text = (TextView) findViewById(R.id.text); button.setOnClickListener(new View.OnClickListener() { private Socket socket = null; @Override public void onClick(View v) { // TODO Auto-generated method stub String sendMsg = edit.getText().toString() + "\r\n"; try { socket = new Socket("192.168.0.37", 8888); // 創建Socket,其中ip地址為我的PC機器的地址,手機通過wifi上網和服務器在一個網段 // PrintWriter out = new PrintWriter(new BufferedWriter(new // OutputStreamWriter(socket.getOutputStream())),true); // out.println(sendMsg); // // BufferedReader in = new BufferedReader(new // InputStreamReader(socket.getInputStream())); // String readMsg = in.readLine(); // if(readMsg !=null){ // text.setText(readMsg); // }else{ // text.setText("錯誤"); // } // // out.close(); // in.close(); // socket.close(); DataOutputStream out = new DataOutputStream(socket .getOutputStream()); // 向服務器發送消息 out.writeUTF(sendMsg); out.flush(); DataInputStream in = new DataInputStream(socket .getInputStream()); // 接收來自服務器的消息 String readMsg = in.readUTF(); if (readMsg != null) { text.setText(readMsg); } out.close(); in.close(); socket.close(); } catch (Exception e) { e.printStackTrace(); } } }); } }
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class Server { public Server(){ new ServerThread().start(); } class ServerThread extends Thread{ public void run() { try { ServerSocket ss=new ServerSocket(8888); ////創建一個ServerSocket對象,並讓這個ServerSocket在8888端口監聽 while(true){ Socket socket=ss.accept(); //調用ServerSocket的accept()方法,接受客戶端所發送的請求,如果客戶端沒有發送數據,那麼該線程就停滯不繼續 // try { // BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); //接收客戶端信息 // String readline = in.readLine(); // System.out.println("readline:"+readline); // // PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true); // out.println("link server success"); // // in.close(); //關閉流 // out.close();//關閉流 // socket.close();//關閉打開的socket // // } catch (Exception e) { // // TODO: handle exception // }finally{ // // socket.close();// // } try { DataInputStream in=new DataInputStream(socket.getInputStream());//接收客戶端信息 String readline=in.readUTF(); System.out.println(readline); DataOutputStream out=new DataOutputStream(socket.getOutputStream()); //向客戶端發送消息 out.writeUTF("link server success"); out.flush(); in.close(); //關閉流 out.close();//關閉流 socket.close();//關閉打開的socket } catch (Exception e) { System.out.println(e.getMessage()); } } } catch (IOException e) { System.out.println(e.getMessage()); } } } public static void main(String[] args) throws IOException { new Server(); //開啟服務器 } }
客戶端和服務器端保持長時間的通信,服務器需要不斷的讀取客戶端數據,並向客戶端寫入數據,客戶端也需要不斷的讀取服務器的數據
服務器應該為每個Socket單獨啟動一條線程,每條線程負責與一個客戶端進行通信
服務器端:
package com.hust.multithred; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; public class MyServer { /** * @param args * @throws IOException */ //服務器端保存所有Socket的ArrayList public static ArrayListsocketlist=new ArrayList (); public static void main(String[] args) throws IOException { // TODO Auto-generated method stub ServerSocket ss=new ServerSocket(3000);//ServerSocket監聽3000端口 while(true){ Socket socket_in_server=ss.accept();//循環等待客戶端的Socket socketlist.add(socket_in_server); //每接收到一個客戶端的Socket,將服務器端產生的與之對應的Socket加入數組 //為每一個Socket單獨啟動一條線程,每個線程負責與一個客戶端進行通信 SocketThread socketthread=new SocketThread(socket_in_server); new Thread(socketthread).start(); } } }
package com.hust.multithred; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.Socket; public class SocketThread implements Runnable{//線程任務類,實現Runnable接口 Socket s=null; BufferedReader br=null; public SocketThread(Socket s) throws IOException{ this.s=s; br=new BufferedReader(new InputStreamReader(s.getInputStream()));//Socket輸入流包裝成字符流,來自客戶端的數據在此輸入流上,服務器端可以讀 } public void run() { // TODO Auto-generated method stub try { String content=null; //循環不斷沖Socket中讀取客戶端發送過來的數據 while((content=readFormClient())!=null){ //每讀到數據之後,將讀到的內容向每個Socket發送一次 for(Socket s:MyServer.socketlist){ OutputStream os=s.getOutputStream(); os.write((content+"\n").getBytes("utf-8")); //寫到每個socket 的輸出流上 } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //從輸入流上讀取來自客戶端的數據方法 public String readFormClient(){ String content=null; try { content = br.readLine(); } catch (IOException e) { // TODO Auto-generated catch block MyServer.socketlist.remove(s); } return content; } }
MainActivity.java
package com.hust.multithreadclient; 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接收來自子線程的消息,負責處理消息,更新UI handler=new Handler(){ @Override //如果消息來自子線程 public void handleMessage(Message msg) { // TODO Auto-generated method stub if(msg.what==0x123){ show.append("\n"+msg.obj.toString()); } } }; //客戶端啟動ClientThread線程創建玩過連接,讀取來自服務器的數據 new Thread(new ClientThread(handler)).start(); send.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { // 當用戶按下發送按鈕後,將用戶輸入的數據封裝成Message,發給子線程的Handler,此處handler負責發送消息 Message msg=new Message(); msg.what=0x111; msg.obj=input.getText().toString(); clientthread.rvhandler.sendMessage(msg);//發給子線程的Handler input.setText(""); } }); } @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); } }
package com.hust.multithreadclient; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; import android.os.Handler; import android.os.Looper; import android.os.Message; public class ClientThread implements Runnable { Socket s; Handler handler; //定義向UI線程發送消息的Handler對象 Handler rvhandler; //定義接收UI線程消息的Handler對象 BufferedReader br=null; OutputStream os=null; public ClientThread(Handler handler){ this.handler=handler; } @Override public void run() { // TODO Auto-generated method stub try { s=new Socket("192.168.1.88",3000); br=new BufferedReader(new InputStreamReader(s.getInputStream())); os=s.getOutputStream(); //啟動一條子線程來讀取服務器端相應的數據 new Thread(){ @Override public void run() { // TODO Auto-generated method stub String content=null; try{ while((content=br.readLine())!=null){ Message msg=new Message(); msg.what=0x123; msg.obj=content; handler.sendMessage(msg);//此子線程中僅僅是讀來自服務器的數據,並發給UI線程的Handler處理 } }catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }.start(); /* * 當前客戶端線程中Handler,Android線程之間的通信是Handler來實現 * 此Hnadler接收UI線程發過來的數據,即用戶的輸入,並寫到輸出流 * 因為此Handler是接收處理消息,所以需要使用Looper * */ Looper.prepare(); rvhandler=new Handler(){ @Override public void handleMessage(Message msg) { //如果接收到UI線程中用戶輸入的數據 if(msg.what==0x111){ try{ //將用戶在文本框內的輸入內容寫入網絡 os.write((msg.obj.toString()+"\r\n").getBytes("utf-8")); }catch(IOException e){ e.printStackTrace(); } } } }; Looper.loop();//啟動looper } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
Volley 是一個 HTTP 庫,它能夠幫助 Android app 更方便地執行網絡操作,最重要的是,它更快速高效。我們可以通過開源的 AOSP 倉庫獲取到 Voll
Activity與Service之間交互並播放歌曲,為了方便,我把要播放的歌曲定死了,大家可以靈活改進 MService:復制代碼 代碼如下:package c
目標效果: 程序運行,顯示圖一的幾個按鈕,點擊按鈕分別顯示圖二到圖六的對話框,點擊對話框的某一項或者按鈕,也會顯示相應的吐司輸出。 1.activity_
前言作為一個開發者,日常會接觸到很多優秀的軟件,其實,或多或少會有這樣的想法,我能不能開發一個自己軟件,甚至辦公軟件都希望是Markdown的文本,為何用office?我