Android p2p局域网聊天软件的实现

最近做了个Android 端的局域网聊天软件。简单说一下思路:

首先由于是局域网的p2p,所以没有后台服务器。但是传文件,发信息用的是tcp,tcp前提是建立连接。我们都知道tcp建立连接时需要双方的ip地址才可以建立连接。

所以刚开始比较比较重要的一步是获取对方主机的ip地址,这里用udp局域网广播实现。

注意,手机应该是要在wifi已连接的状态下。Android 可以用一下方法获取本机的wifi ip地址:

private static String getIp() {
WifiManager wm = (WifiManager) context
.getSystemService(Context.WIFI_SERVICE);
// 检查Wifi状态
if (!wm.isWifiEnabled()) {
Toast.makeText(TinyKingApp.context, "清先打开wifi。", Toast.LENGTH_SHORT)
.show();
System.exit(0);
}
// wm.setWifiEnabled(true);
WifiInfo wi = wm.getConnectionInfo();
// 获取32位整型IP地址
int ipAdd = wi.getIpAddress();
// 把整型地址转换成“*.*.*.*”地址
String ip = intToIp(ipAdd);
return ip;
}

获取到本机的ip地址之后,比如是192.168.23.10,那么用于广播的目的地址就是192.168.23.255。经测试 192.168.23.0(代表一个网段)也是可以进行广播的。

接下来只需要构造udp数据报发送出去即可,核心代码如下:

// 构造数据报包
DatagramPacket packet = new DatagramPacket(MyMsg.getBytes(),
MyMsg.getBytes().length, InetAddress.getByName(TinyKingApp
.getInstance().getSPUtil().getUDPAddress()), 3333);
DatagramSocket socket = new DatagramSocket();
socket.send(packet);
socket.close();

注:MyMsg是一个String类型的变量,及时你要发送给对方的信息,这里不仅仅发送ip,还发送昵称等信息。

udp接收的核心代码如下:

// 构造 DatagramPacket,用来接收长度为 length 的数据包
DatagramPacket packet = new DatagramPacket(inbuf,
inbuf.length);
synchronized (socket) {
try {
// 从此套接字接收数据报包

socket.receive(packet);
} catch (Exception e) {
e.printStackTrace();
break;
}
}
String s = new String(packet.getData(), "UTF-8");

注:inbuf 是一个自定义的缓冲区,这个缓冲区应该要比接受的信息的容量大,我这里用的是100个字节的缓冲区。

        还有要注意的一点,拿到对方ip后,按照常理应该发送自己的ip给对方,这样对方才能更新他的好友列表。所以我们需要判断收到的udp广播是否是自己发的,是否是重复           收到的等因素。若不判断会造成双方一致不停地对发的死循环。

拿到双方的ip之后一切都好办了。对于tcp的连接本省来说,有一个服务端(ServerSocket)跟一个客户端(Socket)。我这里默认当主机要接收信息的时候作为服务端,发送的时候作为客户端。

由上,当我们打开应用的时候,应该开启一个tcp的服务端线程,用于不断接收来自他人的信息(文字,文件。。)

核心代码如下:

            while (StopFalg) {
try {
// 获取客户端连接,并返回一个新的socket对象
Socket socket = serverSocket.accept();
// 创建clientThread并启动
// 启动ClientsThread之后,可以监听改连接对应的客户端是否发送过来信息
// 并获取信息
TCPClientThread tCPClientThread = new TCPClientThread(handler,socket);
tCPClientThread.start();
if (socket != null) {
synchronized (clients) {
// 将客户端连接加入到vector数组中保存
clients.addElement(tCPClientThread);
}
}
} catch (IOException e) {
// TODO: handle exception
continue;
}
}

注:ServerSocket 的 accept方法是一个阻塞方法,就是改方法有一个内循环。如果该方法没有返回一个Socket 的实例,那么语句会一直停在这个方法。

        由于主机可能同时和多个主机进行通信,所以直接在循环中处理即受到的信息不妥当。可以用一个线程维持当前的连接(将实例化好的socket传入即可)。

tcp发送文字信息核心代码如下:

      socket = new Socket(ServerIP, 3333);
out = new DataOutputStream(socket.getOutputStream());


out.writeUTF(TinyKingApp.getInstance().getGson()
.toJson(message, Message.class));


out.close();
socket.close();

其中 ServerIP 是服务端的ip,即接收方的ip。当发送方 执行socket = new Socket(ServerIP, 3333);的同时,服务端ServerSocket 的accept 方法会跳出循环,返回一个Socket实例。

接收方接收文字信息的核心代码如下:

//创建服务器输入/输出流
in = new DataInputStream(clientSocket.getInputStream());

//读入客户端发送过来的信息
String message = in.readUTF();
// synchronized (tCPServerThread.messages) {

if(message != null){
Message msg = new Message();
msg.what = Constants.NEWMSG;
msg.obj = message;
handler.sendMessage(msg);
TCPServerThread.clients.remove(this);

finalize();
break;
}

从ServerSocket返回的Socket实例—clientSocket中取得输入流,监听输入流进行判断即可。

tcp传送文件的方法也跟文字信息大同小异,不再赘述。

贴上源代码:http://pan.baidu.com/s/1c0IeDVi

技术因分享而强大!

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值