实现一个聊天室可发送消息语音图片视频表情包(任意文件)

文章目录

  • 如何跑通
  • 代码仓库地址
  • 客户端
    • 登录
    • 发送消息
    • 接受消息
    • 发送文件
    • 接受文件
  • 服务端
    • 接受消息并发送给各个客户端
    • 接受文件并发送给各个客户端

如何跑通

  • 将手机和电脑都连自己的热点
  • 先运行服务器得到可监听的地址
  • 更新客户端安卓消息线程和文件线程的socker目标地址为可监听地址
  • 然后数据线连接手机运行,此时手机便多了个app,然后可以不需要数据线单独运行了

代码仓库地址

https://github.com/FULLK/llkchatroom/

客户端

登录

输入用户名。获取输入的用户名和通信IP

protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);input_name = (TextView) findViewById(R.id.input_name);Button confirm = (Button) findViewById(R.id.confirm);confirm.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Name.name = input_name.getText().toString();//得到输入的字符串Name.IP = getLocalIpAddress();Log.e("Register", Name.IP + Name.name);if (!Name.name.equals("")) {//输入内容不为空那么点击就跳转到chatromm界面Intent intent = new Intent(MainActivity.this, Chatroom.class);startActivity(intent);}}});}public static String getLocalIpAddress() {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.isLinkLocalAddress()) {return inetAddress.getHostAddress().toString();}}}} catch (SocketException ex) {Log.e("WifiPreference IpAddre", ex.toString());}return null;}

首先是输入用户名存到Name结构体中

public class Name {public static String name ;public static  String IP;
}

这段Java代码遍历了本机的所有网络接口(NetworkInterface),然后对于每个网络接口,进一步遍历其绑定的所有IP地址(InetAddress)。其核心目的是找到并返回一个符合条件的IPv4或IPv6地址,该地址既不是回环地址(loopback address,如127.0.0.1),也不是链路本地地址(link-local address,这类地址仅用于同一链路上的通信,如IPv6的fe80::/10范围内的地址)。具体步骤如下:

  1. 获取网络接口枚举:首先通过NetworkInterface.getNetworkInterfaces()方法获取到本机所有网络接口的枚举(Enumeration)对象。网络接口可以理解为计算机上的物理或虚拟网卡。

  2. 遍历网络接口:使用hasMoreElements()nextElement()方法遍历所有的网络接口。对于每个网络接口intf

  3. 获取IP地址枚举:通过intf.getInetAddresses()方法获取该网络接口上绑定的所有IP地址的枚举。

  4. 遍历IP地址:再次使用hasMoreElements()nextElement()遍历这些IP地址。对于每个IP地址inetAddress

  5. 检查地址类型:使用isLoopbackAddress()方法检查这个IP地址是否是回环地址,使用isLinkLocalAddress()方法检查是否是链路本地地址。这两个条件都不满足,意味着这个IP地址是可外部访问的地址。

  6. 返回符合条件的IP地址:一旦找到一个既不是回环地址也不是链路本地地址的IP地址,就立即通过getHostAddress().toString()获取其字符串表示形式并返回。这意味着该方法最终返回的是本机的第一个非回环、非链路本地的IP地址。

发送消息

定义消息类

public class Msg {public static final int TYPE_RECEIVED = 0;//收到的消息public static final int TYPE_SENT = 1;//发出去的消息private String name;private String content;private int type;//content表示消息内容,type表示类型public Msg(String name,String content ,int type){this.name = name;this.content = content;this.type = type;}public String getContent(){return content;}public int getType(){return type;}public String getName() {return name;}
}

点击按钮后发送消息

