基於TCP的安卓服務器開發
阿新 • • 發佈:2017-05-12
test afr Coding 發送數據 ipaddress 結果 nco tput 服務器開發
一.說明
前文介紹了基於安卓客戶端的開發,在此基礎上,進行少許改動即可開發出一款基於TCP的安卓服務器,理論知識請參見筆者上一篇博文,下面直接實踐操作。
二.權限申明
1 <!--允許應用程序改變網絡狀態--> 2 <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/> 3 4 <!--允許應用程序改變WIFI連接狀態--> 5 <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/> 67 8 <!--允許應用程序訪問有關的網絡信息--> 9 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> 10 11 <!--允許應用程序訪問WIFI網卡的網絡信息--> 12 <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> 13 14 <!--允許應用程序完全使用網絡--> 15 <uses-permission android:name="android.permission.INTERNET"/>
三.布局文件
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:orientation="vertical" android:layout_width="match_parent" 4 android:layout_height="match_parent"> 5 <LinearLayout 6 android:layout_width="match_parent" 7android:layout_height="wrap_content" 8 android:layout_marginLeft="10dp" 9 android:layout_marginRight="10dp" 10 android:layout_marginTop="10dp" 11 android:layout_marginBottom="10dp"> 12 <TextView 13 android:id="@+id/LocalIPTextView" 14 android:layout_width="match_parent" 15 android:layout_height="wrap_content" 16 android:hint="本機IP:" 17 android:textSize="25dp"/> 18 </LinearLayout> 19 <LinearLayout 20 android:layout_width="match_parent" 21 android:layout_height="wrap_content" 22 android:layout_marginLeft="10dp" 23 android:layout_marginRight="10dp" 24 android:layout_marginBottom="10dp"> 25 > 26 <EditText 27 android:id="@+id/MessagetoSendEditText" 28 android:layout_width="0dp" 29 android:layout_height="match_parent" 30 android:layout_weight="3" 31 android:text="Data from Server"/> 32 <Button 33 android:id="@+id/SendButton" 34 android:layout_width="0dp" 35 android:layout_height="wrap_content" 36 android:layout_weight="1" 37 android:text="發送"/> 38 </LinearLayout> 39 40 <LinearLayout 41 android:layout_width="match_parent" 42 android:layout_height="wrap_content" 43 android:layout_marginLeft="10dp" 44 android:layout_marginRight="10dp" 45 46 android:layout_marginBottom="10dp"> 47 <TextView 48 android:id="@+id/DisplayTextView" 49 android:layout_width="match_parent" 50 android:layout_height="wrap_content" 51 android:textSize="25dp"/> 52 </LinearLayout> 53 54 55 </LinearLayout>
四.具體實現代碼
1 package com.example.john.androidsockettest; 2 3 import android.content.Context; 4 import android.net.ConnectivityManager; 5 import android.net.NetworkInfo; 6 import android.net.wifi.WifiInfo; 7 import android.net.wifi.WifiManager; 8 import android.os.Handler; 9 import android.os.Message; 10 import android.support.v7.app.AppCompatActivity; 11 import android.os.Bundle; 12 import android.view.View; 13 import android.widget.Button; 14 import android.widget.EditText; 15 import android.widget.TextView; 16 17 import java.io.BufferedReader; 18 import java.io.IOException; 19 import java.io.InputStreamReader; 20 import java.io.OutputStream; 21 import java.net.Inet4Address; 22 import java.net.InetAddress; 23 import java.net.NetworkInterface; 24 import java.net.ServerSocket; 25 import java.net.Socket; 26 import java.net.SocketException; 27 import java.util.Enumeration; 28 29 public class MainActivity extends AppCompatActivity { 30 31 //線程及套接字定義 32 public Socket socket = null; 33 public ServerSocket serverSocket = null; 34 private AcceptThread acceptThread = null; 35 private ReceiveThread receiveThread = null; 36 private SendThread sendThread = null; 37 //Handler中的消息類型 38 public static final int DEBUG = 0x00; 39 public static final int RECEIVEDATAFROMCLIENT = 0x01; 40 public static final int SENDDATATOCLIENT = 0x02; 41 //控件 42 private TextView localIPTextView; 43 private EditText messagetoSendEditText; 44 private Button sendButton; 45 private TextView displayTextView; 46 //變量定義 47 String messagetoSend=""; 48 49 public Handler myHandler = new Handler() { 50 @Override 51 public void handleMessage(Message msg) { 52 if (msg.what == RECEIVEDATAFROMCLIENT) { 53 Bundle bundle = msg.getData(); 54 displayTextView.append("Client:"+bundle.getString("string1")+"\n"); 55 } 56 else if (msg.what == DEBUG) { 57 Bundle bundle = msg.getData(); 58 displayTextView.append("Debug:"+bundle.getString("string1")+"\n"); 59 } 60 else if (msg.what == SENDDATATOCLIENT) { 61 Bundle bundle = msg.getData(); 62 displayTextView.append("Server:"+bundle.getString("string1")+"\n"); 63 } 64 } 65 66 }; 67 //子線程更新UI 68 public void SendMessagetoHandler(final int messageType , String string1toHandler){ 69 Message msg = new Message(); 70 msg.what = messageType; //消息類型 71 Bundle bundle = new Bundle(); 72 bundle.clear(); 73 bundle.putString("string1", string1toHandler); //向bundle中添加字符串 74 msg.setData(bundle); 75 myHandler.sendMessage(msg); 76 } 77 @Override 78 protected void onCreate(Bundle savedInstanceState) { 79 super.onCreate(savedInstanceState); 80 setContentView(R.layout.activity_main); 81 //控件對象獲取 82 localIPTextView = (TextView)findViewById(R.id.LocalIPTextView); 83 messagetoSendEditText = (EditText)findViewById(R.id.MessagetoSendEditText); 84 sendButton = (Button)findViewById(R.id.SendButton); 85 displayTextView = (TextView)findViewById(R.id.DisplayTextView); 86 //服務器IP獲取顯示 87 localIPTextView.setText("本機IP:"+getIPAddress(this)); 88 //開啟接受線程 89 acceptThread = new AcceptThread(); 90 acceptThread.start(); 91 sendButton.setOnClickListener(new View.OnClickListener() { 92 93 @Override 94 public void onClick(View v) { 95 messagetoSend = messagetoSendEditText.getText().toString(); 96 //使用連接成功後得到的socket構造發送線程,每點擊一次send按鈕觸發一次發送線程 97 sendThread = new SendThread(socket); 98 sendThread.start(); 99 } 100 }); 101 102 } 103 //***** 接受線程 ***** 104 class AcceptThread extends Thread{ 105 @Override 106 public void run() { 107 try{ 108 serverSocket = new ServerSocket(8086); 109 socket = serverSocket.accept(); 110 }catch (IOException e){ 111 e.printStackTrace(); 112 } 113 SendMessagetoHandler(DEBUG,"客戶端連接成功!"); 114 //構造並開啟接收線程 115 receiveThread = new ReceiveThread(socket); 116 receiveThread.start(); 117 } 118 } 119 //******** 接收線程 ********** 120 class ReceiveThread extends Thread{ 121 122 private Socket mSocket; 123 //接收線程的構造函數,由接受線程傳入套接字 124 public ReceiveThread(Socket socket){mSocket = socket;} 125 @Override 126 public void run() { 127 while(true){ //連接成功後將一直運行 128 try { 129 BufferedReader bufferedReader; 130 String line = null; 131 String readBuffer=""; 132 bufferedReader = new BufferedReader(new InputStreamReader(mSocket.getInputStream())); 133 134 while ((line = bufferedReader.readLine()) != null) { 135 readBuffer = line + readBuffer; 136 SendMessagetoHandler(RECEIVEDATAFROMCLIENT,readBuffer); 137 readBuffer = ""; 138 } 139 140 }catch (IOException e) { 141 e.printStackTrace(); 142 //更新UI:顯示發送錯誤信息 143 SendMessagetoHandler(DEBUG,"接收失敗!"); 144 return; 145 } 146 } 147 } 148 } 149 //******** 發送線程 ********** 150 class SendThread extends Thread{ 151 private Socket mSocket; 152 //發送線程的構造函數,由接受線程傳入套接字 153 public SendThread(Socket socket) {mSocket = socket;} 154 155 @Override 156 public void run() { 157 try{ 158 OutputStream outputStream = mSocket.getOutputStream(); 159 //向服務器發送信息 160 outputStream.write(messagetoSend.getBytes("gbk")); 161 outputStream.flush(); 162 //更新UI:顯示發送出的數據 163 SendMessagetoHandler(SENDDATATOCLIENT,messagetoSend); 164 }catch (IOException e) { 165 e.printStackTrace(); 166 //更新UI:顯示發送錯誤信息 167 SendMessagetoHandler(DEBUG,"發送失敗!"); 168 return; 169 } 170 } 171 } 172 //***** 獲取本機的ip地址 173 private String getlocalip(){ 174 WifiManager wifiManager = (WifiManager)this.getApplicationContext().getSystemService(Context.WIFI_SERVICE); 175 WifiInfo wifiInfo = wifiManager.getConnectionInfo(); 176 int ipAddress = wifiInfo.getIpAddress(); 177 // Log.d(Tag, "int ip "+ipAddress); 178 if(ipAddress==0)return null; 179 return ((ipAddress & 0xff)+"."+(ipAddress>>8 & 0xff)+"." 180 +(ipAddress>>16 & 0xff)+"."+(ipAddress>>24 & 0xff)); 181 } 182 183 public static String getIPAddress(Context context) { 184 NetworkInfo info = ((ConnectivityManager) context 185 .getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo(); 186 if (info != null && info.isConnected()) { 187 if (info.getType() == ConnectivityManager.TYPE_MOBILE) {//當前使用2G/3G/4G網絡 188 try { 189 //Enumeration<NetworkInterface> en=NetworkInterface.getNetworkInterfaces(); 190 for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) { 191 NetworkInterface intf = en.nextElement(); 192 for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) { 193 InetAddress inetAddress = enumIpAddr.nextElement(); 194 if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) { 195 return inetAddress.getHostAddress(); 196 } 197 } 198 } 199 } catch (SocketException e) { 200 e.printStackTrace(); 201 } 202 203 } else if (info.getType() == ConnectivityManager.TYPE_WIFI) {//當前使用無線網絡 204 WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); 205 WifiInfo wifiInfo = wifiManager.getConnectionInfo(); 206 int ipAddress = wifiInfo.getIpAddress();//得到IPV4地址 207 return ((ipAddress & 0xff)+"."+(ipAddress>>8 & 0xff)+"." //將得到的int類型的IP轉換為String類型 208 +(ipAddress>>16 & 0xff)+"."+(ipAddress>>24 & 0xff)); 209 } 210 } else { 211 //當前無網絡連接,請在設置中打開網絡 212 } 213 return null; 214 } 215 }
五.Debug
- readLine()
在實際調試當中,還是遇到了上一篇博文中readLine問題,仍將代碼貼下:
1 while ((line = bufferedReader.readLine()) != null) { 2 readBuffer = line + readBuffer; 3 SendMessagetoHandler(RECEIVEDATAFROMCLIENT,readBuffer); 4 readBuffer = ""; 5 }
這段讀取輸入流的代碼與上篇博文是一樣的,但調試的結果卻有不同。上一篇中,服務器向客戶端發送數據,即使沒有帶回車換行符,UI也會更新顯示;然而這一篇中,客戶端向服務器發送數據,如果數據結束不帶上回車換行符的話,UI就不會更新顯示,直到將客戶端端口關閉,這時之前發送的數據會一下顯示到UI。一樣的代碼,不一樣的結果,很是不解,歡迎指教!
六.實際運行效果
基於TCP的安卓服務器開發