PHP.swoft 框架部分

用swoft框架做webSocket服务器 linux 环境

一、推荐用 composer 安装 swoft 框架。 这里只做概述不讲详细安装步骤
composer create-project swoft/swoft swoft安装完后进入目录
二、安装好后需要引入 WebSocket 服务
composer require swoft/websocket-server
三、 配置ws端口文件 .env
一般就在 swoft/.env 这里找到 #HTTP 部分
HTTP_PORT这个是项目运行后,监听socket端口

# HTTP
HTTP_HOST=0.0.0.0
HTTP_PORT=8188
HTTP_MODE=SWOOLE_PROCESS
HTTP_TYPE=SWOOLE_SOCK_TCP
四、创建控制器 websocket 控制器
php bin/swoft gen:websocket Camera --prefix /Camera
生成的代码一般在 swoft/app/WebSocket/xxx.php

/*** Class CameraController* @package App\WebSocket* @WebSocket("/con_camera/camera")*/
class CameraController implements HandlerInterface

注意 @WebSocket("/con_camera/camera") 这里是访问的路由需要自己改

/*** @param Server $server* @param Request $request* @param int $fd*/
public function onOpen(Server $server, Request $request, int $fd)
{$server->push($fd, '{"type":"id", "id":"'.$fd.'"}');
}/*** @param Server $server* @param Frame $frame* @return mixed*/
public function onMessage(Server $server, Frame $frame)
{// 这里是广播。 自己发出的内容,不广播给自己\Swoft::$server->sendToSome($frame->data, [], [$frame->fd]);// $server->push($frame->fd, $frame->data);
}/*** @param Server $server* @param int $fd* @return mixed*/
public function onClose(Server $server, int $fd)
{$server->close($fd);// do something. eg. record log
}

后台运行swoft项目 php bin/swoft ws:restart -d
结束用 php bin/swoft ws:stop

五、测试代码
大家可以在 function onOpen函数内 做打印

    /*** @param Server $server* @param Request $request* @param int $fd*/public function onOpen(Server $server, Request $request, int $fd){var_dump($fd,'这里是测试部分');$server->push($fd, '{"type":"id", "id":"'.$fd.'"}');}