send.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {String content = inputTest.getText().toString();Log.e("get from input", content);if (!"".equals(content)) {try {//将输入框的信息传递给msg,并标记Message handleMsg = new Message();handleMsg.what = 1;handleMsg.obj = inputTest.getText().toString();//将msg传递给发送子线程mClientThread.revHandler.sendMessage(handleMsg);//输入框变空inputTest.setText("");} catch (Exception e) {e.printStackTrace();}}}});

子线程不断循环运行实现发送消息

  Looper.prepare();//绑定发送线程的Handler//由chatroom点击事件跳转到这里发送消息revHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {if (msg.what == 1) {try {//发送消息String content;content =Name.IP+"#$#" + Name.name+"#$#" + msg.obj.toString() + "\r\n";mOutputStream.write(content.getBytes("utf-8"));} catch (IOException e) {e.printStackTrace();}}}};//Looper.loop(); 让Looper开始工作,从消息队列里取消息,处理消息。Looper.loop();} catch (IOException e) {e.printStackTrace();Log.d("error","");}

接受消息

子线程循环接受服务端的消息

      new Thread(){@Overridepublic void run() {super.run();try {String content = null;//一个新线程持续循环的接受从服务器的消息,再发送给chatroomwhile ((content = mBufferedReader.readLine()) != null) {Log.d("get from server",content);//将接受到的数据传递给msg对象,并标记Message handleMsg = new Message();handleMsg.what = 0;handleMsg.obj = content;mHandler.sendMessage(handleMsg);}}catch (IOException e){e.printStackTrace();}}}.start();//启动

然后发送给主线程,主线程根据接受到的消息来更新聊天界面

  mHandler = new Handler() {@Overridepublic void handleMessage(Message handleMsg) {if (handleMsg.what == 0) {//接受到消息后的操作String content = handleMsg.obj.toString();Log.d("recive", content);String[] arr = content.split("#\\$#");String ip = arr[0];String name = arr[1];String str = arr[2];Log.d("get ", ip + name + str);Msg msg;if (ip.equals(Name.IP)) {Log.e("recive from server", "it is me ");msg = new Msg(name, str, Msg.TYPE_SENT);} else {msg = new Msg(name, str, Msg.TYPE_RECEIVED);}msgList.add(msg);Log.e("TAG", "msg " + msgList.size());adapter.notifyItemInserted(msgList.size() - 1);//当有新消息时,刷新RecyclView中的显示msgRecyclerView.scrollToPosition(msgList.size() - 1);//将RecyclerView定位到最后一行inputTest.setText("");//清空输入框*/}}};

发送文件

首先选择文件

file.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 创建意图用于选择文件//Intent intent = new Intent(Intent.ACTION_GET_CONTENT);//intent.setType("*/*");/*if (intent.resolveActivity(getPackageManager()) != null) {startActivityForResult(Intent.createChooser(intent, "选择文件"), PICK_FILE_REQUEST_CODE);} else {Toast.makeText(context, "无法找到文件选择器", Toast.LENGTH_SHORT).show();}*/Intent intent = new Intent(Intent.ACTION_GET_CONTENT);intent.addCategory(Intent.CATEGORY_OPENABLE);intent.setType("*/*");startActivityForResult(intent, PICK_FILE_REQUEST_CODE);}});

然后对选择到的文件的返回结果进行处理

protected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (requestCode == PICK_FILE_REQUEST_CODE && resultCode == RESULT_OK) {try {if (data != null) {Uri uri = data.getData();Log.e("uri", ":" + uri);String filePath = "";// 根据Android版本的不同,获取文件路径的方式也有所不同// 在API 19(KitKat)及以上版本,需要通过ContentResolver查询文件的真实路径if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(this, uri)) {// 处理DocumentsProvider的情况ContentResolver resolver = getContentResolver();InputStream inputStream = null;inputStream = resolver.openInputStream(uri);String filename = getFileNameFromUri(this, uri);Log.e("filename: ", ":" + filename);Log.e("inputstream: ", ":" + inputStream);Log.e("uri: ", ":" + uri);if (uri != null) {handleSelectedFilePath(filename,uri);}}}}catch (FileNotFoundException e) {e.printStackTrace();}}}

其中处理返回结果调用下列函数得到了文件名,并且将选择的文件写到了一个新建的可知道文件路径的文件(因为不能根据返回结果得到文件路径)

public String getFileNameFromUri (Context context, Uri uri){String fileName = null;Cursor cursor = null;try {cursor = context.getContentResolver().query(uri, null, null, null, null);if (cursor != null && cursor.moveToFirst()) {int columnIndex = cursor.getColumnIndex(MediaStore.Files.FileColumns.DISPLAY_NAME);fileName = cursor.getString(columnIndex);}} finally {if (cursor != null) {cursor.close();}}return fileName;}private void handleSelectedFilePath (String filename, Uri file){// 在这里处理获取到的文件路径Log.e("TAG", "Selected file name" + filename);// 可以进一步上传文件、读取文件内容等操作try {// 假设你已经有了一个Uri对象Uri sourceUri = file;// 获取源文件的输入流InputStream inputStream = getContentResolver().openInputStream(sourceUri);// 定义目标文件路径,这里以应用程序的cache目录为例String destFilePath = getCacheDir().getPath() + "/"+filename;File destFile = new File(destFilePath);// 创建并获取目标文件的输出流FileOutputStream outputStream = new FileOutputStream(destFile);// 将源文件内容复制到新文件byte[] buffer = new byte[1024];int read;while ((read = inputStream.read(buffer)) != -1) {outputStream.write(buffer, 0, read);}// 关闭输入输出流outputStream.flush();outputStream.close();inputStream.close();// 现在你可以得到新建文件的文件地址String newFileAddress = destFile.getAbsolutePath();Log.e("getAbsolutePath", ": "+newFileAddress );//将输入框的信息传递给msg,并标记Message handleMsg = new Message();handleMsg.what = 1;handleMsg.obj =newFileAddress ;//"/data/data/llk/files/"//将msg传递给发送子线程fClientThread.revfHandler.sendMessage(handleMsg);//输入框变空inputTest.setText("");} catch (Exception e) {e.printStackTrace();}}}

最后handleSelectedFilePath函数将包含新建文件地址发送到子线程,子线程将文件名字和文件长度和文件字节发送到服务端

  Looper.prepare();//绑定发送线程的Handler//由chatroom点击事件跳转到这里发送消息revfHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {if (msg.what == 1) {try {mOutputStream = fSocket.getOutputStream();//输出流,客户端到管道//发送消息String content;File file = new File(msg.obj.toString());Log.e("msg.obj.toString()",": "+msg.obj.toString());content = Name.IP + "#$#" + Name.name + "#$#" + file.getName() + "\r\n";Log.e("content", ": "+content );mOutputStream.write(content.getBytes("utf-8"));//先发送了name ip 消息再发送文件内容DataOutputStream fout = new DataOutputStream(fSocket.getOutputStream());DataInputStream fin = new DataInputStream(new FileInputStream(file));//将文件发送出去// 传送文件名字fout.writeUTF(file.getName());Log.e("file.getname()", ": "+file.getName() );fout.flush();// 传送长度fout.writeLong(file.length());Log.e("file.length()", ": "+file.length() );fout.flush();System.out.println("开始传送文件...(大小:" + file.getTotalSpace() + ")");// 传送文件int lengthout = -1;// 读取到的文件长度byte[] buffout = new byte[1024];double curLength = 0;// 循环读取文件,直到结束while ((lengthout = fin.read(buffout)) > 0) {Thread.sleep(10);Log.e(" ", "lengthout: "+lengthout );curLength+=lengthout;Log.e("curlength / length", ": "+curLength+"/"+file.length());fout.write(buffout, 0, lengthout);fout.flush();}System.out.println("传送文件完成");Thread.sleep(5000);byte[] bytes = "EOF".getBytes(Charset.forName("UTF-8"));fout.write(bytes);} catch (IOException | InterruptedException e) {e.printStackTrace();}}}};//Looper.loop(); 让Looper开始工作,从消息队列里取消息,处理消息。Looper.loop();}

接受文件

子线程不断接受从服务端发送过来的文件,也是接受文件名和文件长度和文件字节内容,但会在指定路径新建一个文件来接受传输过来的内容。中途会更新消息列表再去接受

 new Thread() {@Overridepublic void run() {super.run();try {while (true){String filename = null;String content = null;DataInputStream dis = new DataInputStream(fSocket.getInputStream());// 从服务器传过来的东西System.out.println("客户端已经链接文件服务");//先传输过来名字和ip和提示文件到达消息mBufferedReader = new BufferedReader(new InputStreamReader(fSocket.getInputStream()));content = mBufferedReader.readLine();Log.e("content", ": "+content );Message handleMsg = new Message();handleMsg.what = 0;handleMsg.obj = content+" position at "+" /storage/emulated/0/Download/";fHandler.sendMessage(handleMsg);filename = dis.readUTF();Log.e("file name", "/storage/emulated/0/Download/"+filename );//根据服务器发送过来的UTF格式的文件名字String destFilePath ="/storage/emulated/0/Download/"+filename;File file = new File(destFilePath);file.createNewFile();// 保存到本地的文件//获取服务器传过来的文件大小Log.e("new position", " "+file.getAbsolutePath() );//显示完整路径double totleLength = dis.readLong();Log.e("length", " "+totleLength );DataOutputStream dos = new DataOutputStream(new FileOutputStream(file));//通过dos往文件里写入内容System.out.println("开始接收:" + totleLength);int length = -1;long recvlength = -1;byte[] buff = new byte[1024];double curLength = 0;try {while((length=dis.read(buff))>0){String str = new String(buff, StandardCharsets.UTF_8);if (str.charAt(0)=='E'&&str.charAt(1)=='O'&&str.charAt(2)=='F'){break;}dos.write(buff, 0, length);Arrays.fill(buff, (byte) 0);//往文件里写入buffLog.e("写入文件的长度: ", " "+length );curLength+=length;//System.out.println("传输进度:"+(curLength/totleLength*100)+"%");System.out.println("传输进度:"+(curLength/totleLength*100)+"%");}System.out.println("传输完成");} catch (Exception ste) {System.out.println("接收文件出错");}}}catch (IOException e) {e.printStackTrace();}}}.start();

中途发送到主线程根据文件消息更新消息列表

 fHandler = new Handler() {@Overridepublic void handleMessage(Message handleMsg) {if (handleMsg.what == 0) {//接受到消息后的操作String content = handleMsg.obj.toString();Log.e("recive content", content);String[] arr = content.split("#\\$#");String ip = arr[0];String name = arr[1];String file = arr[2];Log.e("get ", ip+file + name);Msg msg;if (ip.equals(Name.IP)) {Log.e("recive from server", "it is me ");msg = new Msg(name, file, Msg.TYPE_SENT);} else {msg = new Msg(name, file, Msg.TYPE_RECEIVED);}msgList.add(msg);Log.e("TAG", "msg " + msgList.size());adapter.notifyItemInserted(msgList.size() - 1);//当有新消息时,刷新RecyclView中的显示msgRecyclerView.scrollToPosition(msgList.size() - 1);//将RecyclerView定位到最后一行inputTest.setText("");//清空输入框*/}}};

服务端

先列出各个可以监听的ip地址,然后得到运行两个子线程,分别用处理接受消息和文件并再发送给各个客户端


public class MyServer {public static ArrayList<Socket> mSocketList = new ArrayList<>() ;public static ArrayList<Socket> fSocketList = new ArrayList<>() ;public static void main(String[] args) throws SocketException{Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();while (networkInterfaces.hasMoreElements()) {NetworkInterface ni = networkInterfaces.nextElement();for (InterfaceAddress ia : ni.getInterfaceAddresses()) {InetAddress inetAddress = ia.getAddress();if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) {System.out.println("ServerSocket可能监听的IP地址: " + inetAddress.getHostAddress());}}}try {//创建服务器SocketServerSocket ss = new ServerSocket(8848);ServerSocket fs = new ServerSocket(18848);while (true){//监听链接Socket s = ss.accept();Socket f = fs.accept();//打印信息System.out.println("ip:"+ s.getInetAddress().getHostAddress() +"加入聊天室");System.out.println("ip:"+ f.getInetAddress().getHostAddress()+" 客户端已经链接文件服务");//将s加入到线程池中mSocketList.add(s);fSocketList.add(f);//启动子线程new Thread(new ServerThread(s)).start();new Thread(new FileThread(f) ).start();}}catch (IOException e){e.printStackTrace();System.out.println("服务器已崩溃");e.printStackTrace();}}
}

接受消息并发送给各个客户端

接受消息,然后发给各个客户端


public class ServerThread implements Runnable {private Socket mSocket = null;private BufferedReader mBufferedReader = null;//构造方法public ServerThread(Socket s)throws IOException{mSocket = s;//输入管道到服务器mBufferedReader = new BufferedReader(new InputStreamReader(s.getInputStream(), "utf-8"));}public void run(){try {String content = null;//循环接受服务器消息,如果没有接收到,说明该客户端下线,将其从线程池中删除while ((content = mBufferedReader.readLine())!=null){System.out.println("ip:"+ mSocket.getInetAddress().getHostAddress()+":"+content);//循环向其他线程发送消息for (Iterator<Socket> it = MyServer.mSocketList.iterator();it.hasNext();) {Socket s = it.next();try {OutputStream os = s.getOutputStream();os.write((content + "\n").getBytes("utf-8"));} catch (SocketException e) {e.printStackTrace();it.remove();}}}}catch (IOException e){System.out.println("接收出错");try {mSocket.close();} catch (IOException e1) {e1.printStackTrace();}MyServer.mSocketList.remove(mSocket);System.out.println("ip:"+ mSocket.getInetAddress().getHostAddress() +"退出聊天室");}}
}

接受文件并发送给各个客户端

接受文件相关信息,在本地新建一个文件,并将接受到的字节流写入文件,然后再将文件相关信息和字节内容发送给各个客户端

public class FileThread implements Runnable{private Socket fSocket = null;private BufferedReader fBufferedReader = null;//构造方法public FileThread(Socket f)throws IOException{fSocket = f;//输入管道到服务器}@Overridepublic void run() {try {while (true) {System.out.println("new");   String filename = null;String content = null;DataInputStream dis = new DataInputStream(fSocket.getInputStream());// 从服务器传过来的东西//先传输过来名字和ip和提示文件到达消息BufferedReader mBufferedReader = new BufferedReader(new InputStreamReader(fSocket.getInputStream()));content = mBufferedReader.readLine()+"\r\n";System.out.println("content"+content);filename=dis.readUTF();//根据客户端发送过来的UTF格式的文件名字File file = new File("D:\\androidstudio\\chatroom\\server\\savefile\\"+filename);System.out.println("filename"+filename);if (!file.exists()) {try {// 新建文件boolean created = file.createNewFile();if (created) {System.out.println("成功创建文件");// 文件成功创建} else {// 文件创建失败,可能是因为权限问题或其他原因}} catch (IOException e) {e.printStackTrace();}}// 保存到本地的文件//获取服务器传过来的文件大小double totleLength = dis.readLong();System.out.println("file length "+totleLength);DataOutputStream dos = new DataOutputStream(new FileOutputStream(file));//通过dos往文件里写入内容System.out.println("开始接收:"+totleLength);int length=-1;byte[] buff= new byte[1024];double curLength = 0;try {while((length=dis.read(buff))>0){String str = new String(buff, StandardCharsets.UTF_8);System.err.println(str);if (str.charAt(0)=='E'&&str.charAt(1)=='O'&&str.charAt(2)=='F'){break;}dos.write(buff, 0, length);Arrays.fill(buff, (byte) 0); //往文件里写入buffcurLength+=length;//System.out.println("传输进度:"+(curLength/totleLength*100)+"%");System.out.println("传输进度:"+(curLength/totleLength*100)+"%");}System.out.println("传输完成");} catch (Exception ste) {System.out.println("接收文件出错"); }for (Iterator<Socket> it = MyServer.fSocketList.iterator();it.hasNext();){  Socket f= it.next();try {DataOutputStream fout = new DataOutputStream(f.getOutputStream());DataInputStream fin = new DataInputStream(new FileInputStream(file));fout.write(content.getBytes("utf-8"));System.out.println("content: "+content);//将文件发送出去// 传送文件名字fout.writeUTF(file.getName());System.out.println("file.getName() "+file.getName());fout.flush();// 传送长度fout.writeLong(file.length());System.out.println("file.length() "+file.length());fout.flush();System.out.println("开始传送文件...(大小:" + file.getTotalSpace() + ")");// 传送文件int lengthout = -1;// 读取到的文件长度byte[] buffout = new byte[1024];curLength = 0;// 循环读取文件,直到结束while ((lengthout = fin.read(buffout)) > 0) {Thread.sleep(4);//System.out.println(" lengthout: "+lengthout );curLength+=lengthout;System.out.println("curlength / length: "+curLength+"/"+file.length());fout.write(buffout, 0, lengthout);fout.flush();}System.out.println("传送文件完成");Thread.sleep(1000);byte[] bytes = "EOF".getBytes(Charset.forName("UTF-8"));fout.write(bytes);}catch (Exception e) {System.out.println("传输意外");}}  }}catch (IOException e) {System.out.println("接收出错");try {fSocket.close();} catch (IOException e1) {e1.printStackTrace();}MyServer.fSocketList.remove(fSocket);System.out.println("ip:"+ fSocket.getInetAddress().getHostAddress() +"文件传输结束");}} 
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/8173.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【JAVA】Git 的基本概念和使用方式

Git是一个开源的分布式版本控制系统&#xff0c;由Linus Torvalds创建&#xff0c;用于有效、高速地处理从小到大的项目版本管理。以下是Git的一些基本概念和使用方式的深入探讨&#xff1a; 基本概念 1. 仓库&#xff08;Repository&#xff09; 仓库是Git用来保存你的项目…

go解析含passphrase的pem秘钥

背景 在编写TLS配置时需要用到需要用到一串包含passphrase的RSA秘钥&#xff0c;本想通过官方库的方式解析使用&#xff0c;但由于安全因素&#xff0c;官方已经禁用了DecryptPEMBlock、EncryptPEMBlock、IsEncryptedPEMBlock等函数&#xff0c;导致无法通过官方库去实现这个需…

Unity 委托与事件、装箱和拆箱

文章目录 前言一、委托与事件1、委托的概念2、委托是什么3、事件是什么 二、装箱和拆箱1、什么是装箱和拆箱2、堆、栈3、应用4、优化 总结 前言 一、委托与事件 1、委托的概念 不知道大家在学习C#之前有没有学习过C/C&#xff0c;在中后期会接触到指针。她不仅能指向变量的地…

FPGA第一篇,FPGA现场可编程门阵列,从0开始掌握可编程硬件开发(FPGA入门指南)

简介&#xff1a;FPGA全称Field-Programmable Gate Array&#xff0c;是一种可编程逻辑器件&#xff0c;它通过可编程的逻辑单元和可编程的连接网络实现了灵活的硬件实现。与固定功能的集成电路&#xff08;ASIC&#xff09;相比&#xff0c;FPGA具有更高的灵活性和可重新配置性…

未授权访问:Redis未授权访问漏洞

目录 1、漏洞原理 2、环境搭建 3、未授权访问 4、利用redis未授权写入weshell 5、利用redis未授权反弹shell 6、利用redis未授权实现免密登录 防御手段 从这篇文章开始我就要开始学习各种未授权访问的知识和相关的实操实验了&#xff0c;一共有好多篇&#xff0c;内容主…

美港通正规炒股市场恒生科指半日跌近2% 大型科技股集体下行

查查配5月7日电 7日,港股主要股指回调。截至午盘,恒生指数跌0.85%,恒生科技指数跌1.98%。 美港通证券以其专业的服务和较低的管理费用在市场中受到不少关注。该平台提供了实盘交易、止盈止损、仓位控制等功能,旨在为投资者提供更为全面的投资体验。 来源:Wind 盘面上,零售、软…

OC5864 0.6A输出 60V输入 500KHZ DCDC降压转换IC

一级代理 技术支持 提供样品测试 Tel&#xff1a;18028786817 简介 OC5864是一款内置功率MOSFET的单片降压型开关模式转换器。OC5864在5.5~60V宽输入电源范围内实现0.6A峰值输出电流&#xff0c;并且具有出色的线电压和负载调整率。 OC5864采用PWM电流模工作模式&#xff0c;…

stm32单片机遇到的问题(持续更新)

flymcu下载问题一直显示连接&#xff0c;实际是连接不上 参考&#xff0c;软件一键下载电路等 使用flymcu下载程序过程中&#xff0c;检测两个地方**&#xff0c;第一&#xff0c;两个boot引脚在下载和硬件运行不同的连接方式** BOOT1x&#xff0c;BOOT00&#xff1a;最常用的模…

kubectl_进阶_网络

网络 容器网络发展到现在&#xff0c;形成了两大阵营&#xff0c;就是 Docker 的 CNM 和 Google、CoreOS、Kuberenetes 主导的 CNI。首先明确一点&#xff0c;CNM 和 CNI 并不是网络实现&#xff0c;他们是网络规范和网络体系&#xff0c;从研发的角度他们就是一堆接口&#x…

RPC 失败。curl 16 Error in the HTTP2 framing layer

报错&#xff1a; (base) hh-virtual-machine:~/work$ git clone https://github.com/yangzongzhuan/RuoYi-Vue3.git 正克隆到 RuoYi-Vue3... error: RPC 失败。curl 16 Error in the HTTP2 framing layer fatal: 在引用列表之后应该有一个 flush 包这个错误通常是由于 Git 在…

sql中的lag()和lead()是什么意思

在SQL中&#xff0c;LAG() 和 LEAD() 是窗口函数&#xff0c;它们用于访问行与其相邻行的数据。这两个函数在进行数据比较和分析时非常有用&#xff0c;尤其是在需要根据行的相对位置进行操作的场景中。 ### LAG() LAG() 函数用于访问当前行的前面的行中的数据。你可以指定你想…

CentOS操作

1.如何修改主机名 方法一&#xff1a; 修改命令&#xff1a;hostnamectl set-hostname 主机名 查看命令&#xff1a;hostname 方法二和方法三都是永久改变主机名&#xff0c;需要密码验证 方法二 修改命令&#xff1a;nmcli general hostname 主机名 查看命令&#xff…

了解 websocket

​ 1. 概念 1、 websocket 是一种双向通行协议。实现了浏览器与服务器全双工通信&#xff0c;能更好的节省服务器资源和带宽并达到实时通讯的目的&#xff1b; 2、websocket连接成功后&#xff0c;只要连接不断开&#xff0c;通信就会一保持着&#xff1b; 3、要打开一个 WebS…

三维点云处理-聚类(下)

接着前一部分数据聚类方法的介绍&#xff0c;由于K-means和GMM方法都是基于欧式距离信息处理的&#xff0c;两者分别以圆形和椭圆形来作为数据的聚类分割方式&#xff0c;这种情况下会导致环形图和月牙图数据分割不准确&#xff0c;因此进一步的介绍一种谱聚类方法&#xff0c;…

感知机导论

综述 每一个算法都是为了解决一类问题&#xff0c;或者说是解决之前算法存在的缺陷而产生的,感知机&#xff0c;在这里就起到了一个很大的作用&#xff0c;它向后续的很多算法暴露出来了很多它存在的缺陷。所以我们后面要学习的很多算法都是在某种程度上解决了感知机暴露出来的…

静态NAT

哈喽&#xff01;各位小伙伴们好久不见&#xff0c;最近由于工作的原因断更了一段时间&#xff0c;不过最近我都会把这些给补上&#xff0c;今天我们来学习一个简单的知识——静态NAT转换。 第一章 什么是NAT技术&#xff1f; 网络地址转换技术NAT&#xff08;Networ…

致远M3 log 敏感信息泄露漏洞

文章目录 免责漏洞描述漏洞原理影响版本漏洞复现修复方法 免责 只为学习与交流&#xff0c;若利用做一切违法乱纪的事与本人无关 漏洞描述 致远M3是一个企业移动业务管理平台&#xff0c;全面覆盖各种工作场景&#xff0c;通过智能化的办公和业务场景融合&#xff0c;为企业…

【数据库原理及应用】期末复习汇总高校期末真题试卷07

试卷 一、填空题&#xff08;每空1分&#xff0c;共10分&#xff09; 1.数据库管理系统在外模式、模式和内模式这三级模式之间提供了两层映象&#xff0c;其中 映象保证了数据的逻辑独立性。 2. 数据模型通常由 、数据操作和完整性约束三部分组…

未来几年,还是要掌握真正的技术

我看到某些人很鼓吹不要精心学技术&#xff0c;要学管理&#xff0c;学系统化的思想方式。这都是在鼓吹成功的玄学&#xff0c;其实成功的人都具备偶然性&#xff0c;换而言之&#xff0c;再给他一次机会&#xff0c;他不见得会赚取这么多的财富。过去几十年&#xff0c;经济高…

SAP FI 常用表

GL部分&#xff1a; FAGLFLEXT 新总账汇总表 GLT0 旧总帐汇总表 SKA1 总账科目主记录 (科目表) 科目表层数据 SKAT 总帐科目主记录&#xff08;科目表&#xff1a;说明&#xff09; 包括语言代码 SKB1 总帐科目主记录 (公司代码) 公司代码层数据 BKPF…