Android基于WebSocket实现局域网互联

记录一下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>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
实现局域网音视频通话可以用Spring Boot作为后端框架,Netty作为网络通信框架,WebSocket作为实现双向通信的协议。以下是一个简单的实现过程: 1. 首先需要搭建一个Spring Boot项目,可以使用Spring Initializr来快速生成项目。在pom.xml中添加Netty和WebSocket的依赖,例如: ```xml <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.25.Final</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> ``` 2. 创建一个WebSocket处理器类,用来处理WebSocket的连接、关闭和消息收发等逻辑。例如: ```java @Component @ServerEndpoint("/video-chat") public class VideoChatHandler { private static final Logger LOGGER = LoggerFactory.getLogger(VideoChatHandler.class); @OnOpen public void onOpen(Session session) { LOGGER.info("WebSocket opened: {}", session.getId()); } @OnMessage public void onMessage(String message, Session session) { LOGGER.info("Received message: {}", message); // TODO: 处理收到的消息 } @OnClose public void onClose(Session session) { LOGGER.info("WebSocket closed: {}", session.getId()); } @OnError public void onError(Throwable error) { LOGGER.error("WebSocket error", error); } } ``` 3. 在Spring Boot的配置类中添加WebSocket的配置,例如: ```java @Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { @Autowired private VideoChatHandler videoChatHandler; @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(videoChatHandler, "/video-chat").setAllowedOrigins("*"); } } ``` 4. 使用Netty来实现音视频的传输。可以使用Netty提供的UDP协议来实现多人音视频通话,也可以使用TCP协议来实现点对点的音视频通话。需要根据实际情况选择相应的协议,这里以TCP协议为例: ```java @Component public class VideoChatServer { private static final Logger LOGGER = LoggerFactory.getLogger(VideoChatServer.class); @Value("${server.video-chat.port}") private int port; @PostConstruct public void start() { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); // TODO: 添加音视频相关的编解码器和处理器 } }) .option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true); ChannelFuture future = bootstrap.bind(port).sync(); LOGGER.info("Video chat server started on port {}", port); future.channel().closeFuture().sync(); } catch (InterruptedException e) { LOGGER.error("Video chat server interrupted", e); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } } ``` 5. 在WebSocket处理器中实现音视频数据的收发逻辑。当收到音视频数据时,可以将数据转发给所有连接的WebSocket客户端。例如: ```java @Component @ServerEndpoint("/video-chat") public class VideoChatHandler { private static final Logger LOGGER = LoggerFactory.getLogger(VideoChatHandler.class); private List<Session> sessions = new CopyOnWriteArrayList<>(); @OnOpen public void onOpen(Session session) { LOGGER.info("WebSocket opened: {}", session.getId()); sessions.add(session); } @OnMessage public void onMessage(ByteBuffer buffer, Session session) throws IOException { LOGGER.info("Received video data from {}", session.getId()); byte[] data = new byte[buffer.remaining()]; buffer.get(data); for (Session s : sessions) { if (s.isOpen() && !s.getId().equals(session.getId())) { s.getBasicRemote().sendBinary(ByteBuffer.wrap(data)); } } } @OnClose public void onClose(Session session) { LOGGER.info("WebSocket closed: {}", session.getId()); sessions.remove(session); } @OnError public void onError(Throwable error) { LOGGER.error("WebSocket error", error); } } ``` 6. 在前端页面中使用WebSocket实现音视频通话。可以使用WebRTC等技术来实现音视频采集、编解码、传输等功能。这里不再赘述。 以上就是一个简单的局域网音视频通话的实现过程。需要注意的是,音视频通话涉及到的技术较多,需要根据实际情况进行选择和配置。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值