【專案原始碼】- 【區域網聊天】android實現區域網聊天 - UDP實現
總結下自己前階段學習的區域網聊天,鞏固下知識。這個乃是作者的開山之作,大家隨便看看就好。
補上效果圖:
其中主要採用的UDP協議,其中涉及的知識點主要有,資料庫的操作:SQLite,SharedPreference ,Udp協議,字串資料流的寫入讀取,廣播等
不過這個實現的功能比較少,只能文字聊天,由於區域網聊天的侷限性,所以作者就沒有打算繼續深入的研究,大概瞭解下實現的原理。
知道UPD協議的,就不難理解其中的知識。
過程是這樣的:
在開啟程式的時候就先弄一個接收的服務,在整個程式的執行當中,這個服務就一直開著,這樣就可以一直接收訊息。由於只實現的是文字的傳送接受,所以我們只需要解析成字串就可以達成目的。
但聊天得有聊天聯絡人的列表,那怎樣才能實現聊天聯絡人列表呢,這裡主要靠192.168.1.255這個ip地址來實現,因為這個地址是群發的地址,在路由器上的所有主機都能接受所以我們只要往這個地址上發訊息,那麼接受到訊息的人自然就知道這個發訊息的人是線上的。
知道這個原理,那麼我們就想到了弄一個執行緒,隔斷的時間就群發訊息,用來判別是否線上。
但作者在聊天介面上有一個群聊的功能卻會與這個產生衝突,那怎麼解決這個衝突呢,很簡單,在判斷線上的執行緒裡傳送的訊息用一些不常用的隨便字串就能輕鬆解決問題,但接收訊息的時候判別下接收的字串,如果是的話自然就不用載入到聊天內容當中,自然就解決了。
另外,如果要實現聲音 和 圖片的傳輸,由於作者的能力有限,暫時想到的辦法是在開另外的埠來實現,這樣就不會與接受文字的埠產生衝突。
接受服務部分的程式碼:(可能程式碼比較亂,由於作者旨在學習知識點所以,花在註釋上的時間就少了點)
package com.example.administrator.canchatdemo.util;
import android.content.Context;
import android.content.Intent;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import com.example.administrator.canchatdemo.R;
import com.example.administrator.canchatdemo.activity.MainActivity;
import java.io.*;
import java.net.*;
import java.sql.Connection;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by Administrator on 2016/4/12.
* 接受服務
*/
public class CanChatUdpReceiver extends Thread {
//儲存聊天記錄
public static List<MessageInfo> messageInfos = new ArrayList<MessageInfo>();
public static List<ListContactInfo> listContactInfos = new ArrayList<ListContactInfo>();
//儲存聊天資料庫
private MsgSQLiteOpenHelper helper;
//資料庫表message操作例項化
private MessageDao messageDao;
private int port;
//停止標誌
private boolean flag = true;
private DatagramSocket da = null;
private Context context;
public CanChatUdpReceiver(Context context,int port){
this.context = context;
this.port = port;
//context.deleteDatabase("message.db");//刪除資料庫初始化
//建立資料庫
helper = new MsgSQLiteOpenHelper(context);
//資料庫表message操作例項化
messageDao =new MessageDao(helper);
List<MessageInfo> msgInfos = messageDao.findAll();
if(msgInfos.size() > 50) {//提取一部分資料庫內容
for (int i = msgInfos.size()-40; i < msgInfos.size(); i++) {
messageInfos.add(msgInfos.get(i));
}
}else{
for (int i = 0; i < msgInfos.size(); i++) {
messageInfos.add(msgInfos.get(i));
}
}
//初始化列表中的群聊資料
ListContactInfo listContactInfo = new ListContactInfo();
Calendar calendar = Calendar.getInstance();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm");
String time =simpleDateFormat.format(calendar.getTime());
listContactInfo.setListName("區域網群聊");
listContactInfo.setListImage(R.drawable.dml);
listContactInfo.setListIp(MainActivity.ipToAll);
listContactInfo.setListTime(time);
listContactInfo.setListUnRead("1");
if(listContactInfos.size()< 1)
listContactInfos.add(listContactInfo);
}
public void run(){
try{
if(da == null)
da = new DatagramSocket(port);
while (flag){
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
da.receive(dp);
String ip = dp.getAddress().getHostAddress();
String data = new String(dp.getData(),0,dp.getLength());
//資料分析開始 判斷資料型別
if(data.contains(Udp.CHECKED_CODE)){
//判斷線上人數部分//判斷線上人數部分
//取出 剔除判斷碼部分 取出列表資訊
String listInfoData = data.substring(Udp.CHECKED_CODE.length(),data.length());
//資料解析提取
boolean isAdd = true;
ListContactInfo newListContactInfo = getListContactInfo(listInfoData);
for (int i =0;i<listContactInfos.size();i++){
ListContactInfo listContactInfo = listContactInfos.get(i);
if(listContactInfo.getListIp().equals(ip)){
listContactInfo.setListName(newListContactInfo.getListName());
listContactInfo.setListName(newListContactInfo.getListName());
listContactInfo.setListImage(newListContactInfo.getListImage());
isAdd =false;
break;
}
}
//聯絡人列表資料加入
if(isAdd) {
newListContactInfo.setListIp(ip);
listContactInfos.add(newListContactInfo);
Log.e("列印提示資料:", "列表統計數量:" + listContactInfos.size()+" ip:" + ip);
}
}else{
//訊息資料解析部分
MessageInfo messageInfo =getMessageInfo(data);
messageInfo.setUserIp(ip);
messageInfos.add(messageInfo);
//傳送新訊息廣播
Intent intent = new Intent();
intent.putExtra("listName",messageInfo.getListName());
intent.putExtra("userName",messageInfo.getUserName());
intent.putExtra("userIp",messageInfo.getUserIp());
intent.putExtra("imageId",messageInfo.getImageId());
intent.putExtra("msgBody",messageInfo.getMsgBody());
intent.putExtra("receTime",messageInfo.getReceTime());
intent.setAction("com.ADD_VIEW");
context.sendBroadcast(intent);
//儲存資料到資料庫
saveMessageToSQL(messageInfo);
}
}
}catch(Exception e){
Log.i(e.getMessage(),"伺服器掛了");
}finally {
try{
if(da !=null)
da.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
//訊息資料處理
private MessageInfo getMessageInfo(String data){
String[] datas = data.split("##");
MessageInfo messageInfo = new MessageInfo();
messageInfo.setListName(datas[0]);
messageInfo.setUserName(datas[1]);
messageInfo.setImageId(Integer.parseInt(datas[2]));
messageInfo.setMsgBody(datas[3]);
messageInfo.setReceTime(datas[4]);
return messageInfo;
}
//聯絡人列表資料處理
private ListContactInfo getListContactInfo(String data){
//解析資料data
String[] datas = data.split("##");
//
ListContactInfo listContactInfo = new ListContactInfo();
Calendar calendar = Calendar.getInstance();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm");
String time =simpleDateFormat.format(calendar.getTime());
listContactInfo.setListTime(time);
listContactInfo.setListUnRead("1");
listContactInfo.setListName(datas[0]);
listContactInfo.setListImage(Integer.parseInt(datas[1]));
return listContactInfo;
}
//儲存訊息資料到資料庫
private void saveMessageToSQL(MessageInfo messageInfo){
try {
String userName = messageInfo.getUserName();
String listName = messageInfo.getListName();
String userIp = messageInfo.getUserIp();
int imageId = messageInfo.getImageId();
String msgBody = messageInfo.getMsgBody();
String receTime = messageInfo.getReceTime();
messageDao.add(listName,userName,userIp,imageId,msgBody,receTime);
Log.e("資料庫操作提示:", "儲存成功");
}catch (Exception e){
Log.d(e.getMessage(),"儲存失敗");
}
}
}
以上程式碼中有很多問題就是,大家瞭解下實現的方法就好,由於傳送的內容中包含文字資訊比較多,所以作者只用##來分割,所以當傳送訊息時含有##時就會傳送出錯。傳送的訊息內容主要包括使用者名稱,聊天列表名,使用者ip,頭像的地址,訊息的內容,和接受的時間。
這裡有個列表名和使用者名稱是不一樣的概念,由於作者的資料庫只有一個,所有的聊天資訊都在一個集合當中,這樣在提取資料的時候,由於聊天列表裡有個群聊,在區分分組時採用使用者名稱就會衝突,所以匯入資料時,按的是列表名來匯入,這樣就可以區分資訊。
以上程式碼中還用到了廣播,廣播的用途旨在提示新訊息,這樣可以通知主執行緒資料變化,更新檢視。
傳送訊息的程式碼如下:
package com.example.administrator.canchatdemo.util;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
* Created by Administrator on 2016/4/13.
* * Upd傳送資料
*/
public class CanChatUdpSend implements Runnable {
//傳送的資料文字
private String data;
private int port;
private String ip;
public CanChatUdpSend(String data,String ip,int port){
this.data = data;
this.port = port;
this.ip = ip;
}
public void run() {
DatagramSocket ds = null;
try{
ds = new DatagramSocket();
byte[] buf = data.getBytes();
DatagramPacket dp = new DatagramPacket(buf,buf.length, InetAddress.getByName(ip),port);
ds.send(dp);
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(ds != null)
ds.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
傳送訊息的程式碼就簡單了,只要有ip地址,埠,和內容就好,只管傳送,不用對接受的內容進行處理。
在ip地址中有個問題就是在進入程式中時要判斷自身的ip地址,由於ip地址有可能是192.168.1.1也有可能是192.168.0.1,所以只有知道了自己的ip地址才能得到正確的ip。不過這裡有個小問題,在電腦上JAVA獲取ip地址的方法和手機上的獲取方法有點不同,用電腦上的獲取方法得到的ip地址為127.0.0.1,所以採用瞭如下的程式碼來獲取。
package com.example.administrator.canchatdemo.util;
import android.util.Log;
import android.widget.Toast;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;
/**
* Created by Administrator on 2016/4/14.
* 定義常量
*/
public class Udp {
//定義單獨埠
public static final int PORT_OWN = 52000;
//定義群聊埠
public static final int PORT_ALL = 51000;
public static final String CHECKED_CODE = "check_code_123456789";
//獲取255ip
public static String getIpToAll(){
try {
String ip = getIp();
if(ip == null)
return null;
return getIp().substring(0, 10) + "255";
}catch (Exception e){
e.printStackTrace();
}
return null;
}
//獲取本地ip
public static String getIp(){
try{
for(Enumeration<NetworkInterface> en= NetworkInterface.getNetworkInterfaces();en.hasMoreElements();){
NetworkInterface intf = en.nextElement();
for(Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses();enumIpAddr.hasMoreElements();){
InetAddress inetAddress = enumIpAddr.nextElement();
if(!inetAddress.isLoopbackAddress()&&inetAddress instanceof Inet4Address){
return inetAddress.getHostAddress().toString();
}
}
}
}catch (Exception e){
e.printStackTrace();
}
return null;
}
}
剩下的就是一些佈局的操作之類的東西了吧。
在此貼上自己的原始碼,寫的不好勿噴,謝謝。
http://download.csdn.net/detail/wduj123/9508473
相關文章
- Java實現多執行緒區域網聊天室Java執行緒
- 企業網盤實現區域網共享
- Java用UDP實現簡單聊天JavaUDP
- Flutter 區域性路由實現Flutter路由
- 基於Service Worker實現WebRTC區域網大檔案傳輸能力Web
- 用VC在區域網實現IP多播通訊
- Kali 實現區域網 ARP 欺騙和 ARP 攻擊
- 區域網與廣域網
- Linux下如何實現區域網內網路裝置相互通訊Linux內網
- 如何用Python實現多工版的udp聊天器PythonUDP
- Android:藍芽實現一對一聊天Android藍芽
- 批次網站DNS區域傳送漏洞檢測——bash shell實現網站DNS
- 40.qt quick- 高仿微信實現區域網聊天V4版本(支援gif動圖表情包、訊息聊天、拖動縮放視窗)QTUI
- Padavan安裝使用ZeroTier實現組建虛擬區域網的方法
- 使用Qt5+CMake實現圖片的區域選擇(附原始碼)QT原始碼
- 基於Socket.IO實現Android聊天功能Android
- 區域網訪問共享檔案需要密碼怎麼辦?取消區域網共享檔案訪問密碼的方法密碼
- 區域網的管理
- js程式碼實現多人聊天室JS
- socket實現聊天功能(二)
- python opencv如何實現目標區域裁剪功能PythonOpenCV
- 利用 clip-path 實現動態區域裁剪
- App 多區域皮膚(主題)的實現APP
- 要在區域網中配置檔案伺服器,確保檔案只能在區域網內傳播,並且無法複製到區域網外伺服器
- JAVASE網路程式設計之TCP實現聊天通訊Java程式設計TCP
- 使用輪詢&長輪詢實現網頁聊天室網頁
- win10區域網怎麼快速傳檔案_win10區域網傳檔案的方法Win10
- 區域網共享資料夾設定怎麼弄 區域網檔案共享的辦法
- JS邊角料: NodeJS+AutoJS+WebSocket+TamperMonkey實現區域網多端文字互傳NodeJSWeb
- 區域網硬碟掛載硬碟
- 01、區域網基礎
- 元件無線區域網元件
- 計算機區域網計算機
- Springboot+Vue實現線上聊天室專案-登入、註冊介面的實現Spring BootVue
- C# 實現語音聊天C#
- 原生Node 實現聊天室
- 一對一聊天ajax實現
- uniapp專案實踐總結(十五)使用websocket實現簡易聊天室APPWeb
- Android端實現多人音視訊聊天應用(一)Android