標籤:stream input 服務端 super public strong 響應 xtend 圖片
Android用戶端與本機伺服器Socket通訊
Socket伺服器運行結果圖??
一.用戶端和伺服器端的選擇:
- 用戶端是我們手機端,關於伺服器端,只要安裝了JDK,自然就擁有通訊的功能,我們只需要在Eclipse或者MyEclipse中寫好文章中伺服器端的代碼,運行起來即可,用accept()方法啟動伺服器端,等待用戶端的串連,在未串連的情況下,伺服器端處於堵塞的狀態。
二.用戶端注意事項
andriod用戶端添加網路存取權限
<uses-permission android:name="android.permission.INTERNET" />
對Socket的操作放在非UI線程內進行
要使用正確的IP地址和連接埠號碼連接埠號碼的範圍是0~65535,1024一下的連接埠被系統分給了一些服務,在cmd視窗執行netstat -ano
命令可以看到所有連接埠的使用方式
- 真機進行調試(1、串連上手機,手機開啟adb。步驟:設定> 應用程式> 開發>選擇USB調試;usb選項有些不可見,具體百度),指定Server的IP地址,此地址為區域網路地址,如果是使用WIFI上網,則為PC機的WIFI IP。中串連的第二個就是樣本。
三.Socket通訊
利用ip地址+連接埠號碼唯一標示網路中的一個進程,能夠唯一標示網路中的進程後,它們就可以利用socket進行通訊。
socket是在應用程式層和傳輸層之間的一個抽象層,它把TCP/IP層複雜的操作抽象為幾個簡單的介面供應用程式層調用,實現進程在網路中通訊。
socket是"開啟—讀/寫—關閉"模式的實現(只能讀取對方放在流中的資料),以使用TCP協議通訊的socket為例,其互動流程大概是這樣子的
Socket有兩種主要的操作方式:連線導向的和不需連線的,即TCP和UDP。
連線導向的Socket操作就像一部電話,Socket必須在發送資料之前與目的地的Socket取得串連,一旦串連建立了,Socket就可以使用一個流介面進行開啟、讀寫以及關閉操作。並且,所有發送的資料在另一端都會以相同的順序被接收。
- 不需連線的Socket操作就像一個郵件投遞,每一個資料報都是一個獨立的單元,它包含了這次投遞的所有資訊(目的地址和要發送的內容)。在這個模式下的Socket不需要串連目的地Socket,它只是簡單的投出資料報。
四.TCP串連與HTTP串連與Socket串連的區別
TCP串連與HTTP串連的區別
HTTP是基於TCP的,用戶端往服務端發送一個HTTP請求時第一步就是要建立與服務端的TCP串連。
socket層只是在TCP/UDP傳輸層上做的一個抽象介面層,基於TCP協議的socket串連同樣需要通過三向交握建立串連,是可靠的;基於UDP協議的socket串連不需要建立串連的過程,不過對方能不能收到都會發送過去,是不可靠的,大多數的即時通訊IM都是後者。
HTTP是短串連,Socket(基於TCP協議的)是長串連。儘管HTTP1.1開始支援持久串連,但仍無法保證始終串連。而Socket串連一旦建立TCP三向交握,除非一方主動斷開,否則串連狀態一直保持。
HTTP串連服務端無法主動發訊息。決定二者分別適合應用在什麼情境下。HTTP採用“要求-回應”機制,必須滿足用戶端發送訊息在前,服務端回複在後。Socket串連雙方類似peer2peer的關係,一方隨時可以向另一方喊話。
用HTTP的情況:雙方不需要時刻保持串連線上,比如用戶端資源的擷取、檔案上傳等。
用Socket的情況:大部分即時通訊應用(QQ、)、聊天室、蘋果APNs等。
五.socket代碼
用戶端代碼
public class MainActivity extends AppCompatActivity {//IP地址和連接埠號碼public static String IP_ADDRESS = "192.168.1.106";public static int PORT = 2346;//三個控制項EditText text = null;Button connect = null;TextView info = null;//handlerHandler handler = null;Socket soc = null;DataOutputStream dos = null;DataInputStream dis = null;String messageRecv = null;@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); text = (EditText) findViewById(R.id.editText); connect = (Button) findViewById(R.id.buttonConnection); info = (TextView) findViewById(R.id.info); connect.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new ConnectionThread(text.getText().toString()).start(); } }); handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); Bundle b = msg.getData(); //擷取訊息中的Bundle對象 String str = b.getString("data"); //擷取鍵為data的字串的值 info.append(str); } }; } //建立一個子線程,實現socket通訊 class ConnectionThread extends Thread { String message = null; public ConnectionThread(String msg) { message = msg; } @Override public void run() { if (soc == null) { try { //Log.d("socket","new socket"); soc = new Socket(IP_ADDRESS, PORT); //擷取socket的輸入輸出資料流 dis = new DataInputStream(soc.getInputStream()); dos = new DataOutputStream(soc.getOutputStream()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } try { dos.writeUTF(message); dos.flush(); messageRecv = dis.readUTF();//如果沒有收到資料,會阻塞 Message msg = new Message(); Bundle b = new Bundle(); b.putString("data", messageRecv); msg.setData(b); handler.sendMessage(msg); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}}
`
伺服器端代碼
public class Server {ServerSocket serverSocket = null;public final int port = 2346;public Server(){ //輸出伺服器的IP地址 try { InetAddress addr = InetAddress.getLocalHost(); System.out.println("local host:"+addr); serverSocket = new ServerSocket(port); System.out.println("0k"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }}public void startService(){ try { Socket socket = null; System.out.println("waiting..."); //等待串連,每建立一個串連,就建立一個線程 while(true){ socket = serverSocket.accept();//等待一個用戶端的串連,在串連之前,此方法是阻塞的 System.out.println("connect to"+socket.getInetAddress()+":"+socket.getLocalPort()); new ConnectThread(socket).start(); } } catch (IOException e) { // TODO Auto-generated catch block System.out.println("IOException"); e.printStackTrace(); }}//向用戶端發送資訊class ConnectThread extends Thread{ Socket socket = null; public ConnectThread(Socket socket){ super(); this.socket = socket; } @Override public void run(){ try { DataInputStream dis = new DataInputStream(socket.getInputStream()); DataOutputStream dos = new DataOutputStream(socket.getOutputStream()); while(true){ String msgRecv = dis.readUTF(); System.out.println("msg from client:"+msgRecv); dos.writeUTF("received:"+msgRecv); dos.flush(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}public static void main(String[] args) { // TODO Auto-generated method stub new Server().startService();}}
代碼的邏輯
用戶端 :
初始化控制項,並綁定監聽器,編寫按鈕的事件處理代碼。
- 在事件處理代碼中開啟子線程,子線程中通過Sockt訪問伺服器。
利用非同步訊息處理機制,message對象將子線程的資料傳回handle的處理方法更新UI。
服務端
- serversocket對象監聽等待,利用迴圈當有客戶訪問就開啟子線程處理傳訊息回用戶端。(模擬器和手機同時通過區域網路訪問)
最後的廢話
搞電腦必須得有理論指導實踐,否則只能像個沒頭蒼蠅到處亂撞,我的電腦網路知識真的是一言難盡。
- 各大語言的官網是個好東西。豐富的資料和教程簡直讓人沉醉其中不能自拔。雖然比不上網路小說通俗易懂,但是引人入勝一點也不差。
不會的東西太多,用Google外掛程式等工具列表,先解決主要的,平時有想法也可以記錄。
用部落格整理自己的知識,形成體系。看得再多不如編一遍。
PS. 整合了很多地方的知識點,官網,博主,就不一一記錄原地址了。
2018-05-13 22:15:53 星期日
Android用戶端與本機伺服器Socket通訊