- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
在 Web 开发方面,我是初学者。最近我一直在开发一个完全基于 PHP 和 JS/jQuery 的实时聊天网站(我没有使用任何框架)。目前,我的设置只是简单的 AJAX 轮询,这显然不如我希望的那样好。我的数据库是 MYSQL 数据库。
我已经阅读了有关 websockets 的内容,我的新初始计划是使用 Socket.io 创建一个 NodeJS 服务器来处理消息 (How to integrate nodeJS + Socket.IO and PHP?),我考虑将这些消息存储在 MySQL 数据库中 (MySQL with Node.js)。
这是我目前拥有的(不多,我想在我真正取得进步之前澄清如何进步)。这是我的测试设置,实际聊天中使用的 HTML 显然有点不同。
Node.js 服务器:
// NODE
var socket = require( 'socket.io' );
var express = require( 'express' );
var https = require( 'https' );
var http = require( 'http'); //Old
var fs = require( 'fs' );
var app = express();
//Working HTTPS server
var server = https.createServer({
key: fs.readFileSync('/etc/letsencrypt/live/%site%/privkey.pem'),
cert: fs.readFileSync('/etc/letsencrypt/live/%site%/fullchain.pem')
},app);
// var server = https.createServer( app ); Won't work cause no cert.
var io = socket.listen( server );
console.log("Server Started");
io.sockets.on( 'connection', function( client ) {
console.log( "New client !" );
client.on( 'message', function( data ) {
console.log( 'Message received ' + data); //Logs recieved data
io.sockets.emit( 'message', data); //Emits recieved data to client.
});
});
server.listen(8080, function() {
console.log('Listening');
});
JS 客户端脚本:
var socket = io.connect('https://%site%:8080');
document.getElementById("sbmt").onclick = function () {
socket.emit('message', "My Name is: " + document.getElementById('nameInput').value + " i say: " + document.getElementById('messageInput').value);
};
socket.on( 'message', function( data ) {
alert(data);
});
我 super 简单的测试 HTML:
<form id="messageForm">
<input type="text" id="nameInput"></input>
<input type="text" id="messageInput"></input>
<button type="button" id="sbmt">Submits</button>
</form>
PHP 需要一些解释 - 当有人连接到我的网站时,我运行 session_start()
。这是因为我想要匿名 session 之类的东西。我通过 $_SESSION
变量区分登录用户和匿名用户。 anon 用户会将 $_SESSION['anon']
设置为 true,并且不会将 $_SESSION['username']
设置。登录用户显然会将其倒置。
谈到聊天 - 登录用户和匿名用户都可以使用它。当用户是匿名用户时,会从数据库或随机名称中生成一个随机用户名。当用户登录时,会选择他自己的用户名。现在我的 Ajax 轮询系统是这样工作的:
用户输入消息(在当前的聊天解决方案中,而不是我上面发送的测试 HTML)并按下回车键,然后对以下函数进行 AJAX 调用:
function sendMessage($msg, $col) {
GLOBAL $db;
$un = "";
if (!isset($_SESSION['username'])) {
$un = self::generateRandomUsername();
} else {
$un = $_SESSION['username'];
}
try {
$stmt = $db->prepare('INSERT INTO chat (id, username, timestamp, message, color) VALUES (null, :un, NOW(), :msg, :col)');
$stmt->bindParam(':un', $un, PDO::PARAM_STR);
$stmt->bindValue(':msg', strip_tags(stripslashes($msg)), PDO::PARAM_STR); //Stripslashes cuz it saved \\\ to the DB before quotes, strip_tags to prevent malicious scripts. TODO: Whitelist some tags.
$stmt->bindParam(':col', $col, PDO::PARAM_STR);
} catch (Exception $e) {
var_dump($e->getMessage());
}
$stmt->execute();
}
(请不要讨厌我的糟糕代码和蹩脚的异常处理,这不是任何官方项目)。此函数将用户消息输入数据库。
为了接收新消息,我使用 JS 的 setTimeout()
函数,在收到新消息后每 1 秒运行一次 AJAX 检查。我保存在 JS 中显示的最后一条消息的 ID,并将该 ID 作为参数发送到此 PHP 函数(它每 1 秒运行一次):
/* Recieve new messages, ran every 1s by Ajax call */
function recieveMessage($msgid) {
//msgid is latest msg id in this case
GLOBAL $db;
$stmt = $db->prepare('SELECT * FROM chat WHERE id > :id');
$stmt->bindParam(':id', $msgid, PDO::PARAM_INT);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
return json_encode($result);
}
问题是:如何实现类似的东西,但使用我之前提到的 node.js 服务器和 websockets 设置?我需要以某种方式区分登录用户和匿名用户。我的第一个想法是只运行从 node.js 服务器到 PHP 的 ajax 调用并传递消息数据,然后 PHP 会像现在一样将它插入到 DB 中。但是这种情况下的问题是如何将消息再次发送给客户端?在将消息输入数据库时应用用户名,这意味着我必须调用 AJAX 来保存到数据库,然后调用另一个 AJAX 来提取新输入的消息并将其发送给客户端,或者创建一个函数插入和提取并返回提取的消息。但是,如果同时输入 2 条消息,这不会引起问题吗?
是否可以通过某种方式在 Node.js 中访问 PHP session 变量?然后我可以重写所有数据库查询以在 Node.js 服务器而不是 PHP 中工作。
如果我的代码或解释困惑,我再次道歉。
最佳答案
所以,对于所有想知道并在未来会找到这个线程的人:我没有找到我想使用的解决方案的答案,但是我想出了其他的东西,这里是一个描述:
我没有让 Node.js 服务器发送 AJAX 请求,而是像以前一样将它从客户端发送到 PHP 函数的 jQuery $.post() 请求。
我接下来要做的是实现一个 MySQL 监听器,它检查 MySQL binlog 是否有更改。我用了 mysql-events
模块。它检索新添加的包含所有数据的行,然后使用 socket.io emit 函数将其发送到连接的客户端。我还不得不放弃 SSL,因为它显然讨厌我。这是一个小型的业余爱好项目,所以我真的不必为 SSL 操心。
最好的解决方案显然是在 Node.js 中对整个网络服务器进行编程,然后完全放弃 Apache。 Node.js 非常适合实时应用程序,它是一种非常容易学习和使用的语言。
我对 Node.js + Socket.io + mysql-events 的设置:(忽略未使用的要求)
// NODE
var socket = require( 'socket.io' );
var express = require( 'express' );
var https = require( 'https' );
var http = require( 'http');
var fs = require( 'fs' );
var request = require( 'request' );
var qs = require( 'qs' );
var MySQLEvents = require('mysql-events');
var app = express();
/*Correct way of supplying certificates.
var server = https.createServer({
key: fs.readFileSync('/etc/letsencrypt/live/x/privkey.pem'),
cert: fs.readFileSync('/etc/letsencrypt/live/x/cert.pem'),
ca: fs.readFileSync('/etc/letsencrypt/live/x/chain.pem')
},app); */
var server = http.createServer( app ); // Won't work without cert.
var io = socket.listen( server );
console.log("Server Started");
//DB credentials
var dsn = {
host: 'x',
user: 'x',
password: 'x',
};
var mysqlEventWatcher = MySQLEvents(dsn);
//Watcher magic, waits for mysql events.
var watcher = mysqlEventWatcher.add(
'newage_db.chat',
function (oldRow, newRow, event) {
//row inserted
if (oldRow === null) {
//insert code goes here
var res = JSON.stringify(newRow.fields); //Gets only the newly inserted row data
res.charset = 'utf-8'; //Not sure if needed but i had some charset trouble so i'm leaving this.
console.log("Row has updated " + res);
io.sockets.emit('message', "[" + res + "]"); //Emits to all clients. Square brackets because it's not a complete JSON array w/o them, and that's what i need.
}
//row deleted
if (newRow === null) {
//delete code goes here
}
//row updated
if (oldRow !== null && newRow !== null) {
//update code goes here
}
//detailed event information
//console.log(event)
});
io.sockets.on( 'connection', function( client ) {
console.log( "New client !" );
client.on( 'message', function( data ) {
//PHP Handles DB insertion with POST requests as it used to.
});
});
server.listen(8080, function() {
console.log('Listening');
});
客户端 JavaScript 发送消息:
$('#txtArea').keypress(function (e) {
if (e.which == 13 && ! e.shiftKey) {
var emptyValue = $('#txtArea').val();
if (!emptyValue.replace(/\s/g, '').length) { /*Do nothing, only spaces*/ }
else {
$.post("/shana/?p=execPOST", $("#msgTextarea").serialize(), function(data) {
});
}
$('#txtArea').val('');
e.preventDefault();
}
});
客户端 JavaScript 接收消息:
socket.on( 'message', function( data ) {
var obj = JSON.parse(data);
obj.forEach(function(ob) {
//Execute appends
var timestamp = ob.timestamp.replace('T', ' ').replace('.000Z', '');
$('#messages').append("<div class='msgdiv'><span class='spn1'>"+ob.username+"</span><span class='spn2'style='float: right;'>"+timestamp+"</span><div class='txtmsg'>"+ob.message+"</div>");
$('#messages').append("<div class='dashed-line'>- - - - - - - - - - - - - - - - - - - - - - - - - - -</div>"); //ADD SCROLL TO BOTTOM
$("#messages").animate({ scrollTop: $('#messages').prop("scrollHeight")}, 1000);
});
});
不知何故,二进制日志魔法破坏了时间戳字符串,所以为了清理它我不得不替换字符串本身的一部分。
PHP 数据库插入函数:
function sendMessage($msg, $col) {
GLOBAL $db;
$un = "";
if (!isset($_SESSION['username'])) {
$un = self::generateRandomUsername();
} else {
$un = $_SESSION['username'];
}
try {
$stmt = $db->prepare('INSERT INTO chat (id, username, timestamp, message, color) VALUES (null, :un, NOW(), :msg, :col)');
$stmt->bindParam(':un', $un, PDO::PARAM_STR);
$stmt->bindValue(':msg', strip_tags(stripslashes($msg)), PDO::PARAM_LOB); //Stripslashes cuz it saved \\\ to the DB before quotes, strip_tags to prevent malicious scripts. TODO: Whitelist some tags.
$stmt->bindParam(':col', $col, PDO::PARAM_STR);
} catch (Exception $e) {
var_dump($e->getMessage());
}
$stmt->execute();
}
我希望这至少能对某人有所帮助。请随意使用此代码,因为我可能已经从互联网上复制了大部分代码:) 我会不时检查此线程,所以如果您有任何问题,请发表评论。
关于php - 实时聊天、消息处理 - Socket.io、PHP、MySQL、Apache,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45348866/
基于 socket.io 的官方网站 http://socket.io/#how-to-use , 我找不到任何术语。socket.emit 、 socket.on 和 socket.send 之间有
我正在使用 lua-socket 3.0rc1.3(Ubuntu Trusty 附带)和 lua 5.1。我正在尝试监听 unix 域套接字,我能找到的唯一示例代码是 this -- send std
这两者有什么区别? 我注意到如果我在一个工作程序中从 socket.emit 更改为 socket.send ,服务器无法接收到消息,虽然我不明白为什么。 我还注意到,在我的程序中,如果我从 sock
使用套接字在两台服务器之间发送数据是个好主意,还是应该使用 MQ 之类的东西来移动数据。 我的问题:套接字是否可靠,如果我只需要一次/有保证的数据传输? 还有其他解决方案吗? 谢谢。 最佳答案 套接字
引自 this socket tutorial : Sockets come in two primary flavors. An active socket is connected to a
我已经安装了在端口81上运行的流服务器“Lighttpd”(light-tpd)。 我有一个C程序,它使用套接字api创建的服务器套接字在端口80上监听http请求。 我希望从客户端收到端口80上的请
这是我正在尝试做的事情: 当有新消息可用时,服务器会将消息发送给已连接的客户端。另一方面,客户端在连接时尝试使用send()向服务器发送消息,然后使用recv()接收消息,此后,客户端调用close(
如何将消息发送到动态 session 室,以及当服务器收到该消息时,如何将该消息发送到其他成员所在的同一个 session 室? table_id是房间,它将动态设置。 客户: var table_i
这是我尝试但不起作用的方法。我可以将传入的消息从WebSocket连接转发到NetSocket,但是只有NetSocket收到的第一个消息才到达WebSocket后面的客户端。 const WebSo
我正在实现使用boost将xml发送到客户端的服务器。我面临的问题是缓冲区不会立即发送并累积到一个点,然后发送整个内容。这在我的客户端造成了一个问题,当它解析xml时,它可能具有不完整的xml标记(不
尝试使用Nginx代理Gunicorn套接字。 /etc/systemd/system/gunicorn.service文件 [Unit] Description=gunicorn daemon Af
我正在使用Lua套接字和TCP制作像聊天客户端和服务器这样的IRC。我要弄清楚的主要事情是如何使客户端和服务器监听消息并同时发送它们。由于在服务器上执行socket:accept()时,它将暂停程序,
我看了一下ZMQ PUSH/PULL套接字,尽管我非常喜欢简单性(特别是与我现在正在通过UDP套接字在系统中实现的自定义碎片/ack相比),但我还是希望有自定义负载平衡功能,而不是幼稚的回合-robi
我正在编写一个应用程序,其中有多个 socket.io 自定义事件,并且所有工作正常,除了这个: socket.on("incomingImg", function(data) {
在我的应用程序中,我向服务器发送了两条小消息(类似 memcached 的服务)。在类似 Python 的伪代码中,这看起来像: sock.send("add some-key 0") ignored
很抱歉再次发布此问题,但大多数相关帖子都没有回答我的问题。我在使用 socket.io 的多个连接时遇到问题我没有使用“socket.socket.connect”方法,但我从第一次连接中得到了反馈。
我尝试使用 socket.io 客户端连接到非 socket.io websocket 服务器。但我做不到。我正在尝试像这样连接到套接字服务器: var socket = io.connect('ws
我遇到了一个奇怪的问题。在我非常基本的服务器中,我有: server.listen(8001); io.listen(server); var sockets = io.sockets; 不幸的是,套
我正在使用带套接字 io 的sailsjs。帆的版本是 0.10.5。我有以下套接字客户端进行测试: var socketIOClient = require('socket.io-client');
这个问题在这里已经有了答案: What is the fundamental difference between WebSockets and pure TCP? (4 个答案) 关闭 4 年前。
我是一名优秀的程序员,十分优秀!