Android通过WIFI建立热点,通过scoket实现聊天室,文件传输等通信功能。

    xiaoxiao2021-03-25  65

    最近要做一个手机跟蓝牙模块进行通信的项目,查了一些资料,做出了一个可以实现通信的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)(inLengthQ2); 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("0d", 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<inLength;i++){ try { mgs[i]=(byte)inputStream.read(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(modeCode==0){ reviceMgs=new String(mgs,"UTF-8"); Log.e("收到数据",reviceMgs.toString()); handler.sendEmptyMessage(3); // ET_print.getText().append("\n"+new String(mgs)); }else if (modeCode==1){ } }catch (Exception e){ } } } } 我们可以设置一个按钮,点击按钮就连接服务器启动线程

    就可以在点击时执行

    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("0d", 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("d", 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("0d", 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上进行通信的截图。

    转载请注明原文地址: https://ju.6miu.com/read-39047.html

    最新回复(0)