记录一下Android 基于WebSoket局域网互联技术,大家互相交流
准备工作
1、导入依赖
implementation "org.java-websocket:Java-WebSocket:1.5.1"
2,配置权限
申请网络权限(必须)
<uses-permission android:name="android.permission.INTERNET" /> 申请wifi相关权限(必须) <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
工具类:IPToolsUtils 用于查询IP
import com.tencent.mmkv.MMKV;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.Socket;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class IPToolsUtils {
//匹配C类地址的IP
public static final String regexCIp = "^192\\.168\\.(\\d{1}|[1-9]\\d|1\\d{2}|2[0-4]\\d|25\\d)\\.(\\d{1}|[1-9]\\d|1\\d{2}|2[0-4]\\d|25\\d)$";
//匹配A类地址
public static final String regexAIp = "^10\\.(\\d{1}|[1-9]\\d|1\\d{2}|2[0-4]\\d|25\\d)\\.(\\d{1}|[1-9]\\d|1\\d{2}|2[0-4]\\d|25\\d)\\.(\\d{1}|[1-9]\\d|1\\d{2}|2[0-4]\\d|25\\d)$";
//匹配B类地址
public static final String regexBIp = "^172\\.(1[6-9]|2\\d|3[0-1])\\.(\\d{1}|[1-9]\\d|1\\d{2}|2[0-4]\\d|25\\d)\\.(\\d{1}|[1-9]\\d|1\\d{2}|2[0-4]\\d|25\\d)$";
public static String getHostIp() {
String hostIp;
Pattern ip = Pattern.compile("(" + regexAIp + ")|" + "(" + regexBIp + ")|" + "(" + regexCIp + ")");
Enumeration<NetworkInterface> networkInterfaces = null;
try {
networkInterfaces = NetworkInterface.getNetworkInterfaces();
} catch (SocketException e) {
e.printStackTrace();
}
InetAddress address;
while (networkInterfaces.hasMoreElements()) {
NetworkInterface networkInterface = networkInterfaces.nextElement();
Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
while (inetAddresses.hasMoreElements()) {
address = inetAddresses.nextElement();
String hostAddress = address.getHostAddress();
Matcher matcher = ip.matcher(hostAddress);
if (matcher.matches()) {
hostIp = hostAddress;
return hostIp;
}
}
}
return null;
}
private static void bindPort(String host, int port) throws Exception{
Socket s = new Socket();
s.bind(new InetSocketAddress(host, port));
s.close();
}
public static int getFreePort(){//判断端口是否可用
int port=MMKV.defaultMMKV().decodeInt("port",8888);
try{
bindPort("0.0.0.0", port);
bindPort(InetAddress.getLocalHost().getHostAddress(),port);
}
catch (Exception e)
{
port=new Random().nextInt(65535);
MMKV.defaultMMKV().encode("port",port);
getFreePort();
}
return port;
}
public static boolean isIssued(int port){//判断端口是否可用
try{
bindPort("0.0.0.0", port);
bindPort(InetAddress.getLocalHost().getHostAddress(),port);
return true;
}
catch (Exception e)
{
return false;
}
}
}
服务端WEbSoketClient代码实现
import android.util.Log;
import org.greenrobot.eventbus.EventBus;
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import java.net.InetSocketAddress;
import static com.tuosi.websocketchartdemo.MainActivity.isServer;
/**
* guguangxian
*/
public class WebSocketServer extends org.java_websocket.server.WebSocketServer{
private static WebSocketServer websocketServer;
WebSocketServer(InetSocketAddress host){
super(host);
}
@Override
public void onOpen(WebSocket conn, ClientHandshake handshake) {
Log.d("WebSocketServer","onOpen():连接到: "+getRemoteSocketAddress(conn));
EventBus.getDefault().post(new MessageEvent(1,"onOpen:"+getRemoteSocketAddress(conn)));
isServer=true;
}
@Override
public void onClose(WebSocket conn, int code, String reason, boolean remote) {
Log.d("WebSocketServer","onClose");
EventBus.getDefault().post(new MessageEvent(1,"onClose:"+reason));
}
@Override
public void onMessage(WebSocket conn, String message) {
Log.d("WebSocketServer","onMessage"+message);
EventBus.getDefault().post(new MessageEvent(2,getRemoteSocketAddress(conn)+message));
}
@Override
public void onError(WebSocket conn, Exception ex) {
Log.d("WebSocketServer","onError"+ex.toString());
EventBus.getDefault().post(new MessageEvent(1,"onError:"+ex.toString()));
}
@Override
public void onStart() {
Log.d("WebSocketServer","onStart:"+websocketServer.getAddress());
EventBus.getDefault().post(new MessageEvent(1,"onStart:服务器已就绪"+websocketServer.getAddress()));
}
public static void ready(){
String ip = IPToolsUtils.getHostIp();
InetSocketAddress myHost = new InetSocketAddress(ip, 8080);
WebSocketServer websocketServer = new WebSocketServer(myHost);
try {
websocketServer.start();
} catch (Exception e) {
e.printStackTrace();
}
WebSocketServer.websocketServer = websocketServer;
}
public static void Stop() {
try {
websocketServer.stop();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void Send(String string) {
try {
websocketServer.broadcast(string);
//websocketServer.broadcast(string,clients);//Collection<WebSocket> clients,指定发送到哪个客户端
} catch (Exception e) {
e.printStackTrace();
}
}
}
客户端代码实现
import android.os.Looper;
import android.util.Log;
import org.greenrobot.eventbus.EventBus;
import org.java_websocket.exceptions.WebsocketNotConnectedException;
import org.java_websocket.handshake.ServerHandshake;
import java.net.URI;
import static com.tuosi.websocketchartdemo.MainActivity.isClient;
/**
* guguangxian
*/
public class WebSocketClient extends org.java_websocket.client.WebSocketClient {
public WebSocketClient(URI serverUri) {
super(serverUri);
}
@Override
public void onOpen(ServerHandshake handshakedata) {
Log.d("WebSocketClient","onOpen"+"成功连接到:"+getRemoteSocketAddress());
EventBus.getDefault().post(new MessageEvent(1,"onOpen:"+getRemoteSocketAddress()));
isClient=true;
}
@Override
public void onMessage(String message) {
Log.d("WebSocketClient","onMessage"+message);
EventBus.getDefault().post(new MessageEvent(2,getRemoteSocketAddress()+":"+message));
}
@Override
public void onClose(int code, String reason, boolean remote) {
Log.d("WebSocketClient","onClose");
EventBus.getDefault().post(new MessageEvent(1,"onClose:"+reason));
}
@Override
public void onError(Exception ex) {
Log.d("WebSocketClient","onError");
EventBus.getDefault().post(new MessageEvent(505,"onError:"+ex.toString()));
}
private static WebSocketClient webSocketClient;
public static boolean connect(String ip) {
if (webSocketClient != null) {
Release();
}
if (webSocketClient == null ) {
URI uri = URI.create("ws://"+ip+":8080/");
webSocketClient = new WebSocketClient(uri);
}
try {
webSocketClient.connect();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public static void Release() {
Close();
webSocketClient = null;
}
public static void Close() {
if (webSocketClient == null) return;
if (!webSocketClient.isOpen()) return;
try {
webSocketClient.connect();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void Send(String string) {
if (webSocketClient == null) return;
if (!webSocketClient.isOpen())
Reconnect();
try {
webSocketClient.send(string);
} catch (WebsocketNotConnectedException e) {
e.printStackTrace();
}
}
public static boolean Reconnect() {
if (webSocketClient == null) return false;
if (webSocketClient.isOpen()) return true;
try {
webSocketClient.connect();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
使用案例
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.tencent.mmkv.MMKV;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.net.URI;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MainActivity extends AppCompatActivity {
Button ready;
Button connect;
Button send;
LinearLayout linearLayout;
TextView textView;
EditText editText;
public static boolean isServer = false;
public static boolean isClient = false;
public static int index = 191;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
linearLayout = findViewById(R.id.linearLayout);
textView = findViewById(R.id.TextView2);
ready = findViewById(R.id.ready);
connect = findViewById(R.id.connect);
editText = findViewById(R.id.editText);
ready.setOnClickListener(v -> WebSocketServer.ready());
connect.setOnClickListener(v -> {
// String ip = NetWorkUtil.getHostIp();
// WebSocketClient.connect("192.168.1.193");
// executorService.execute(thread);
thread=new SessionThread();
thread.start();
});
send = findViewById(R.id.send);
send.setOnClickListener(v -> {
String message = editText.getText().toString();
if (message.equals("")) {
Toast.makeText(MainActivity.this, "禁止发送空消息", Toast.LENGTH_SHORT).show();
return;
}
if (isServer) {
WebSocketServer.Send(message);
addText("我:" + message);
} else if (isClient) {
WebSocketClient.Send(message);
addText("我:" + message);
} else {
Toast.makeText(MainActivity.this, "未连接", Toast.LENGTH_SHORT).show();
}
});
MMKV.initialize(this);
EventBus.getDefault().register(this);
}
SessionThread thread;
@Subscribe(threadMode = ThreadMode.MAIN)
public synchronized void MessageEventBusa(MessageEvent messageEvent) {
String string = messageEvent.getString();
switch (messageEvent.getCode()) {
case 1://
textView.setText(string);
break;
case 2:
addText(string);
case 505:
if (isClient) {
return;
}
textView.setText(string);
++index;
thread=null;
thread = new SessionThread();
thread.start();
// executorService.execute(thread);
break;
}
}
private void addText(String string) {
TextView textView = new TextView(this);
LinearLayout.LayoutParams lllp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
textView.setText(string);
linearLayout.addView(textView, lllp);
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
/* 发送进程 */
private class SessionThread extends Thread {
@Override
public void run() {
synchronized (this) {
Log.e("wifiInfo", "index="+index);
if (index > 255) {
return;
}
try {
String ipStart = "", ipEnd = "";
//获取wifi服务
WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
if (wifiManager != null) {
if (!wifiManager.isWifiEnabled())
wifiManager.setWifiEnabled(true);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
int ipAddress = wifiInfo.getIpAddress();
String str = intToIp(ipAddress);
String[] ip = str.split("\\.");
if (ip.length == 4) {
ipStart = (ip[0] + "." + ip[1] + "." + ip[2] + ".2");
ipEnd = (ip[0] + "." + ip[1] + "." + ip[2] + ".255");
}
}
Log.e("wifiInfo", "startIP=" + ipStart);
String[] startStr = ipStart.split("\\.");
String[] endStr = ipEnd.split("\\.");
// 扫描设备
int startInt = Integer.parseInt(startStr[3]);
int endInt = Integer.parseInt(endStr[3]);
if (startStr.length == endStr.length && startStr[0].equals(endStr[0]) && startStr[1].equals(endStr[1]) && startStr[2].equals(endStr[2])) {
int num = endInt - startInt;
if (num > -1) {
WebSocketClient[] websocket = new WebSocketClient[endInt - startInt + 1];
String ipAddress = startStr[0] + "." + startStr[1] + "." + startStr[2] + ".";
Log.e("wifiInfo", "ipAddress=" + ipAddress);
String ipServer = ipAddress + index;
WebSocketClient.connect(ipServer);
Log.e("wifiInfo", "ipServer=" + ipServer);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
private String intToIp(int i) {
return (i & 0xFF) + "." +
((i >> 8) & 0xFF) + "." +
((i >> 16) & 0xFF) + "." +
(i >> 24 & 0xFF);
}
}
xml
<?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=".MainActivity">
<Button
android:id="@+id/ready"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="等待连接"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.359"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.011" />
<Button
android:id="@+id/connect"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发起连接"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.049"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.023" />
<TextView
android:id="@+id/TextView2"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="8dp"
android:text="连接到xxx"
app:layout_constraintTop_toBottomOf="@+id/ready">
</TextView>
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/TextView2"
app:layout_constraintVertical_bias="0.0"
tools:layout_editor_absoluteX="0dp">
</LinearLayout>
<EditText
android:singleLine="true"
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="8dp"
app:layout_constraintTop_toBottomOf="@+id/linearLayout"
tools:layout_editor_absoluteX="16dp" />
<Button
android:id="@+id/send"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="8dp"
app:layout_constraintTop_toBottomOf="@+id/editText"
android:text="发送"
tools:layout_editor_absoluteX="0dp" />
</androidx.constraintlayout.widget.ConstraintLayout>