這個系列終於來到下篇了
這次要講的就是TCP協議中以一個客戶端的身份連線至伺服器端的一個過程
在開始之前一樣,提供一下這個系列的前面兩篇
->碼農日常-『Android studio』在Android上實現TCP/UDP區域網路通訊上篇-UDP伺服器端與客戶端實現
->碼農日常-『Android studio』在Android上實現TCP/UDP區域網路通訊中篇-TCP伺服器端實現
->碼農日常-『Android studio』在Android上實現TCP/UDP區域網路通訊下篇-TCP客戶端實現
同樣,因為在前兩篇之中我都有講過一些跟原理比較相關的東西
所以這篇我就不再費唇舌再講一次(-‿◦)
在上篇(中篇)中,我們演示了如何基於TCP通訊下開啟伺服器
所以這篇要演示的就是如何以客戶的身份連線到伺服器
用遊戲的角度來說,就是以玩家連線到伺服器的一個簡單實現
那麼,來看範例吧
還有Github
->https://github.com/thumbb13555/UDP_TCP_ConnectDemo
来い!
1. 介紹&加入權限
1.1 介紹專案結構
本次專案為了節省我Github的空間,所以我直接把UDP跟TCP的功能都放在一個APP
怎麼樣?很有誠意對吧(-‿◦)
來看一下專案結構吧
身為一個二合一的APP,所以主畫面(MainActivity.java)便是選擇UDP或是TCP的頁面而已
當然,這次的文章我們是選擇UDP得這個畫面
而在檔案中還有一個CommendFun.java
裡面只放了一個用來取得手機所連線到之WIfi之IP而已
我直接PO一下吧
public class CommendFun { @SuppressLint("DefaultLocale") public static String getLocalIP(Context context) { WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(WIFI_SERVICE); assert wifiManager != null; WifiInfo info = wifiManager.getConnectionInfo(); int ipAddress = info.getIpAddress(); return String.format("%d.%d.%d.%d" , ipAddress & 0xff , ipAddress >> 8 & 0xff , ipAddress >> 16 & 0xff , ipAddress >> 24 & 0xff); } }
本篇的內容是要講關於TCP通訊的Client端
也就是下圖紅匡內TCP的資料夾內的TCPActivity.java跟TCPClient.java兩個檔案
如果要知道UDP的話,麻煩電梯上到二樓
->碼農日常-『Android studio』在Android上實現TCP/UDP區域網路通訊上篇-UDP伺服器端與客戶端實現
想知道TCP通訊的Server端,請電梯上一樓
->碼農日常-『Android studio』在Android上實現TCP/UDP區域網路通訊中篇-TCP伺服器端實現
1.2 加入權限
本次的專案因為涉及到網路使用以及Wifi使用
因此必須加入相關權限
請至AndroidManifest.xml的部分
加入以下粉底白字兩行
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.jetec.udp_tcp_connectdemo"> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.INTERNET"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".TCP.TCPActivity"></activity> <activity android:name=".UDP.UDPActivity" /> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
網路的話不用特別問使用者,因此準備工作到這篇囉
接下來畫介面โ๏∀๏ใ
2. 畫介面
這是這次介面的內容
請仔細看一下本介面右上角有個切換元件
由於一個IP不會同時存在Server端與Client端
因此我們必須在介面上加以互鎖以防止閃退
效果如下
來吧,上介面
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".UDP.UDPActivity"> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" app:layout_constraintGuide_percent="0.1" /> <TextView android:id="@+id/textView_IP" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:text="本機IP: " android:textColor="@android:color/background_dark" android:textSize="18sp" android:textStyle="bold" app:layout_constraintBottom_toTopOf="@+id/guideline2" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <ToggleButton android:id="@+id/toggleButton_Server" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textOff="開啟Server" android:textOn="關閉Server" app:layout_constraintBottom_toTopOf="@+id/guideline6" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@+id/editText_Port" app:layout_constraintTop_toTopOf="@+id/guideline2" /> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" app:layout_constraintGuide_percent="0.4" /> <EditText android:id="@+id/editText_ReceiveMessage" android:layout_width="0dp" android:layout_height="0dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:layout_marginEnd="8dp" android:layout_marginBottom="8dp" android:focusable="false" android:focusableInTouchMode="false" android:gravity="top" android:minLines="20" android:inputType="textMultiLine" app:layout_constraintBottom_toTopOf="@+id/guideline4" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textView3" app:layout_constraintVertical_bias="0.0" /> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" app:layout_constraintGuide_percent="0.9" /> <TextView android:id="@+id/textView3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:text="收到的消息" android:textAppearance="@style/TextAppearance.AppCompat.Large" android:textStyle="bold" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@+id/guideline3" /> <EditText android:id="@+id/editText_Input" android:layout_width="0dp" android:layout_height="0dp" android:layout_marginStart="8dp" android:ems="10" android:hint="請輸入內容" android:inputType="textPersonName" android:text="Hello! I'm samsung" app:layout_constraintBottom_toBottomOf="@+id/button_Send" app:layout_constraintEnd_toStartOf="@+id/button_clear" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@+id/button_Send" /> <EditText android:id="@+id/editText_Port" android:layout_width="0dp" android:layout_height="0dp" android:ems="10" android:hint="Port" android:inputType="number" android:text="8888" app:layout_constraintBottom_toTopOf="@+id/guideline6" app:layout_constraintEnd_toStartOf="@+id/guideline5" app:layout_constraintStart_toEndOf="@+id/textView4" app:layout_constraintTop_toTopOf="@+id/guideline2" /> <Button android:id="@+id/button_Send" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="發送" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="@+id/guideline4" /> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline5" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintGuide_percent="0.7" /> <EditText android:id="@+id/editText_RemoteIp" android:layout_width="0dp" android:layout_height="0dp" android:layout_marginStart="8dp" android:ems="10" android:inputType="numberDecimal" android:text="192.168.50.5" app:layout_constraintBottom_toTopOf="@+id/toggleButton_ClientConnect" app:layout_constraintEnd_toStartOf="@+id/guideline5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textView5" /> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline6" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" app:layout_constraintGuide_percent="0.17" /> <TextView android:id="@+id/textView4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:text="本機Port: " android:textAppearance="@style/TextAppearance.AppCompat.Large" android:textSize="18sp" android:textStyle="bold" app:layout_constraintBottom_toTopOf="@+id/guideline6" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@+id/guideline2" /> <TextView android:id="@+id/textView5" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:text="Remote Ip:" android:textAppearance="@style/TextAppearance.AppCompat.Body1" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@+id/guideline6" /> <TextView android:id="@+id/textView6" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="Remote Port: " android:textAppearance="@style/TextAppearance.AppCompat.Body1" app:layout_constraintStart_toStartOf="@+id/guideline5" app:layout_constraintTop_toTopOf="@+id/guideline6" /> <EditText android:id="@+id/editText_RemotePort" android:layout_width="0dp" android:layout_height="0dp" android:layout_marginStart="8dp" android:ems="10" android:inputType="textPersonName" android:text="8888" app:layout_constraintBottom_toTopOf="@+id/toggleButton_ClientConnect" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="@+id/guideline5" app:layout_constraintTop_toBottomOf="@+id/textView6" /> <ToggleButton android:id="@+id/toggleButton_ClientConnect" android:layout_width="0dp" android:textOff="連線至指定Server" android:textOn="斷線" android:enabled="false" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:layout_marginEnd="16dp" android:layout_marginBottom="8dp" app:layout_constraintBottom_toTopOf="@+id/guideline3" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" /> <Button android:id="@+id/button_clear" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="清除" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/button_Send" app:layout_constraintTop_toTopOf="@+id/guideline4" /> <Switch android:id="@+id/switch_ModeChange" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Server" app:layout_constraintBottom_toTopOf="@+id/guideline2" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="@+id/guideline5" app:layout_constraintTop_toTopOf="parent" tools:ignore="UseSwitchCompatOrMaterialXml" /> </androidx.constraintlayout.widget.ConstraintLayout>
3. 撰寫TCP-Client端的主要功能
接著就是主程式的部分了
在TCP中篇中,我們由於需要抓出每個連線的裝置之裝置資訊,因此稍微複雜了一點點
但是在Client中,由於只需要連線到指定裝置,並與之溝通
因此整體來說就簡單許多(・ωー)~☆
來吧,看程式
class TCPClient implements Runnable { private String TAG = TCPServer.TAG; private PrintWriter pw; private InputStream is; private DataInputStream dis; private String serverIP; private int serverPort; private boolean isRun = true; private Socket socket; private Context context; public TCPClient(String ip , int port,Context context){ this.serverIP = ip; this.serverPort = port; this.context = context; } public boolean getStatus(){ return isRun; } public void closeClient(){ isRun = false; } public void send(byte[] msg){ try { OutputStream outputStream = socket.getOutputStream(); outputStream.write(msg); outputStream.flush(); } catch (IOException e) { e.printStackTrace(); } } public void send(String msg){ pw.print(msg); pw.flush(); } @Override public void run() { byte[] buff = new byte[100]; try { /**將Socket指向指定的IP & Port*/ socket = new Socket(serverIP,serverPort); socket.setSoTimeout(5000); pw = new PrintWriter(socket.getOutputStream(),true); is = socket.getInputStream(); dis = new DataInputStream(is); } catch (IOException e) { e.printStackTrace(); } while (isRun){ try { int rcvLen = dis.read(buff); String rcvMsg = new String(buff, 0, rcvLen, "utf-8"); Log.d(TAG, "收到訊息: "+ rcvMsg); Intent intent =new Intent(); intent.setAction(TCPServer.RECEIVE_ACTION); intent.putExtra(TCPServer.RECEIVE_STRING, rcvMsg); context.sendBroadcast(intent); } catch (IOException e) { e.printStackTrace(); } } try { pw.close(); is.close(); dis.close(); socket.close(); Log.d(TAG, "關閉Client"); } catch (IOException e) { e.printStackTrace(); } } }
整體來說跟UDP那篇的架構很相似
分姐一下程式吧
首先是幾個方法
public boolean getStatus(){ return isRun; } public void closeClient(){ isRun = false; } public void send(byte[] msg){ try { OutputStream outputStream = socket.getOutputStream(); outputStream.write(msg); outputStream.flush(); } catch (IOException e) { e.printStackTrace(); } } public void send(String msg){ pw.print(msg); pw.flush(); }
由上而下分別為
1. 取得裝置是否正在連線
2. 關閉連線
3. 發送byteArray類型的資訊
4. 發送String類型的資訊
接下來看看Run的部分
首先是開啟Socket通道
byte[] buff = new byte[100]; try { /**將Socket指向指定的IP & Port*/ socket = new Socket(serverIP,serverPort); socket.setSoTimeout(5000); pw = new PrintWriter(socket.getOutputStream(),true); is = socket.getInputStream(); dis = new DataInputStream(is); } catch (IOException e) { e.printStackTrace(); }
再來進入到While回圈,用以接收來自Server端回傳的資訊
並用Intent廣播的方式傳回Activity
while (isRun){ try { int rcvLen = dis.read(buff); String rcvMsg = new String(buff, 0, rcvLen, "utf-8"); Log.d(TAG, "收到訊息: "+ rcvMsg); Intent intent =new Intent(); intent.setAction(TCPServer.RECEIVE_ACTION); intent.putExtra(TCPServer.RECEIVE_STRING, rcvMsg); context.sendBroadcast(intent); } catch (IOException e) { e.printStackTrace(); } }
再來,是關閉TCP連線的方法(跳出While回圈即代表關閉連線)
try { pw.close(); is.close(); dis.close(); socket.close(); Log.d(TAG, "關閉Client"); } catch (IOException e) { e.printStackTrace(); }
最後,回頭來看這些方法用在哪裡吧(・ω・)b
4. 撰寫主要程式
接下來就是TCP的Activity的部分
也就是TCPActivity.java這個檔案
這次我先不PO全部,因為會混雜到上篇有聊到的TCPServer的程式
最後我當然會PO全部
Client端+UI設置的程式如下
public class TCPActivity extends AppCompatActivity { EditText edRemoteIp, edLocalPort, edReceiveMessage, edInputBox, edRemotePort; ToggleButton btClientConnect, btOpenServer, btServer; @SuppressLint("UseSwitchCompatOrMaterialCode") Switch swFunction; ExecutorService exec = Executors.newCachedThreadPool(); MyBroadcast myBroadcast = new MyBroadcast(); StringBuffer stringBuffer = new StringBuffer(); TCPClient tcpClient; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_t_c_p); //設置基本UI setBaseUI(); //設置TCP客戶端功能 setClientSwitch(); //設置發送資料功能(含伺服器/客戶端) setSendFunction(); //註冊廣播,接收來自對方設備回傳的資料 IntentFilter intentFilter = new IntentFilter(TCPServer.RECEIVE_ACTION); registerReceiver(myBroadcast, intentFilter); } private void setBaseUI() { TextView tvLocalIp = findViewById(R.id.textView_IP); tvLocalIp.setText("本機IP: " + getLocalIP(this)); Button btClear = findViewById(R.id.button_clear); btClear.setOnClickListener(v -> { stringBuffer.delete(0, stringBuffer.length()); edReceiveMessage.setText(stringBuffer); }); btOpenServer = findViewById(R.id.toggleButton_Server); btClientConnect = findViewById(R.id.toggleButton_ClientConnect); edRemoteIp = findViewById(R.id.editText_RemoteIp); edRemotePort = findViewById(R.id.editText_RemotePort); edLocalPort = findViewById(R.id.editText_Port); edReceiveMessage = findViewById(R.id.editText_ReceiveMessage); edInputBox = findViewById(R.id.editText_Input); swFunction = findViewById(R.id.switch_ModeChange); swFunction.setChecked(false); //設置模式切換之Switch swFunction.setOnCheckedChangeListener((buttonView, isChecked) -> { btOpenServer.setEnabled(!isChecked); btClientConnect.setEnabled(isChecked); if (!isChecked) { if (tcpClient != null && tcpClient.getStatus()) { tcpClient.closeClient(); btClientConnect.setChecked(false); } swFunction.setText("Server"); } else { swFunction.setText("Client"); } }); } /**設置TCP客戶端功能*/ private void setClientSwitch() { String remoteIp = edRemoteIp.getText().toString(); int remotePort = Integer.parseInt(edRemotePort.getText().toString()); btClientConnect.setOnCheckedChangeListener((buttonView, isChecked) -> { if (isChecked) { tcpClient = new TCPClient(remoteIp, remotePort, this); exec.execute(tcpClient); edRemoteIp.setEnabled(false); edRemotePort.setEnabled(false); } else { tcpClient.closeClient(); edRemoteIp.setEnabled(true); edRemotePort.setEnabled(true); } }); } /**設置發送資料功能(含伺服器/客戶端)*/ private void setSendFunction() { Button btSend = findViewById(R.id.button_Send); btSend.setOnClickListener(v -> { String text = edInputBox.getText().toString(); //切換開關在Client模式時 if (tcpClient == null)return; if (text.length() == 0 || !tcpClient.getStatus()) return; exec.execute(() -> tcpClient.send(text)); }); } private class MyBroadcast extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String mAction = intent.getAction(); assert mAction != null; /**接收來自UDP回傳之訊息*/ switch (mAction) { case TCPServer.RECEIVE_ACTION: String msg = intent.getStringExtra(TCPServer.RECEIVE_STRING); byte[] bytes = intent.getByteArrayExtra(TCPServer.RECEIVE_BYTES); stringBuffer.append("收到: ").append(msg).append("\n"); edReceiveMessage.setText(stringBuffer); break; } } } @Override protected void onDestroy() { super.onDestroy(); //取消監聽廣播 unregisterReceiver(myBroadcast); } }
在我的標注中有深紫紅、粉、藍、綠、土黃這五個顏色的底
深紫紅是剛才我們上面TCP-Client的主要部分
粉是連線指定Server
藍是斷開連線
綠是對伺服器發送訊息
土黃則是接收客戶端傳送資訊的部分
最後,PO一下包含上篇有用到的Server端程式全部PO出來
public class TCPActivity extends AppCompatActivity { EditText edRemoteIp, edLocalPort, edReceiveMessage, edInputBox, edRemotePort; ToggleButton btClientConnect, btOpenServer, btServer; @SuppressLint("UseSwitchCompatOrMaterialCode") Switch swFunction; ExecutorService exec = Executors.newCachedThreadPool(); MyBroadcast myBroadcast = new MyBroadcast(); StringBuffer stringBuffer = new StringBuffer(); TCPServer tcpServer; TCPClient tcpClient; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_t_c_p); //設置基本UI setBaseUI(); //設置TCP伺服器功能 setServerSwitch(); //設置TCP客戶端功能 setClientSwitch(); //設置發送資料功能(含伺服器/客戶端) setSendFunction(); //註冊廣播,接收來自對方設備回傳的資料 IntentFilter intentFilter = new IntentFilter(TCPServer.RECEIVE_ACTION); registerReceiver(myBroadcast, intentFilter); } private void setBaseUI() { TextView tvLocalIp = findViewById(R.id.textView_IP); tvLocalIp.setText("本機IP: " + getLocalIP(this)); Button btClear = findViewById(R.id.button_clear); btClear.setOnClickListener(v -> { stringBuffer.delete(0, stringBuffer.length()); edReceiveMessage.setText(stringBuffer); }); btOpenServer = findViewById(R.id.toggleButton_Server); btClientConnect = findViewById(R.id.toggleButton_ClientConnect); edRemoteIp = findViewById(R.id.editText_RemoteIp); edRemotePort = findViewById(R.id.editText_RemotePort); edLocalPort = findViewById(R.id.editText_Port); edReceiveMessage = findViewById(R.id.editText_ReceiveMessage); edInputBox = findViewById(R.id.editText_Input); swFunction = findViewById(R.id.switch_ModeChange); swFunction.setChecked(false); //設置模式切換之Switch swFunction.setOnCheckedChangeListener((buttonView, isChecked) -> { btOpenServer.setEnabled(!isChecked); btClientConnect.setEnabled(isChecked); if (!isChecked) { if (tcpClient != null && tcpClient.getStatus()) { tcpClient.closeClient(); btClientConnect.setChecked(false); } swFunction.setText("Server"); } else { if (tcpServer != null && tcpServer.getStatus()) { tcpServer.closeServer(); btServer.setChecked(false); } swFunction.setText("Client"); } }); } /**設置TCP伺服器功能*/ private void setServerSwitch() { btServer = findViewById(R.id.toggleButton_Server); ExecutorService exec = Executors.newCachedThreadPool(); btServer.setOnCheckedChangeListener((buttonView, isChecked) -> { if (isChecked) { int port = Integer.parseInt(edLocalPort.getText().toString()); tcpServer = new TCPServer(port, this); exec.execute(tcpServer); edLocalPort.setEnabled(false); } else { tcpServer.closeServer(); edLocalPort.setEnabled(true); } }); } /**設置TCP客戶端功能*/ private void setClientSwitch() { String remoteIp = edRemoteIp.getText().toString(); int remotePort = Integer.parseInt(edRemotePort.getText().toString()); btClientConnect.setOnCheckedChangeListener((buttonView, isChecked) -> { if (isChecked) { tcpClient = new TCPClient(remoteIp, remotePort, this); exec.execute(tcpClient); edRemoteIp.setEnabled(false); edRemotePort.setEnabled(false); } else { tcpClient.closeClient(); edRemoteIp.setEnabled(true); edRemotePort.setEnabled(true); } }); } /**設置發送資料功能(含伺服器/客戶端)*/ private void setSendFunction() { Button btSend = findViewById(R.id.button_Send); btSend.setOnClickListener(v -> { String text = edInputBox.getText().toString(); if (swFunction.isChecked()) { //切換開關在Client模式時 if (tcpClient == null)return; if (text.length() == 0 || !tcpClient.getStatus()) return; exec.execute(() -> tcpClient.send(text)); } else { //切換開關在Server模式時 if (tcpServer == null)return; if (text.length() == 0 || !tcpServer.getStatus()) return; //此處Lambda表達式相等於下方註解部分 if (tcpServer.SST.size() == 0) return; exec.execute(() -> tcpServer.SST.get(0).sendData(text)); // exec.execute(new Runnable() { // @Override // public void run() { // tcpServer.SST.get(0).sendData(text); // } // }); } }); } private class MyBroadcast extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String mAction = intent.getAction(); assert mAction != null; /**接收來自UDP回傳之訊息*/ switch (mAction) { case TCPServer.RECEIVE_ACTION: String msg = intent.getStringExtra(TCPServer.RECEIVE_STRING); byte[] bytes = intent.getByteArrayExtra(TCPServer.RECEIVE_BYTES); stringBuffer.append("收到: ").append(msg).append("\n"); edReceiveMessage.setText(stringBuffer); break; } } } @Override protected void onDestroy() { super.onDestroy(); //取消監聽廣播 unregisterReceiver(myBroadcast); } }
總算是把這個系列給寫完了( ̄ー ̄;
這個系列UDP/TCP都是在我工作中用到的東西
不過我常常覺得如果不是跟遊戲開發商有關的公司的話,可能不一定會用到這個技術吧(應該...
而我們公司因為要發展物聯網技術,因此今天講的這項技術我們研發團隊就把它套用在項目之中了
Okay, 這系列的文章就停在這裡
希望這些文章對各位有幫助!(・ωー)~☆
留言列表