测试方法很多,我只用 websocket 测试 谷歌浏览器

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"></head>
<body>
<script type="text/javascript">
function websocketOpen () {if ("WebSocket" in window) {alert("您的浏览器支持 WebSocket!")return false;} else {// 浏览器不支持 WebSocket123alert("您的浏览器不支持 WebSocket!");return true;}
}if(websocketOpen()){console.log('链接失败')
}let ws = new WebSocket("wss://localhost.com/con_camera/camera");ws.onopen = function (evt) {alert('连接成功')
}ws.onmessage = function (evt) {let received_msg = evt.dataconsole.log(received_msg);
}ws.onclose = function (){alert('关闭链接')
}</script>
</body>
</html>

new WebSocket(“wss://localhost.com/con_camera/camera”)
这里 wss代表服务器配置了https证书,如果服务器没有配置证书需要用 ws

以上内容是PHP部分,没有多少需要编辑的。php.swoft只做转发和广播


webRtc部分

首先需要了解WebSocket,MediaDevices,RTCPeerConnection,信令服务器作用

WebSocket

基本都知道吧,不懂的看 官方文档

WebSocket 对象提供了用于创建和管理 WebSocket 连接,以及可以通过该连接发送和接收数据的 API。

基本理解成 它是一个双向管道

浏览页面 股票服务器 管理人员 我们搭建个管道吧 ok,我一有消息就通知你 操作服务器,A股涨了30元 服务器通知:A股涨了30元 操作服务器,B股涨了20元 服务器通知:B股涨了20元 我关闭了,不用推送了 服务器关闭浏览页面 的管道不在推送 浏览页面 股票服务器 管理人员

MediaDevices 媒体设备

简单的理解成。调用媒体设备,获取 摄像头媒体设备 输入的信息 官方文档


RTCPeerConnection

简单理解成本地到远端的连接 官方文档
官方推荐引入Adapter.js保持浏览器的兼容性


信令服务器

作为webRTC中极为重要的一部分,会话管理需要建立服务器端与客户端之间的连接。
有人就问了:webRTC建立的是点对点连接,流数据是从浏览器直接传输到另一个浏览器,不需要服务器周转,怎么还需要建立服务器端与客户端连接呢?
这是个很好的问题!尽管webRTC建立的是P2P连接,但由于流数据传输需要一条信道,而这个信道则是由信令服务器提供的。而在webRTC中并没有这一过程,所以需要我们手动建立信号的传递和交涉过程。

信令服务器的实现软件有很多,我们这里用coturn官方文档

参考原文:https://blog.csdn.net/vainfanfan/article/details/82632737


我们组合一下信息

  1. 主播与客户端建立websocket通道
  2. 通过web获取流媒体MediaDevices
  3. 主播生成流媒体通道插座信息,通过websocket传输给客户,客户受到信息后设置插销信息
    与主播建立流媒体通道RTCPeerConnection。并且把主播流媒体通过流媒体通道传给客户端
  4. 这中间通过coturn信令服务器把流媒体穿透给外网,让客户端可以在外网获取

步骤很简单,但是中间遇到很多坑,我会把遇到的问题,也列出来


实现MediaDevices获取流媒体

需要的文件
jquery-3.2.1.min.js
adapter.js这个最好用迅雷下载
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><meta name="description" content="php web-rtc例子,一对一聊天-基于workerman"><meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"><meta itemprop="description" content="Video chat using the reference WebRTC application"><meta itemprop="name" content="AppRTC"><meta name="mobile-web-app-capable" content="yes"><meta id="theme-color" name="theme-color" content="#1e1e1e"><title>webRtc视频通话</title>
</head><body><div class="videos"><video id="localVideo" autoplay></video><video id="remoteVideo" autoplay class="hidden"></video>
</div><script src="jquery-3.2.1.min.js"></script>
<script src="adapter.js"></script>
<script type="text/javascript">var localVideo = document.getElementById('localVideo');var remoteVideo = document.getElementById('remoteVideo');navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;navigator.mediaDevices.getUserMedia({// audio: true,video: true}).then(function (stream) {localVideo.srcObject = stream;localStream = stream;localVideo.addEventListener('loadedmetadata', function () {console.log('视频加载成功')});}).catch(function (e) {alert(e);});
</script>
</body>
</html>


我的电脑摄像头坏了


实现链接媒体通道RTCPeerConnection 在局域网内可测试

用上面的代码修改下
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><meta name="description" content="php web-rtc例子,一对一聊天-基于workerman"><meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"><meta itemprop="description" content="Video chat using the reference WebRTC application"><meta itemprop="name" content="AppRTC"><meta name="mobile-web-app-capable" content="yes"><meta id="theme-color" name="theme-color" content="#1e1e1e"><title>webRtc视频通话</title>
</head><body><div class="videos"><video id="localVideo" autoplay></video><video id="remoteVideo" autoplay class="hidden"></video>
</div><script src="jquery-3.2.1.min.js"></script>
<script src="adapter.js"></script>
<script type="text/javascript">var localVideo = document.getElementById('localVideo');var remoteVideo = document.getElementById('remoteVideo');// 流媒体对象navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;// 流媒体通道配置var configuration = {iceTransportPolicy:"all",iceCandidatePoolSize:"0"};// 协商次数var answer = 1;/*流媒体获取
*/function openMediaSetSend() {navigator.mediaDevices.getUserMedia({// audio: true,video: true}).then(function (stream) {localVideo.srcObject = stream;localStream = stream;localVideo.addEventListener('loadedmetadata', function () {// 广播客户端 准备连接 publish('client-call', null)});}).catch(function (e) {alert(e);});}/*websocketOpen
*/function websocketOpen () {if ("WebSocket" in window) {alert("您的浏览器支持 WebSocket!")return false;} else {// 浏览器不支持 WebSocket123alert("您的浏览器不支持 WebSocket!");return true;}}if(websocketOpen()){console.log('链接失败')}let ws = new WebSocket("wss://www.cwtui.com/con_camera/camera");//发送消息function publish(event, data) {ws.send(JSON.stringify({cmd:'publish',// subject: subject, // 房间号 暂时不做这个event:event,data:data}));}ws.onopen = function (evt) {openMediaSetSend() // 广播客户端 准备连接}ws.onmessage = function(e){let package = JSON.parse(e.data)let data = package.data;switch (package.event) {case 'client-call':// 主播模块client_call();break;case 'client-answer':// 更改与连接关联的 远程描述pc.setRemoteDescription(data).then().catch(e=>{alert(e)})break;case 'client-offer':// 粉丝模块client_offer(data)break;case 'client-candidate':/*将新接收的候选服务器传递到浏览器的ICE代理服务器。值为空字符串(“”),则表示已传递所有远程候选对象(候选对象结束)在协商过程中,您的应用程序可能会收到许多候选项,您可以通过这种方式将这些候选项传递给ICE代理,从而允许它构建一个潜在连接方法的列表。*/pc.addIceCandidate(new RTCIceCandidate(data)).then().catch(e=>{alert(e)})break;}};ws.onclose = function (){alert('关闭链接')}/*流媒体通道创建
*/function icecandidate(localStream) {// 创建链接pc = new RTCPeerConnection(configuration);/**onicecandidate属性 是一个事件处理程序 当调用 RTCPeerConnection.setlocaldescription() 或将 RTCIceCandidate 添加到 RTCPeerConnection 时应将候选对象传输到 远程客户端 以便 ICE代理与远程客户端 协商 */pc.onicecandidate = event => {if (event.candidate) {publish('client-candidate', event.candidate);}}var tracks = localStream.getTracks();// 将一个媒体流 添加到一组流中,这些新流将被传输给 客户端for(const val of tracks){pc.addTrack(val, localStream);}pc.ontrack = event => {$('#remoteVideo').removeClass('hidden');$('#localVideo').remove();alert(event.streams)remoteVideo.srcObject = event.streams[0];};}// 主播 开始准备 插座 信息function client_call() {// 创建流媒体通道icecandidate(localStream);// 生成插座pc.createOffer({  // 创建一个 SDP 提供一个新的 webrtc 连接到远程节点 offerToReceiveAudio: false,offerToReceiveVideo: true}).then(function (desc) {// 更改与连接关联的本地描述 设置后 onicecandidate 协商 pc.setLocalDescription(desc).then(function () {publish('client-offer', pc.localDescription);}).catch(function (e) {alert(e);});}).catch(function (e) {alert(e);});}// 粉丝端 收到消息 开始链接function client_offer(data) {// 创建流媒体通道icecandidate(localStream);// 更改与连接关联的 远程描述pc.setRemoteDescription(data).then(function (){if (answer) {answer = 0;/*方法在WebRTC 连接的要约/答复 协商期间,为从粉丝户端接收到的要约创建一个SDP信息。答案包含关于已经附加到会话的任何媒体、浏览器支持的编解码器和选项以及已经收集到的ICE候选项的信息。答案是交付给返回的承诺,然后应该发送到报价源继续谈判过程。*/return pc.createAnswer();}return false;}).then( desc => {if(desc !== false){// 更改与连接关联的本地描述 设置后 onicecandidate 协商 createAnswerpc.setLocalDescription(desc).then(function (){publish('client-answer', pc.localDescription);})}}).catch( e => {alert(e)})}</script>
</body>
</html>

主播页面和粉丝页面不同的地方
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><meta name="description" content="php web-rtc例子,一对一聊天-基于workerman"><meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"><meta itemprop="description" content="Video chat using the reference WebRTC application"><meta itemprop="name" content="AppRTC"><meta name="mobile-web-app-capable" content="yes"><meta id="theme-color" name="theme-color" content="#1e1e1e"><title>webRtc主播</title>
</head><body><div class="videos"><video id="localVideo" autoplay></video><video id="remoteVideo" autoplay class="hidden"></video>
</div><script src="jquery-3.2.1.min.js"></script>
<script src="adapter.js"></script>
<script type="text/javascript">var localVideo = document.getElementById('localVideo');var remoteVideo = document.getElementById('remoteVideo');// 流媒体对象navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;// 流媒体通道配置var configuration = {iceTransportPolicy:"all",iceCandidatePoolSize:"0"};// 协商次数var answer = 1;/*流媒体获取
*/function openMediaSetSend() {navigator.mediaDevices.getUserMedia({// audio: true,video: true}).then(function (stream) {localVideo.srcObject = stream;localStream = stream;localVideo.addEventListener('loadedmetadata', function () {// 广播客户端 准备连接 publish('client-call', null)});}).catch(function (e) {alert(e);});}/*websocketOpen
*/function websocketOpen () {if ("WebSocket" in window) {alert("您的浏览器支持 WebSocket!")return false;} else {// 浏览器不支持 WebSocket123alert("您的浏览器不支持 WebSocket!");return true;}}if(websocketOpen()){console.log('链接失败')}let ws = new WebSocket("wss://www.cwtui.com/con_camera/camera");//发送消息function publish(event, data) {ws.send(JSON.stringify({cmd:'publish',// subject: subject, // 房间号 暂时不做这个event:event,data:data}));}ws.onopen = function (evt) {openMediaSetSend() // 广播客户端 准备连接}ws.onmessage = function(e){let package = JSON.parse(e.data)let data = package.data;switch (package.event) {case 'client-call':// 主播模块client_call();break;case 'client-answer':// 更改与连接关联的 远程描述pc.setRemoteDescription(data).then().catch(e=>{alert(e)})break;}};ws.onclose = function (){alert('关闭链接')}/*流媒体通道创建
*/function icecandidate(localStream) {// 创建链接pc = new RTCPeerConnection(configuration);/**onicecandidate属性 是一个事件处理程序 当调用 RTCPeerConnection.setlocaldescription() 或将 RTCIceCandidate 添加到 RTCPeerConnection 时应将候选对象传输到 远程客户端 以便 ICE代理与远程客户端 协商 */pc.onicecandidate = event => {if (event.candidate) {publish('client-candidate', event.candidate);}}var tracks = localStream.getTracks();// 将一个媒体流 添加到一组流中,这些新流将被传输给 客户端for(const val of tracks){pc.addTrack(val, localStream);}pc.ontrack = event => {$('#remoteVideo').removeClass('hidden');$('#localVideo').remove();// alert(event.streams)remoteVideo.srcObject = event.streams[0];};}// 主播 开始准备 插座 信息function client_call() {// 创建流媒体通道icecandidate(localStream);// 生成插座pc.createOffer({  // 创建一个 SDP 提供一个新的 webrtc 连接到远程节点 offerToReceiveAudio: false,offerToReceiveVideo: true}).then(function (desc) {// 更改与连接关联的本地描述 设置后 onicecandidate 协商 pc.setLocalDescription(desc).then(function () {publish('client-offer', pc.localDescription);}).catch(function (e) {alert(e);});}).catch(function (e) {alert(e);});}</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><meta name="description" content="php web-rtc例子,一对一聊天-基于workerman"><meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"><meta itemprop="description" content="Video chat using the reference WebRTC application"><meta itemprop="name" content="AppRTC"><meta name="mobile-web-app-capable" content="yes"><meta id="theme-color" name="theme-color" content="#1e1e1e"><title>webRtc粉丝</title>
</head><body><div class="videos"><video id="localVideo" autoplay></video><video id="remoteVideo" autoplay class="hidden"></video>
</div><script src="jquery-3.2.1.min.js"></script>
<script src="adapter.js"></script>
<script type="text/javascript">var localVideo = document.getElementById('localVideo');var remoteVideo = document.getElementById('remoteVideo');// 流媒体对象navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;// 流媒体通道配置var configuration = {iceTransportPolicy:"all",iceCandidatePoolSize:"0"};// 协商次数var answer = 1;/*websocketOpen
*/function websocketOpen () {if ("WebSocket" in window) {alert("您的浏览器支持 WebSocket!")return false;} else {// 浏览器不支持 WebSocket123alert("您的浏览器不支持 WebSocket!");return true;}}if(websocketOpen()){console.log('链接失败')}let ws = new WebSocket("wss://www.cwtui.com/con_camera/camera");//发送消息function publish(event, data) {ws.send(JSON.stringify({cmd:'publish',// subject: subject, // 房间号 暂时不做这个event:event,data:data}));}ws.onopen = function (evt) {publish('client-call', null) // 广播客户端 准备连接}ws.onmessage = function(e){let package = JSON.parse(e.data)let data = package.data;switch (package.event) {case 'client-offer':// 粉丝模块if(answer){client_offer(data)}break;case 'client-candidate':/*将新接收的候选服务器传递到浏览器的ICE代理服务器。值为空字符串(“”),则表示已传递所有远程候选对象(候选对象结束)在协商过程中,您的应用程序可能会收到许多候选项,您可以通过这种方式将这些候选项传递给ICE代理,从而允许它构建一个潜在连接方法的列表。*/pc.addIceCandidate(new RTCIceCandidate(data)).then().catch(e=>{alert(e)})break;}};ws.onclose = function (){alert('关闭链接')}/*流媒体通道创建
*/function icecandidate() {// 创建链接pc = new RTCPeerConnection(configuration);/**onicecandidate属性 是一个事件处理程序 当调用 RTCPeerConnection.setlocaldescription() 或将 RTCIceCandidate 添加到 RTCPeerConnection 时应将候选对象传输到 远程客户端 以便 ICE代理与远程客户端 协商 */pc.ontrack = event => {$('#remoteVideo').removeClass('hidden');$('#localVideo').remove();// alert(event.streams)remoteVideo.srcObject = event.streams[0];};}// 粉丝端 收到消息 开始链接function client_offer(data) {// 创建流媒体通道icecandidate();// 更改与连接关联的 远程描述pc.setRemoteDescription(data).then(function (){answer = 0;/*方法在WebRTC 连接的要约/答复 协商期间,为从粉丝户端接收到的要约创建一个SDP信息。答案包含关于已经附加到会话的任何媒体、浏览器支持的编解码器和选项以及已经收集到的ICE候选项的信息。答案是交付给返回的承诺,然后应该发送到报价源继续谈判过程。*/return pc.createAnswer();}).then( desc => {if(desc !== false){// // 更改与连接关联的 远程描述pc.setLocalDescription(desc).then(function (){publish('client-answer', pc.localDescription);})}}).catch( e => {alert(e)})}</script>
</body>
</html>
区别
主播不需要 与粉丝端建立握手机制 client-candidate
不需要 client-candidate 添加 ICE代理服务器连接方法的列表
粉丝端需要只有一次创建 流媒体通道
粉丝端,不需要获取媒体流
粉丝端,不需要与远程端协商

接下来需要配置信令服务器,打通内外网的差异

配置一下页面的信令服务器

改下上面的代码
var configuration = {iceServers:[{urls:["turn:www.cwtui.com:3478"], //地址username:"hu", // 账号credential:"123456" // 密码}],iceTransportPolicy:"all",iceCandidatePoolSize:"0"
};

重点注意下 turn 协议和 stun 这两个协议 我们配置的协议是turn

安装信令服务器与配置

coturn 下载页面

cd coturn
./configure
make
sudo make install

查看是否安装成功
使用命令:which turnserver

我的配置

listening-port=3478
tls-listening-port=5349
listening-ip=172.17.142.214 // 内网ip
relay-device=eth0
relay-ip=172.17.142.214 // 内网ip
external-ip=47.94.228.114/172.17.142.214 // 外网ip/内网ip
relay-threads=5
min-port=49152
max-port=65535
fingerprint
lt-cred-mech
user=hu:123456
realm=www.cwtui.com
cert=/etc/turn_server_cert.pem
pkey=/etc/turn_server_pkey.pem
pidfile="/var/run/turnserver.pid"
cli-password=qwerty

参考原文: https://www.pressc.cn/967.html
参考原文: https://blog.csdn.net/bvngh3247/article/details/80742396

启动命令
turnserver -a -f -v -r www.cwtui.com
turnserver -a -f --user=hu:123456 -v -r www.cwtui.com
启动参数解析
-a 长期验证机制
-o 如果指定 -o 则后台运行
-f 使用指纹
-v
-r realm组别
–user 指定账户运行

参考原文:https://www.cnblogs.com/mobilecard/p/6542294.html

希望朋友给点个赞~~~~ 谢谢大家看到这里

利用Swoft实现PHP+websocket直播,即时通讯代码相关推荐

  1. springboot框架下利用websocket实现即时通讯

    springboot框架下利用websocket实现即时通讯(文章末尾有git项目打包文件,直接下载使用即可) 用websocket实现简单的在线聊天,先画个时序图,直观感受下流程 SystemCon ...

  2. SpringCloud工作笔记060---SpringBoot中使用WebSocket实现即时通讯_实现呼叫中心业务封装

    JAVA技术交流QQ群:170933152 ---------------我们主要用这个来转接,呼叫中心发过来的分机电话 呼叫中心:呼叫过程,首先呼叫中心运营商给个,api手册,api会规定,首先登陆 ...

  3. 基于springboot+h5+websocket的即时通讯客服系统和百度实时语音转译(语音在线识别)

    本文章由本人原创 下载链接:https://download.csdn.net/download/u014191624/51948075 这是一个基于springboot+h5+websocket的即 ...

  4. 一对一语聊直播源码视频交友系统,一对一直播即时通讯IM产品。

    一对一语聊直播源码视频交友系统,一对一直播即时通讯IM产品. 匹配聊天 开启速度匹配,匹配逻辑异性匹配.原始码,回调,API和SDK等接口调用正常双端经过测试完美正常跑通! 纯原生开发 开发语言 后端 ...

  5. Java聊天室程序源码 Java即时通讯代码 Java局域网聊天系统 Java即时通讯 Java聊天系统

    Java聊天室程序源码 Java即时通讯代码 Java局域网聊天系统  Java即时通讯 Java聊天系统 public Swingtest002() {// 设置标题setTitle("请 ...

  6. Websocket实现即时通讯

    前言 关于我和WebSocket的缘:我从大二在计算机网络课上听老师讲过之后,第一次使用就到了毕业之后的第一份工作.直到最近换了工作,到了一家是含有IM社交聊天功能的app的时候,我觉得我现在可以谈谈 ...

  7. java node websocket_nodejs怎么实现webSocket接口即时通讯服务?

    websocket 工作方式:广播和收听 # 使用场景:金融/聊天室/-- websocket:服务器支持广泛(node/java/php/c#--) 原生API操作复杂 可以使用第三方模块:sock ...

  8. 私有化部署|短视频|带直播|即时通讯|IM|聊天app|支持二开丨视频会议丨支付红包

    1.私聊.群聊 2.网页导航:镶嵌所需网址: 3.短视频.视频会议.视频直播. 4.附近人.公众号 5.多消息类型:文字表情.语音.图片视频.名片.文件等 6.消息功能:已读通知.撤回.删除.复制.转 ...

  9. Springboot集成WebSocket实现即时通讯

    在SpringBoot的pom.xml文件里添加依赖: <!-- websocket --> <dependency><groupId>org.springfram ...

最新文章

  1. DL之MobileNetV2:MobileNetV2算法的架构详解(包括ReLu的意义)
  2. Citrix Netscaler负载均衡算法
  3. 多层陶瓷电容器用处_【科普】片状多层陶瓷电容器的封装方法,你了解吗?
  4. Sublime Text for Mac 最新版安装后,无法搜索到Install Package的解决办法
  5. 2021汉语言文学对高考成绩查询,2021汉语言文学专业就业前景怎么样
  6. 【Java】为什么java构造函数的构造器只能在第一行写this() 或者super() ?
  7. .NET Windows编程系列笔记(一)
  8. IOS开发UI控件UIScrollView和Delegate的使用
  9. 1 Hello World,JavaFX Style
  10. JavaScript ECMAScript版本介绍
  11. acm常见错误-持续更新
  12. 再论:男人有多大责任和感恩代表着有多大的驾驭能力和事业能力
  13. 计算机word设置信纸,一分钟教你学会用Word做信纸和公章!
  14. free pascal语言学习笔记(一)
  15. (dfs)[USACO3.4]“破锣摇滚”乐队 Raucous Rockers
  16. js区号插件(全国电话区号)
  17. 一篇就明白什么是H3C?
  18. Linux用户态与内核态通信的几种方式(待完善)
  19. 《华尔街》观后笔记7——阳光交易
  20. Java内存相关的常用命令

热门文章

  1. OTT TV系统你最关心的几个问题都在这
  2. 环信即时通讯IM重大更新助力企业数字化转型
  3. 【PHP】实现搜索引擎中把搜索结果命中的关键字标记红色
  4. Mac新手必看教程—轻松玩转Mac OS
  5. 智慧能源物联网云平台方案
  6. 蓝牙UART和PCM接口传输的信号 硬件接口
  7. linux下r232转usb驱动,R232转usb驱动
  8. RS232不能通信的问题
  9. 学校无盘服务器配置,学校无盘服务器配置
  10. 在IDEA中使用搜狗输入法输入文字是繁体字,但是在其他地方输入文字是正常的简体字