最近要做一个手机跟蓝牙模块进行通信的项目,查了一些资料,做出了一个可以实现通信的demo。
这里是把手机作为服务器,开启手机热点。(可以去系统设置里开启热点,也可以代码开启热点)
下面是开启热点的代码(配置文件要加上权限),但是这个方法在Android6.0里面开启不了,我查了一下大家都说加上
WRITE_SETTINGS权限,但是我加上了也不行,只有把
targetSdkVersion 由23改为22了。。。
/**
* 判断WIFI热点是否开启
*/
public boolean isApOn() {
try {
Method method = wifiManager.getClass().getDeclaredMethod("isWifiApEnabled");
method.setAccessible(true);
return (Boolean) method.invoke(wifiManager);
}
catch (Throwable ignored) {}
return false;
}
/**
* 设置热点名称及密码,并创建热点
* @param mSSID
* @param mPasswd
*/
private Boolean stratWifiAp(String mSSID, String mPasswd,Boolean onoff) {
Method method1 = null;
if(onoff){
wifiManager.setWifiEnabled(false);
}
try {
//通过反射机制打开热点
method1 = wifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
WifiConfiguration netConfig = new WifiConfiguration();
netConfig.SSID = mSSID;
netConfig.preSharedKey = mPasswd;
netConfig.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
netConfig.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
netConfig.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
netConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
netConfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
netConfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
netConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
netConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
return (Boolean)method1.invoke(wifiManager, netConfig, onoff);
} catch (Exception e) {
return false;
}
}
public void startServer(){
Thread thread = new Thread(){
@Override
public void run() {
super.run();
/*指明服务器端的端口号*/
try {
server = new ServerSocket(9999);
} catch (IOException e) {
e.printStackTrace();
}
while (true){
try {
socket = server.accept();
in = socket.getInputStream();
handler.sendEmptyMessage(2);
} catch (IOException e) {
e.printStackTrace();
}
new ServerThread(socket,in).start();
}
}
};
thread.start();
}
class ServerThread extends Thread{
private Socket socket;
private InputStream inputStream;
public ServerThread(Socket socket,InputStream inputStream){
this.socket = socket;
this.inputStream = inputStream;
}
@Override
public void run() {
byte[]mode=new byte[13];//对话0 文件1
while (inputStream!= null) {
for(int i=0;i<13;i++){
try {
mode[i]=(byte)inputStream.read();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
String modestr =new String(mode);
//传送的数据模式 0 对话 1 文件
try {
//对话或文件
int modeCode = Integer.parseInt(modestr.substring(0, 1), 10);
//对话或文件大小
long inLength = Long.parseLong(modestr.substring(1, 11), 10);
//如果是文件的话文件名长度
int nameLength = Integer.parseInt(modestr.substring(11, 13), 10);
byte[] fileName = new byte[nameLength];
byte[] mgs = new byte[new Long(inLength).intValue()];
//设置buff缓存为512字节
int inTime=(int)(inLength/512);
int inTimeResidue=(int)(inLength%512);
if (modeCode == 0) {
for (int i = 0; i < inLength; i++) {
try {
mgs[i] = (byte) inputStream.read();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
reviceMgs = new String(mgs,"UTF-8");
Log.e("收到数据", reviceMgs.toString());
handler.sendEmptyMessage(1);
// ET_print.getText().append("\n"+new String(mgs));
} else if (modeCode == 1) {
for (int i = 0; i < nameLength; i++) {
try {
fileName[i] = (byte) inputStream.read();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
reviceName = new String(fileName,"UTF-8");
Log.e("收到文件名", reviceName.toString());
// handler.sendEmptyMessage(1);
dir = new File("/mnt/sdcard/WifiSocketDownload/"+reviceName);
File file = new File("/mnt/sdcard/WifiSocketDownload");
if (!file.exists()) {
try {
//按照指定的路径创建文件夹
file.mkdirs();
Log.e("创建文件夹成功",file.toString());
} catch (Exception e) {
// TODO: handle exception
Log.e("创建文件夹失败","创建文件夹失败");
}
}
if (!dir.exists()) {
try {
//在指定的文件夹中创建文件
dir.createNewFile();
Log.e("创建文件成功",dir.toString());
} catch (Exception e) {
Log.e("创建文件失败","创建文件失败");
}
}
if(inTime>=0&&inTimeResidue>0) {
byte[] buffer = new byte[512];
reciveTime= 0;
for (int i = 0; i < inTime + 1; i++) {
for (int k = 0; k < 512; k++) {
try {
buffer[k] = (byte) inputStream.read();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
writeFileSdcard(dir, buffer);
handler.sendEmptyMessage(99);
}
}else if(inTime>=0&&inTimeResidue==0){
byte[] buffer = new byte[512];
reciveTime= 0;
for (int i = 0; i < inTime ; i++) {
for (int k = 0; k < 512; k++) {
try {
buffer[k] = (byte) inputStream.read();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
writeFileSdcard(dir, buffer);
handler.sendEmptyMessage(99);
}
}
handler.sendEmptyMessage(98);
}
}catch (Exception e){
}
}
}
}
public void writeFileSdcard(File fileName, byte []wb){
try{
//FileOutputStream fout = openFileOutput(fileName, MODE_PRIVATE);
FileOutputStream fout = new FileOutputStream(fileName,true);
fout.write(wb);
fout.close();
}
catch(Exception e){
e.printStackTrace();
}
}
while (true){ try { socket = server.accept(); in = socket.getInputStream(); handler.sendEmptyMessage(2); } catch (IOException e) { e.printStackTrace(); } new ServerThread(socket,in).start(); }
new ServerThread(socket,in).start();进行监听
(如果要实现多人群聊的话,就是美有一个客户端进行连接,就把这个客户端保存到list里面然后服务器进行数据转发,我这里没有保存,也没有关闭前一个客户端,如果有两个客户端进行连接的话,服务器发的对话只能最近一个客户端可以收到,但是客户端发给服务器的数据,服务器都能收到)
在ServerThread的run方法里对接收到的数据进行处理
byte[]mode=new byte[13];
13个字节为发送过来的头部分,其中第一个字节判断是发送的对话还是文件,第二到11共10字节为发送类容的字节数(比如163字节的类容就表示为0000000163)(好像最大可以是9个多G的样子,一般用不到这么长啦),11到13字节表示文件名长度,如果是对话就是00.
for(int i=0;i<13;i++){ try { mode[i]=(byte)inputStream.read(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }读出13字节的头
//对话或文件 int modeCode = Integer.parseInt(modestr.substring(0, 1), 10); //对话或文件大小 long inLength = Long.parseLong(modestr.substring(1, 11), 10); //如果是文件的话文件名长度 int nameLength = Integer.parseInt(modestr.substring(11, 13), 10); byte[] fileName = new byte[nameLength]; byte[] mgs = new byte[new Long(inLength).intValue()];
下面是服务器发给客户端发送对话的方法(没有加发送文件,客户端有发送文件,如果服务器要向客户端发送文件,可以用客户端发送文件的方法)
public static Boolean send(Socket socket, byte[] msg) {
DataOutputStream out=null;
try {
out = new DataOutputStream((socket.getOutputStream()));
String mode ="0";
String name ="00";
int mgsLength =msg.length;
String ll =String.format("%010d", mgsLength);
String sss=mode+ll+name;
byte sendByte[] =addBytes(sss.getBytes("UTF-8"),msg);
Log.e("aa","类容字节"+ Arrays.toString(sendByte));
out.write(sendByte);
System.out.println("写入数据");
return true;
// out.flush();
} catch (IOException e) {
e.printStackTrace();
System.out.println("写入数据异常");
return false;
}
}
public static byte[] addBytes(byte[] data1, byte[] data2) {
byte[] data3 = new byte[data1.length + data2.length];
System.arraycopy(data1, 0, data3, 0, data1.length);
System.arraycopy(data2, 0, data3, data1.length, data2.length);
return data3;
}
if (!wifiManager.isWifiEnabled()) { wifiManager.setWifiEnabled(true); }
WifiConfiguration config = new WifiConfiguration(); config.SSID = "\"wifisocket\""; config.preSharedKey = "\"00000000\"";//加密wifi config.hiddenSSID = true; config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP); config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP); //config.allowedProtocols.set(WifiConfiguration.Protocol.WPA); config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP); config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP); config.status = WifiConfiguration.Status.ENABLED; int netId = wifiManager.addNetwork(config);
上面是打开WiFi 连接服务WiFi热点的代码
连接上服务器热点后,启动客户端连接服务器:
public void initClientSocket() {
try {
socket = new Socket("192.168.43.1", 9999);
handler.sendEmptyMessage(1);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
System.out.println("请检查端口号是否为服务器IP");
handler.sendEmptyMessage(5);
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("服务器未开启");
handler.sendEmptyMessage(5);
e.printStackTrace();
}
}
private class ReadThread extends Thread{
@Override
public void run() {
byte[]mode=new byte[13];//对话0 文件1
InputStream inputStream = null;
try {
inputStream = socket.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
while (inputStream!= null) {
for(int i=0;i<13;i++){
try {
mode[i]=(byte)inputStream.read();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
// try {
// Log.e("关闭socket"," socket.close();");
// inputStream.close();
// socket.close();
// } catch (IOException e1) {
// e1.printStackTrace();
// }
}
}
String modestr =new String(mode);
//传送的数据模式 0 对话 1 文件
try{
int modeCode=Integer.parseInt(modestr.substring(0,1), 10);
//对话或文件大小
int inLength=Integer.parseInt(modestr.substring(1,11), 10);
//如果是文件的话文件名长度
int nameLength=Integer.parseInt(modestr.substring(11,13), 10);
byte[]fileName=new byte[nameLength];
byte[]mgs=new byte[inLength];
for(int i=0;i
就可以在点击时执行
new Thread(runnable).start();//开启线程
Runnable runnable = new Runnable() { @Override public void run() { // TODO Auto-generated method stub initClientSocket(); readThread = new ReadThread(); readThread.start(); } };
下面是像服务器发送对话和文件的方法(发送文件前要选着一个文件路径)
public static byte[] addBytes(byte[] data1, byte[] data2) {
byte[] data3 = new byte[data1.length + data2.length];
System.arraycopy(data1, 0, data3, 0, data1.length);
System.arraycopy(data2, 0, data3, data1.length, data2.length);
return data3;
}
public static Boolean send(Socket socket, byte[] msg) {
DataOutputStream out=null;
try {
out = new DataOutputStream((socket.getOutputStream()));
String mode ="0";
String name ="00";
int mgsLength =msg.length;
String ll =String.format("%010d", mgsLength);
String sss=mode+ll+name;
byte sendByte[] =addBytes(sss.getBytes("UTF-8"),msg);
Log.e("aa","类容字节"+ Arrays.toString(sendByte));
out.write(sendByte);
System.out.println("写入数据");
return true;
// out.flush();
} catch (IOException e) {
e.printStackTrace();
System.out.println("写入数据异常");
return false;
}
}
public Boolean sendfile(Socket socket) {
DataOutputStream out=null;
try {
out = new DataOutputStream((socket.getOutputStream()));
String mode ="1";
String[] getname = file_path.split("/");
String filename=getname[getname.length-1];
byte filenamebyte[] =filename.getBytes("UTF-8");
String name =String.format("%02d", filenamebyte.length);
File file =new File(file_path);
if (file.exists()) {
sendtime=0;
FileInputStream fis = null;
fis = new FileInputStream(file);
size = fis.available();
String filesizeString =String.format("%010d", size);
String sss=mode+filesizeString+name;
byte sendByteHead[] =addBytes(sss.getBytes("UTF-8"),filenamebyte);
out.write(sendByteHead);
handler.sendEmptyMessage(91);
int n=512;
byte buffer[]=new byte[n];
while((fis.read(buffer,0,n)!=-1)&&(n>0)){
System.out.println(Arrays.toString(buffer));
System.out.println(new String(buffer));
out.write(buffer);
handler.sendEmptyMessage(92);
}
System.out.println("写入完成");
handler.sendEmptyMessage(93);
fis.close();
return true;
} else {
file.createNewFile();
Log.e("获取文件大小", "文件不存在!");
return false;
}
// out.flush();
} catch (IOException e) {
e.printStackTrace();
System.out.println("写入数据异常");
return false;
}
}
源码下载地址:点击打开链接
如果改下包名安装成2个APP,同一个手机也可以同时启动服务器和客户端,下图就是同一pad上进行通信的截图。