Android中socket通信的簡單實(shí)現(xiàn)
Android中socket通信簡單實(shí)現(xiàn),供大家參考,具體內(nèi)容如下
socket通信需要有一個(gè)服務(wù)器和客戶端,可以把同一個(gè)APP作為服務(wù)器跟客戶端,也可以分開成兩個(gè)APP。
先上個(gè)圖:

這里以一個(gè)APP作為服務(wù)器跟客戶端為示例
1、添加網(wǎng)絡(luò)訪問權(quán)限
<uses-permission android:name="android.permission.INTERNET" />
2、寫服務(wù)器,在APP上啟動(dòng)
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
ServerSocket serverSocket = null;
public final int port = 9998;
private int i = 0;
public Server(){
//輸出服務(wù)器的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...");
//等待連接,每建立一個(gè)連接,就新建一個(gè)線程
while(true){
socket = serverSocket.accept();//等待一個(gè)客戶端的連接,在連接之前,此方法是阻塞的
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();
}
}
//向客戶端發(fā)送信息
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){
i++;
String msgRecv = dis.readUTF();
System.out.println("msg from client:"+msgRecv);
dos.writeUTF(msgRecv + i);
dos.flush();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
需要在線程中調(diào)用,調(diào)用方法:
new Thread(() -> new Server().startService()).start();
3、客戶端代碼
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import androidx.appcompat.app.AppCompatActivity;
/**
* @author fenghaitao
* @time 2020年4月2日14:34:33
* scoket客戶端連接測(cè)試
*/
public class SocketActivity extends AppCompatActivity {
//IP地址和端口號(hào)
public static String IP_ADDRESS = "";
public static int PORT = 9998;
//三個(gè)控件
EditText et_message = null; //需要發(fā)送的內(nèi)容
Button bt_getAdress = null; //獲取本機(jī)IP地址
Button bt_connect = null; //連接并發(fā)送
Button bt_startServer = null; //啟動(dòng)服務(wù)端
TextView tv_adress = null; //ip地址
TextView tv_reply = null; //服務(wù)器回復(fù)的消息
//handler
Handler handler = null;
Socket soc = null;
DataOutputStream dos = null;
DataInputStream dis = null;
String messageRecv = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_socket);
et_message = findViewById(R.id.et_message);
bt_getAdress = findViewById(R.id.bt_getAdress);
bt_connect = findViewById(R.id.bt_connect);
bt_startServer = findViewById(R.id.bt_startServer);
tv_adress = findViewById(R.id.tv_adress);
tv_reply = findViewById(R.id.tv_reply);
bt_getAdress.setOnClickListener(v -> {
new Thread(() -> {
try {
InetAddress addr = InetAddress.getLocalHost();
System.out.println("local host:"+addr);
runOnUiThread(() -> tv_adress.setText(addr.toString().split("/")[1]));
} catch (UnknownHostException e) {
e.printStackTrace();
}
}).start();
});
bt_startServer.setOnClickListener(v -> {
new Thread(() -> new Server().startService()).start();
Toast.makeText(SocketActivity.this,"服務(wù)已啟動(dòng)",Toast.LENGTH_SHORT).show();
});
bt_connect.setOnClickListener(v -> {
IP_ADDRESS = tv_adress.getText().toString();
new ConnectionThread(et_message.getText().toString()).start();
});
handler = new Handler(msg -> {
Bundle b = msg.getData(); //獲取消息中的Bundle對(duì)象
String str = b.getString("data"); //獲取鍵為data的字符串的值
tv_reply.append(str);
return false;
});
}
//新建一個(gè)子線程,實(shí)現(xiàn)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");
if ("".equals(IP_ADDRESS)) {
return;
}
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();//如果沒有收到數(shù)據(jù),會(huì)阻塞
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();
}
}
}
}
下面是xml頁面代碼
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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=".SocketActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp">
<Button
android:id="@+id/bt_getAdress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="獲取IP地址"/>
<TextView
android:id="@+id/tv_adress"
android:layout_width="200dp"
android:layout_height="match_parent"
android:layout_marginLeft="15dp"
android:textSize="20dp"
android:gravity="center"/>
</LinearLayout>
<Button
android:id="@+id/bt_startServer"
android:text="啟動(dòng)服務(wù)"
android:layout_marginTop="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<EditText
android:id="@+id/et_message"
android:layout_marginTop="10dp"
android:hint="請(qǐng)輸入發(fā)送信息"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/bt_connect"
android:text="連接發(fā)送"
android:layout_marginTop="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/tv_reply"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="服務(wù)端返回消息:"
android:textSize="30sp"/>
</LinearLayout>
</LinearLayout>
客戶端跟服務(wù)器進(jìn)行通信之前記得先啟動(dòng)服務(wù)器,如果端口被占用需要換個(gè)端口。
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android使用屬性動(dòng)畫如何自定義倒計(jì)時(shí)控件詳解
自Android 3.0版本開始,系統(tǒng)給我們提供了一種全新的動(dòng)畫模式,屬性動(dòng)畫(property animation),它的功能非常強(qiáng)大,下面這篇文章主要給大家介紹了關(guān)于Android使用屬性動(dòng)畫如何自定義倒計(jì)時(shí)控件的相關(guān)資料,需要的朋友可以參考下2018-05-05
Android模仿Toast實(shí)現(xiàn)提示框效果
這篇文章主要為大家詳細(xì)介紹了Android模仿Toast實(shí)現(xiàn)提示框效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08
Kotlin協(xié)程flowOn與線程切換超詳細(xì)示例介紹
這篇文章主要介紹了Kotlin協(xié)程flowOn與線程切換,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-09-09
Android使用Gridview單行橫向滾動(dòng)顯示
這篇文章主要為大家詳細(xì)介紹了Android使用Gridview單行橫向滾動(dòng)顯示,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07
Android開發(fā)之圓角矩形創(chuàng)建工具RoundRect類定義與用法分析
這篇文章主要介紹了Android開發(fā)之圓角矩形創(chuàng)建工具RoundRect類定義與用法,結(jié)合完整實(shí)例形式分析了Android圓角矩形工具類的定義與簡單使用技巧,需要的朋友可以參考下2018-01-01

