smark和openfire即时通信代码
从:http://blog.csdn.net/casuallc/article/details/34794501
server:openfire
client计划:smark写
首先安装openfire,下载client直接安装就可以。数据库能够用openfire自身的,也能够用自己的数据库,仅仅要按提示设置好參数就可以
之后,就能够用smark写一个client測试与openfire的通信了(须要引进的jar包除了smark自身的。还要引入xmlpull-1.1.3.1.jar、kxml2-2.3.0.jar两个包
,作用是解析xml文件)
备注:我用的smark版本号是4.0。要引入的基本包有smack-core-4.0.0.jar、smack-debug-4.0.0.jar、smack-extensions-4.0.0.jar、smack-tcp-4.0.0.jar
debug包使用来调试的。tcp是用来初始化连接的、extension包里面含有发送离线消息、文件等类
以下是创建一个连接
![](https://code.csdn.net/assets/CODE_ico.png)
- ConnectionConfiguration config = new ConnectionConfiguration("ip", 5222);
- //设置成disabled。则不会去验证server证书是否有效,默觉得enabled
- config.setSecurityMode(SecurityMode.disabled);
- //设置能够调试。默觉得false,老版本号的写法为XMPPConnection.DEBUG_ENABLED = true;
- config.setDebuggerEnabled(true);
- //设置是否在登陆的时候告诉server,默觉得true
- config.setSendPresence(false);
- //XMPPConnection在后来的版本号中改成了抽象类
- XMPPConnection conn = new XMPPTCPConnection(config);
- //设置等待时间
- conn.setPacketReplyTimeout(5000);
- conn.connect();
- //username,password,资源名(比如:假设是用潘迪安发送的消息。则资源名就是: 潘迪安,用于标识client)
- conn.login("admin", "0", "资源名");
关于连接的參数,在新版本号中所有在config中设置
发送消息
![](https://code.csdn.net/assets/CODE_ico.png)
- private void testSendMessage(XMPPConnection conn) throws Exception {
- //jid在数据表中ofroster能够查到。通常是 username@server名称
- Chat chat = ChatManager.getInstanceFor(conn).createChat("ly@192.168.1.100", new MessageListener() {
- @Override
- public void processMessage(Chat chat, Message message) {
- System.out.println("Received message: " + message);
- }
- });
- Message msg = new Message();
- msg.setBody("hello world");
- //定义成normal,在对象不在线时发送离线消息。消息存放在数据表ofoffline中
- msg.setType(Message.Type.normal);
- //发送消息。參数能够是字符串,也能够是message对象
- chat.sendMessage(msg);
- //发送广播
- conn.sendPacket(msg);
- }
发送离线消息
![](https://code.csdn.net/assets/CODE_ico.png)
- private void testOffLine(XMPPConnection conn) throws Exception {
- //离线文件
- OfflineMessageManager offMM = new OfflineMessageManager(conn);
- System.out.println("离线文件数量 :" + offMM.getMessageCount());
- System.out.println("离线文件内容 :");
- //经測试。当调用getMessages时,会触发chat设置的监听器,从而输出离线消息内容。可是getMessages方法返回的离线消息为空
- //推測回调函数的触发条件是一个变量,方变量改变时(while(flag))。运行回调函数
- List<Message> listMessage = offMM.getMessages();
- //listMessage的大小为0
- System.out.println(listMessage.size());
- for(Message m : offMM.getMessages()) {
- System.out.println(" 离线 : " + m.getBody() + m.getBodies());
- }
- }
得到好友列表
![](https://code.csdn.net/assets/CODE_ico.png)
- private void testGetRoster(XMPPConnection conn) throws Exception {
- //得到该user的roster(相当于好友列表),不区分是否在线
- Roster r = conn.getRoster();
- Collection<RosterEntry> c = r.getEntries();
- for(RosterEntry re : c) {
- StringBuilder sb = new StringBuilder();
- sb.append("name : ").append(re.getName());
- sb.append("\nuser : ").append(re.getUser());
- sb.append("\ntype : ").append(re.getType());
- sb.append("\nstatus : ").append(re.getStatus());
- System.out.println(sb.toString());
- System.out.println("-----------------------------");
- }
- System.out.println(r.getEntries());
- //输出内容
- /* name : null
- user : ly@192.168.1.100
- type : from
- status : null
- -----------------------------
- name : null
- user : yy@192.168.1.100
- type : to
- status : null
- -----------------------------
- [ly@192.168.1.100, yy@192.168.1.100]
- */
- }
管理好友,监听好友请求
![](https://code.csdn.net/assets/CODE_ico.png)
- <pre name="code" class="java">
![](https://code.csdn.net/assets/CODE_ico.png)
- </pre><pre name="code" class="java">private void testAddAndDelFriends(final XMPPConnection conn) throws Exception {
- Roster r = conn.getRoster();
- // 用户的jid。昵称,用户的分组。假设该用户不存在也能够加入
- // r.createEntry("yy@192.168.1.100", "yy", null);
- // rosterEntry的构造方法是包訪问权限。不能直接new
- // RosterEntry entry = r.getEntry("ly@192.168.1.100");
- // r.removeEntry(entry);
- //监听全部的请求,之后能够过滤掉不想要的请求
- PacketListener packetListener = new PacketListener() {
- @Override
- public void processPacket(Packet packet) throws NotConnectedException {
- /*
- available
- unavailable
- subscribe 发出加入好友的请求
- subscribed 允许加入好友
- unsubscribe 发出删除好友请求
- unsubscribed 删除好友(即拒绝加入好友)。
- 备注:对方发出加入好友的请求后。在server端会自己主动把对方加入到自己的roster,所以在运行处理好友请求或加入删除好友的时候,要又一次获取roster,更新好友列表
- */
- Presence presence = (Presence) packet;
- Type type = presence.getType();
- //请求加入好友
- if(Type.subscribe.equals(type)) {
- //注意点:要设置to(即指明要发送的对象,否则不能成功拒绝),至于from不用设置,由于在sendPacket方法中已经设置了,formMode初始化的时候为OMITTED,能够自己设置
- /*
- switch (fromMode) {
- case OMITTED:
- packet.setFrom(null);
- break;
- case USER:
- packet.setFrom(getUser());//getUser是抽象方法
- break;
- */
- //直接用传来的presence,不能自己新建一个presence(可能要验证presence是否是原来的对象,来推断是谁拒绝了谁的好友请求),否则不能成功拒绝对方加入好友
- //例:A--presence1-->B A---presence2---C, C---presence3---A这样server就没办法推断是B、C中的哪一个拒绝了A的请求
- presence.setType(Type.unsubscribed);//拒绝,发送了一条presence
- //presence.setType(Type.unavailable);//发送了两条presence,一条是subscribed,一条是unavailabled,能接受对方消息,自己的状态显示隐身。再一次登录的时候显示在线
- presence.setTo(presence.getFrom());
- presence.setPacketID(presence.getPacketID());
- Roster r = conn.getRoster();
- try {
- RosterEntry entry = r.getEntry(presence.getFrom());
- if(entry != null)
- r.removeEntry(entry);
- } catch (NotLoggedInException | NoResponseException | XMPPErrorException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- conn.sendPacket(presence);
- //多方删除自己
- } else if(Type.unsubscribe.equals(type)) {
- presence.setTo(presence.getFrom());
- presence.setType(Type.unsubscribe);
- Roster r = conn.getRoster();
- try {
- r.removeEntry(r.getEntry(presence.getFrom()));
- } catch (NotLoggedInException | NoResponseException | XMPPErrorException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- conn.sendPacket(presence);
- }
- }
- };
- // PacketFilter packetFilter = new PacketFilter() {
- //
- // //假设返回false,则不把事件交给listener处理,否则会调用packetListener中的processPacket方法
- // //方法解释true if and only if packet passes the filter.
- // @Override
- // public boolean accept(Packet packet) {
- // System.out.println("2" + packet);
- // return true;
- // }
- // };
- //过滤掉全部的不是好友请求、删除的全部packet
- PacketFilter packetFilter = new AndFilter(new PacketTypeFilter(Presence.class));
- conn.addPacketListener(packetListener, packetFilter);
- //未知
- RosterExchangeManager rem = new RosterExchangeManager(conn);
- rem.addRosterListener(new RosterExchangeListener() {
- @Override
- public void entriesReceived(String from, Iterator<RemoteRosterEntry> remoteRosterEntries) {
- System.out.println(from);
- while(remoteRosterEntries.hasNext()) {
- RemoteRosterEntry entry = remoteRosterEntries.next();
- System.out.println(entry.getUser() + " : " + entry.getName());
- }
- }
- });
- }
得到好友的信息。主要是VCard类的使用
![](https://code.csdn.net/assets/CODE_ico.png)
- private void testGetFriendInfo(XMPPConnection conn) throws Exception {
- VCard vCard = new VCard();
- VCardManager vcManager = new VCardManager();
- //此处返回false
- boolean b = vcManager.isSupported("ly@192.168.1.100", conn);
- System.out.println(b);
- vCard.load(conn, "ly@192.168.1.100");
- // Load Avatar from VCard
- byte[] avatarBytes = vCard.getAvatar();
- //得不到头像等的信息
- if(avatarBytes == null) {
- return;
- }
- // To create an ImageIcon for Swing applications
- ImageIcon icon = new ImageIcon(avatarBytes);
- System.out.println(icon.getIconWidth() + " : " + icon.getIconHeight());
- // To create just an image object from the bytes
- ByteArrayInputStream bais = new ByteArrayInputStream(avatarBytes);
- try {
- Image image = ImageIO.read(bais);
- FileOutputStream fos = new FileOutputStream("D://icon.jpg");
- fos.write(avatarBytes);
- fos.close();
- }
- catch (IOException e) {
- e.printStackTrace();
- }
- }
设置自己的状态信息
![](https://code.csdn.net/assets/CODE_ico.png)
- private void testSetInfo(XMPPConnection conn) throws Exception {
- VCard vCard = new VCard();
- vCard.load(conn);
- vCard.setEmailHome("admin@126.com");
- vCard.setAddressFieldWork("POSTAL", "汇宝大厦");
- //改动完要保存改动的内容,否则没办法更新到server
- vCard.save(conn);
- //改动自身的状态,包含隐身,上线(能够指定对特定的好友更改状态)
- Presence p = new Presence(Type.available);
- p.setTo("ly@192.168.1.100");
- //改动心情
- p.setStatus("我的心情");
- //相同要发到server
- conn.sendPacket(p);
- }
监听好友的状态
![](https://code.csdn.net/assets/CODE_ico.png)
- private void testSetRosterListener(XMPPConnection conn) throws Exception {
- Roster r = conn.getRoster();
- r.createEntry("ly@192.168.1.100", "昵称", null);
- r.addRosterListener(new RosterListener() {
- @Override
- public void presenceChanged(Presence presence) {
- //更改状态信息时调用该方法(更改在线状态。改动心情。改动头像等)
- System.out.println("presenceChanged");
- }
- @Override
- public void entriesUpdated(Collection<String> addresses) {
- //该方法以及以下的方法都是在server改动好友信息时触发
- System.out.println("entriesUpdated");
- }
- @Override
- public void entriesDeleted(Collection<String> addresses) {
- // TODO Auto-generated method stub
- System.out.println("entriesDeleted");
- }
- @Override
- public void entriesAdded(Collection<String> addresses) {
- // TODO Auto-generated method stub
- System.out.println("entriesAdded");
- }
- });
- }
监听好友的输入状态
![](https://code.csdn.net/assets/CODE_ico.png)
- private void testGetExtention(XMPPConnection conn) throws Exception {
- Chat chat = ChatManager.getInstanceFor(conn).createChat("ly@192.168.1.100", new MessageListener() {
- @Override
- public void processMessage(Chat chat, Message message) {
- //得到输入状态,分为五种:正在输入(composing)。暂停输入(paused),发送(active),关闭对话框(gone)
- PacketExtension pe = message.getExtension("http://jabber.org/protocol/chatstates");
- switch (pe.getElementName()) {
- case "composing":
- System.out.println("正在输入......");
- break;
- case "paused":
- System.out.println("正在冥想......");
- break;
- case "active":
- System.out.println("对方已发送。");
- break;
- case "gone":
- System.out.println("对话框已被关闭。");
- break;
- default:
- break;
- }
- }
- });
- Message msg = new Message();
- msg.addExtension(new ChatStateExtension(ChatState.gone));
- msg.setBody("hello world");
- chat.sendMessage(msg);
- }
增加聊天室进行多人聊天
![](https://code.csdn.net/assets/CODE_ico.png)
- private MultiUserChat multiUserChat;
- private void testMutiUserChat(XMPPConnection conn) throws Exception {
- MultiUserChat.addInvitationListener(conn, new InvitationListener() {
- @Override
- public void invitationReceived(XMPPConnection conn, String room, String inviter, String reason, String password, Message message) {
- StringBuilder sb = new StringBuilder();
- sb.append("房间号 : ").append(room);
- sb.append("\n邀请者 : ").append(inviter);
- sb.append("\n理由 : ").append(reason);
- sb.append("\n密码 : ").append(password);
- sb.append("\n消息 : ").append(message);
- System.out.println(sb);
- multiUserChat = new MultiUserChat(conn, room);
- try {
- multiUserChat.join("admin", password);
- } catch (XMPPErrorException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (SmackException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- multiUserChat.addMessageListener(new PacketListener() {
- @Override
- public void processPacket(Packet packet) throws NotConnectedException {
- Message msg = (Message) packet;
- System.out.println(msg.getBody());
- }
- });
- }
- });
- while(true) {
- try {
- Thread.sleep(500);
- if(multiUserChat == null)
- continue;
- //关于发送消息的问题。能够直接发字符串
- //也能够发送message。可是要设定message的一些參数,否则不能发送(參数设置例如以下)
- //用Chat发送消息时。不用设置,原因是在Chat的sendMessage方法中已经加入了这些參数
- /*
- * message.setTo(participant);
- message.setType(Message.Type.chat);
- message.setThread(threadID);
- */
- //可是,用MultiUserChat类中的sendMessage方法,直接调用了XMPPConnection中的sendPacket方法,没有设置Message的參数
- Message msg = new Message();
- //房间名称
- msg.setTo("a@conference.192.168.1.100");
- msg.setType(Message.Type.groupchat);
- msg.setThread(Thread.currentThread().getId() + "");
- msg.setBody("hello");
- multiUserChat.sendMessage(msg);
- break;
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (NotConnectedException e) {
- e.printStackTrace();
- } catch (XMPPException e) {
- e.printStackTrace();
- }
- }
- }
发送和接收文件
![](https://code.csdn.net/assets/CODE_ico.png)
- private void testSendFile(XMPPConnection conn) throws Exception {
- // 发送文件的管理器
- FileTransferManager ftm = new FileTransferManager(conn);
- ftm.addFileTransferListener(new FileTransferListener() {
- @Override
- public void fileTransferRequest(FileTransferRequest request) {
- System.out.println(request.getFileName());
- IncomingFileTransfer inComingFileTransfer = request.accept();
- try {
- //能够直接写到file文件里
- File file = new File("D://" + request.getFileName());
- inComingFileTransfer.recieveFile(file);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- });
- // 注意jid格式。以下为标准格式,假设不正确则会抛出jid格式错误的异常
- // (if (parseName(jid).length() <= 0 || parseServer(jid).length() <= 0|| parseResource(jid).length() <= 0) {
- // return false;
- OutgoingFileTransfer oft = ftm.createOutgoingFileTransfer("admin@192.168.1.100/潘迪安");
- File file = new File("D://time.jpg");
- oft.sendFile(file, "图片");
- System.out.println(oft.isDone());
- }
创建多人聊天室
![](https://code.csdn.net/assets/CODE_ico.png)
- private void testCreateRoom(XMPPConnection conn) throws Exception {
- while(true) {
- if(conn != null)
- break;
- }
- //@之前的是会议房间名称。之后的是conference+ip(固定格式,不能改变)
- MultiUserChat muc = new MultiUserChat(conn, "ly@conference.192.168.1.100");
- //昵称,假设该房间已经存在,则会抛出Creation failed - Missing acknowledge of room creation.(先增加房间,然后离开房间)
- muc.create("real_admin");
- Form form = muc.getConfigurationForm();
- Form submitForm = form.createAnswerForm();
- //以下的初始化有什么用,在创建submitForm的时候已经设置參数了
- // List<FormField> list = submitForm.getFields();
- // for(FormField f : list) {
- // if(!(FormField.TYPE_HIDDEN.equals(f.getType())) && f.getVariable() != null) {
- // submitForm.setDefaultAnswer(f.getVariable());
- // }
- // }
- //參数究竟是什么意思。为什么有的能够设置,有的不能够设置
- /*
- * variable:FORM_TYPE type:hidden value:[http://jabber.org/protocol/muc#roomconfig]
- variable:muc#roomconfig_roomname type:text-single value:[]
- variable:muc#roomconfig_roomdesc type:text-single value:[]
- variable:muc#roomconfig_changesubject type:boolean value:[]
- variable:muc#roomconfig_maxusers type:list-single value:[]
- variable:muc#roomconfig_presencebroadcast type:list-multi value:[]
- variable:muc#roomconfig_publicroom type:boolean value:[]
- variable:muc#roomconfig_persistentroom type:boolean value:[]
- variable:muc#roomconfig_moderatedroom type:boolean value:[]
- variable:muc#roomconfig_membersonly type:boolean value:[]
- variable:muc#roomconfig_allowinvites type:boolean value:[]
- variable:muc#roomconfig_passwordprotectedroom type:boolean value:[]
- variable:muc#roomconfig_roomsecret type:text-private value:[]
- variable:muc#roomconfig_whois type:list-single value:[]
- variable:muc#roomconfig_enablelogging type:boolean value:[]
- variable:x-muc#roomconfig_reservednick type:boolean value:[]
- variable:x-muc#roomconfig_canchangenick type:boolean value:[]
- variable:x-muc#roomconfig_registration type:boolean value:[]
- variable:muc#roomconfig_roomadmins type:jid-multi value:[]
- variable:muc#roomconfig_roomowners type:jid-multi value:[]
- */
- //submitForm.setAnswer(FormField.TYPE_TEXT_PRIVATE, "0");
- muc.sendConfigurationForm(submitForm);
- //被拒绝时运行
- muc.addInvitationRejectionListener(new InvitationRejectionListener() {
- @Override
- public void invitationDeclined(String invitee, String reason) {
- System.out.println(invitee + " : " + reason);
- }
- });
- muc.invite("yy@192.168.1.100", "ly_room");
- }
管理房间
![](https://code.csdn.net/assets/CODE_ico.png)
- <pre name="code" class="java">private void testManageRoom(XMPPConnection conn) throws Exception {
- testCreateRoom(conn);
- MultiUserChat muc = new MultiUserChat(conn, "ly@conference.192.168.1.100");
- //Thread.sleep(5000);
- //赋予管理员权限
- //muc.grantAdmin("yy@192.168.1.100");
- //Thread.sleep(5000);
- //假设是管理员,则不能踢除
- //muc.banUser("yy@192.168.1.100", "太水");
- //收回说话的权限
- muc.revokeVoice("yy");
- //muc.grantVoice("yy");
- }
注冊
![](https://code.csdn.net/assets/CODE_ico.png)
- private void testRegister(XMPPConnection conn) throws Exception {
- //能够直接改登陆用户的信息(假设是username的值必须和该用户的用户名同样)
- Registration r = new Registration();
- Map<String, String> attributes = new HashMap<String, String>();
- attributes.put("username", "newuser");
- attributes.put("password", "0");
- attributes.put("email", "new00@126.com");
- attributes.put("name", "name@192.168.1.100");
- //加入用户,要设置type类型为set。原因不明
- r.setType(IQ.Type.SET);
- r.setAttributes(attributes);
- //过滤器,用来过滤由server返回的信息(即得到注冊信息的内容)
- PacketFilter packetFilter = new AndFilter(new PacketIDFilter(r.getPacketID()), new PacketTypeFilter(IQ.class));
- PacketCollector collector = conn.createPacketCollector(packetFilter);
- System.out.println(r);
- conn.sendPacket(r);
- IQ result = (IQ) collector.nextResult();
- if(result == null) {
- System.out.println("server没有返回不论什么信息");
- } else {
- switch (result.getType().toString()) {
- case "result":
- System.out.println("注冊成功");
- break;
- case "error":
- if(result.getError().toString().equalsIgnoreCase("conflict"))
- System.out.println("用户名称已存在");
- else
- System.out.println("注冊失败");
- break;
- default:
- break;
- }
- }
- }
管理账号password
![](https://code.csdn.net/assets/CODE_ico.png)
- private void testModifyPwd(XMPPConnection conn) throws Exception {
- //创建一个用户信息管理,能够创建新用户。或者改动用户密码
- AccountManager am = AccountManager.getInstance(conn);
- Collection<String> c = am.getAccountAttributes();
- for(String s : c) {
- System.out.println(s);
- }
- /*
- * 通过accountManager能够得到的属性
- * username
- registered
- name
- password
- */
- am.getAccountAttribute("username");
- am.createAccount("newUser", "0");
- am.changePassword("00");
- }
至于细节,中遇到,我在程序代码描述
参考博客:
http://blog.csdn.net/shimiso/article/details/11225873
smark和openfire即时通信代码相关推荐
- 对方正在输入 java_smark和openfire即时通信代码
出自:http://blog.csdn.net/casuallc/article/details/34794501 服务器:openfire 客户端程序:smark编写 首先安装openfire,下载 ...
- android-使用环信SDK开发即时通信功能及源码下载
最近项目中集成即时聊天功能,挑来拣去,最终选择环信SDK来进行开发,选择环信的主要原因是接口方便.简洁,说明文档清晰易懂.文档有android.ios.和后台服务器端,还是非常全的. 环信官网:htt ...
- 利用openfire和smark的即时通信
利用openfire和smark的即时通信 2014-06-26 09:12 3240人阅读 评论(5) 收藏 举报 分类: Android(3) 版权声明:本文为博主原创文章,未经博主允许不得转 ...
- java即时通信解决方案openfire+spark完整安装指南
本文介绍基于java的即时通信解决方案openfire3.6.4+spark2.5.8的完整的安装说明,并介绍了使用smack的java类库如何与im用户交互的例子,这样使得业务系统的消息可以通过sm ...
- 【即时通信】openfire安装和配置讲解
文章目录 概述 一.下载openfire,解压就可以openfire启动服务.这里我安装openfire在linux服务器上.服务器地址:10.119.9.149. 二.准备openfire所需的数据 ...
- iOS开发之使用XMPPFramework实现即时通信(二)
上篇的博客iOS开发之使用XMPPFramework实现即时通信(一)只是本篇的引子,本篇博客就给之前的微信加上即时通讯的功能,主要是对XMPPFramework的使用.本篇博客中用到了Spark做测 ...
- agsXMPP + Openfire 即时通讯开发(二) 【文件传输】
上篇bolg(agsXMPP + Openfire 即时通讯开发(一) [agsXMPP 连接 Openfire])中agsXMPP的MiniClient已经可以相互之间进行通讯了,本篇介绍如何进行文 ...
- 基于android即时通信聊天系统
本即时通讯毕业设计主要采用Java后台以及手机端app的体系结构,建立了关于XMPP协议的安卓app即时通信系统,本系统包含了客户端以及服务端,(即前台后台)服务器是使用OpenFire.是一个jav ...
- xmpp协议(即时通信协议规范)
转载自 https://www.cnblogs.com/jiyuqi/p/5085932.html 相关背景 IM(Instant Messaging)正在被广泛使用,特别是公司与它们的客户互动连接方 ...
最新文章
- 如何测量智能产品的AI智商水平,论AI的三种智商 |未来研究
- Paramiko: SSH and SFTP With Python
- Asp.net Core认证和授权:JWT认证和授权
- nginx 卸载后重新安装/etc/nginx配置文件没了,cannot open /etc/nginx/nginx.conf (No such file or directory)...
- C++lowest common ancestor最近公共祖先算法(附完整源码)
- 第三次学JAVA再学不好就吃翔(part80)--List三个子类的特点
- HTML5 API详解(11):Cache 应用程序缓存,这下离线也可以玩了
- fir.im同款企业级APP分发平台系统源码
- 触摸事件touchevent
- jetbrains IDEA/pycharm修改代码提示框配色
- C51单片机————串行接口
- HDU-1255 覆盖的面积 矩形面积交
- RHEL5_x64上安装oracle 11.2
- tcgames使用有延迟_心得分享:tcgames电脑玩刺激战场怎么用最流畅?
- NB-IoT未来发展,主要是靠什么驱动的?
- 贴片二极管正负极如何区分
- yarn的安装及使用教程
- 对称算法与非对称算法
- 滑铁卢大学开发了一套AI工具,教泥瓦匠初学者搬砖诀窍
- jqGrid参数整理
热门文章
- python 替换空格
- linux内核的中断上下文,Linux操作系统中中断上下文中的互斥
- uml 时序图_UML学习-14种UML图
- 恢复错误:\anaconda3\lib\site-packages\zmq\backend\cffi\__pycache__\_cffi_ext.c(266)
- 32位程序调用64位dll_电脑系统怎样区分32位和64位
- 通过python里面的pyautogui自动化控制鼠标和键盘操作
- python抽奖游戏大全_抽奖游戏
- 《STL源码剖析》学习--6章--_rotate算法分析
- VideoCapture类
- 【多线程】C++11进行多线程开发 (std::thread)