Android/安卓开发之WIFI通讯(下)--与搜索到的设备进行通讯

上一篇文章是已经完成了搜索区域网内的所有设备,那么搜索出来后就是进行通讯了。

其实,这几篇文章说是wifi的应用也不准确,准确的说都是socket的应用。只要基础应用那篇是涉及wifi的。

 

之前说了,在发送UDP广播时,我们为了大家都能相互搜索,所以大家都有一个客户端和服务端,但是到了TCP这么做不太好,平时我们玩游戏不就是房主创建房间,其他人加入么?难道每个人都创建自己的房间,然后又可以加入别人的房间?这么做是可以,但是感觉没这个必要,所以就涉及到了上一篇文章遗留的问题:

问题:到底是由谁来建立服务端?

这个问题我是这么解决的:

我们扫描出区域网内的设备时:

1.如果设备已经创立了房间,那么收到搜索广播时,把自己已经建立服务器的信息和服务器的端口号回应过去

2.搜索端收到回应,然后记录收到的设备详细信息

3.搜索方选择需要进行通讯的设备发起建立TCP连接请求(此时应关闭搜索线程),连接请求使用一个连接线程以udp的形式发送

3.1 如果对方还没建立房间,则自己建立一个房间后,将约定的端口号发送给目标设备。目标设备受到请求之后,若同意连接,则回应一个消息同时建立TCP客户端连接到房间

3.2如果对方已经建立房间,在提示对方已经建立房间,是否请求加入。如果是,则建立TCP客户端连接到房间

4.如果自己已经建立自己的房间,但是想加入对方的房间,需要先关闭自己的服务端,然后新建客户端连接到房间

5.成功建立TCP之后,接下来就可以进行聊天和文件传输等了,具体见:Socket实现多人聊天以及文件传输

这只是做一个基本通讯DEMO还有很多逻辑未处理,大家作为参考就行了。作为小白,错误是家常便饭。希望大家指出我的错误和可以优化之处。

 

下面直接贴代码:

首先,点击该设备时,需要手动关闭搜索线程,建立发起连接线程。发起建立连接线程是这样子的:

 

 
public class ConnectThread extends Thread { private JSONObject mJson; private byte[] recvDate = null; private byte[] sendDate = null; private DatagramPacket recvDP; private DatagramSocket recvDS = null; private DatagramSocket sendDS = null; private String name; private String port;//假如创建房间,则作为房间服务端口 private Handler mHandler; public ConnectThread(JSONObject json,String name,String port,Handler handler) { recvDate = new byte[256]; recvDP = new DatagramPacket(recvDate, 0, recvDate.length); mHandler = handler; this.name=name; this.port =port; mJson = json; } @Override public void run() { try { if (mJson.getBoolean(JsonUtil.DATA_SERVER)) { Message message =Message.obtain(); message.what =1003; message.obj = mJson; mHandler.sendMessage(message); } else { mHandler.sendEmptyMessage(1006); recvDS = new DatagramSocket(54000); sendDS = new DatagramSocket(); recvDS.setSoTimeout(5000);//超时5秒 sendDate = JsonUtil.generateData(name, "connect", port, true); DatagramPacket sendDP = new DatagramPacket(sendDate, sendDate.length, (InetAddress) mJson.get(JsonUtil.DATA_ADDRESS), 53000); sendDS.send(sendDP); //等待回应 recvDS.receive(recvDP); //收到回应 mHandler.sendEmptyMessage(1004); } } catch (IOException e) { e.printStackTrace(); } catch (JSONException e) { e.printStackTrace(); } finally { if (recvDS != null) recvDS.close(); if (sendDS != null) sendDS.close(); } } }

 

 

 

 

 

 

 

大概逻辑是:判断对方是否已经建立房间,如果已经建立,则通知UI,询问用户是否加入对方房间;如果对方没建立,则自己建立一个房间,并且发送一个邀请连接请求给对方;最后等待回应

 

然后是TCP客户端的代码:

 

public class TCPClientThread extends Thread {
    private String mAddr;
    private int mPort;
    private PrintWriter writer;
    private Handler mHandler;
    private boolean isRun;
    public TCPClientThread(String address ,String port,Handler handler){
        mAddr =address;
        mPort = Integer.valueOf(port);
        mHandler = handler;
    }

    @Override
    public void run() {
        isRun = true;
        try {
            boolean flag = true;
            Socket socket = new Socket(mAddr, mPort);
            InputStream is = socket.getInputStream();
            OutputStream os = socket.getOutputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
            writer = new PrintWriter(new OutputStreamWriter(os,"UTF-8"), true);
            while (flag) {
               String  content = reader.readLine();//阻塞接收消息
                if (content==null){
                    //已经断开链接 应通知UI
                    break;
                }
                //将消息通知UI
                Message msg = Message.obtain();
                msg.obj =new String[]{content,"/"+mAddr};
                msg.what=10010;
                mHandler.sendMessage(msg);
            }
            reader.close();
            writer.close();
            socket.close();

        } catch (UnknownHostException e) {
            isRun=false;
            e.printStackTrace();
            Message message =Message.obtain();
            message.what=1009;
            message.obj = "客户端异常:"+e.getMessage();
            mHandler.sendMessage(message);
        } catch (IOException e) {
            isRun=false;
            e.printStackTrace();
            Message message =Message.obtain();
            message.what=1009;
            message.obj = "客户端异常:"+e.getMessage();
        }
    }

    @Override
    public synchronized void start() {
        if (!isRun) {
            super.start();
        }
    }

    //发送消息
    public void sendMessage(final String msg){
        new Thread(){
            @Override
            public void run() {
                if (writer!=null){
                    writer.println(msg);
                    writer.flush();
                }
            }
        }.start();
    }
}

 

 

 

 

 

大概逻辑是,收到连接请求之后,开始开启这个线程,建立和对方的TCP连接接下来就可以通讯了

 

最后是TCP服务端的代码:

 

 
public class TCPServerThread extends Thread { private ServerSocket ss; private int port;//约定的端口 private Map<String,SocketThread> clients;//保存加入房间的客户端 private Handler mHandler;//用于通知UI更新 private boolean isRun;//标记 线程是否已经运行,避免重复启动 public TCPServerThread(String port,Handler handler) { this.port = Integer.valueOf(port); clients = new HashMap<>(); mHandler = handler; } @Override public void run() { isRun=true; try { ss = new ServerSocket(Integer.valueOf(port)); ss.setReuseAddress(true);//设置端口重用,避免TIME_WAIT引起Address already in use异常 mHandler.sendEmptyMessage(1007);//通知服务已经创建成功 for(;;) { Sock
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值