Maison  >  Article  >  Tutoriel CMS  >  Chat en temps réel à l'aide de Readline et Socket.io pour Node.js

Chat en temps réel à l'aide de Readline et Socket.io pour Node.js

WBOY
WBOYoriginal
2023-08-31 18:09:071259parcourir

Chat en temps réel à laide de Readline et Socket.io pour Node.js

Node.js possède un module sous-estimé, mais très utile dans sa bibliothèque standard. Le module Readline fait ce qu'il dit sur la boîte : lit une ligne d'entrée depuis le terminal. Cela peut être utilisé pour poser une ou deux questions à l'utilisateur ou créer une invite en bas de l'écran. Dans ce didacticiel, je vais démontrer les capacités de Readline et créer une salle de discussion CLI en direct alimentée par Socket.io. Non seulement les clients peuvent envoyer des messages simples, mais ils peuvent également utiliser /me 发送表情命令,使用 /msg 发送私人消息,并允许使用 /nick.

Un peu sur Readline

C'est probablement l'utilisation la plus simple de Readline :

var readline = require('readline');

var rl = readline.createInterface(process.stdin, process.stdout);

rl.question("What is your name? ", function(answer) {
	console.log("Hello, " + answer );
	rl.close();
});

Nous incluons ce module pour créer une interface Readline utilisant des flux d'entrée et de sortie standard, puis posons à l'utilisateur une question ponctuelle. C’est la première utilisation de Readline : poser des questions. Si vous avez besoin de confirmer quelque chose avec l'utilisateur, probablement sous la forme populaire « Voulez-vous faire cela ? (o/n) », qui est omniprésente dans les outils CLI, readline.question () est la façon de le faire.

Une autre fonctionnalité fournie par Readline concerne les invites, qui peuvent être personnalisées avec leurs caractères par défaut ">" et temporairement mises en pause pour empêcher la saisie. Pour notre client de chat Readline, ce sera notre interface principale. Apparaîtra une fois readline.question() 来询问用户昵称,但其他所有内容都将是 readline.prompt().

Gérez vos dépendances

Commençons par la partie ennuyeuse : les dépendances. Le projet utilisera socket.iosocket.io-client 包和 ansi-color。您的 packages.json Le fichier devrait ressembler à ceci :

{
    "name": "ReadlineChatExample",
	"version": "1.0.0",
	"description": "CLI chat with readline and socket.io",
	"author": "Matt Harzewski",
	"dependencies": {
		"socket.io": "latest",
		"socket.io-client": "latest",
		"ansi-color": "latest"
	},
	"private": true
}

Courez npm install et c'est tout.

Serveur

Dans ce tutoriel, nous utiliserons un serveur Socket.io très simple. Il n’y a rien de plus basique que ceci :

var socketio = require('socket.io');

// Listen on port 3636
var io = socketio.listen(3636);

io.sockets.on('connection', function (socket) {

    // Broadcast a user's message to everyone else in the room
	socket.on('send', function (data) {
		io.sockets.emit('message', data);
    });

});

Tout ce qu'il fait, c'est recevoir les messages entrants d'un client et les transmettre à tous les autres. Pour les applications à plus grande échelle, le serveur peut être plus robuste, mais pour cet exemple simple, cela devrait suffire.

Cela doit être enregistré dans le répertoire du projet sous le nom server.js.

Client : inclut et paramètres

Avant de passer à la partie amusante, nous devons inclure nos dépendances, définir certaines variables et démarrer l'interface Readline et la connexion socket.

var readline = require('readline'),
socketio = require('socket.io-client'),
util = require('util'),
color = require("ansi-color").set;


var nick;
var socket = socketio.connect('localhost', { port: 3636 });
var rl = readline.createInterface(process.stdin, process.stdout);

À ce stade, le code est presque explicite. Nous avons déjà la variable pseudo, la connexion socket (via le package socket.io-client) et l'interface Readline.

Dans cet exemple, Socket.io se connectera à localhost via le port 3636, bien sûr, si vous créez une application de chat de production, cela changera pour le domaine et le port de votre propre serveur. (Cela ne sert à rien de discuter avec vous-même !)

Client : demandez le nom d'utilisateur

Maintenant, nous utilisons Readline pour la première fois ! Nous souhaitons demander à l'utilisateur un pseudo de son choix, qui l'identifiera dans le salon de discussion. Pour ce faire, nous utiliserons la méthode question() de Readline.

// Set the username
rl.question("Please enter a nickname: ", function(name) {
    nick = name;
	var msg = nick + " has joined the chat";
	socket.emit('send', { type: 'notice', message: msg });
	rl.prompt(true);
});

Nous définissons la variable de pseudo précédente sur la valeur collectée auprès de l'utilisateur, envoyons un message au serveur (qui sera transmis aux autres clients) indiquant que notre utilisateur a rejoint le chat, puis remettons l'interface Readline en mode invite. Passer la valeur prompt()true garantit que l'invite s'affiche correctement. (Sinon, le curseur risque de se déplacer à la position zéro de la ligne et ">" ne sera pas affiché.)

Malheureusement, Readline a des problèmes frustrants avec la méthode prompt(). Cela ne fonctionne pas bien avec console.log(), qui affiche le texte sur la même ligne que le caractère d'invite, laissant des caractères "prompt() 方法方面存在令人沮丧的问题。它与 console.log() 配合得不太好,它会将文本输出到与提示字符相同的行,从而在各处留下杂散的“>”字符和其他字符怪异。为了解决这个问题,我们不会在此应用程序中的任何位置使用 console.log> partout

" parasites et d'autres caractères. personnages bizarres. Pour résoudre ce problème, nous n'utiliserons console.log nulle part dans cette application, sauf à un seul endroit. Au lieu de cela, le résultat doit être transmis à cette fonction :

function console_out(msg) {
    process.stdout.clearLine();
	process.stdout.cursorTo(0);
	console.log(msg);
	rl.prompt(true);
}
Cette solution légèrement

hackée garantit que la ligne actuelle dans la console est vide et que le curseur est en position zéro avant d'imprimer la sortie. Ensuite, il demande explicitement d'afficher à nouveau l'invite.

console_out() 而不是 console.log()Donc pour la suite de ce tutoriel, vous verrez

.

Client : gérer les entrées

Les utilisateurs peuvent saisir deux types de saisie : le chat et les commandes. Nous savons que la commande est précédée d'une barre oblique, il est donc facile de faire la différence entre les deux.

🎜

Readline 有几个事件处理程序,但最重要的无疑是 line。每当在输入流中检测到换行符(通过 return 或 Enter 键)时,就会触发此事件。因此,我们需要为我们的输入处理程序挂钩 line

rl.on('line', function (line) {
    if (line[0] == "/" && line.length > 1) {
		var cmd = line.match(/[a-z]+\b/)[0];
		var arg = line.substr(cmd.length+2, line.length);
		chat_command(cmd, arg);

	} else {
		// send chat message
		socket.emit('send', { type: 'chat', message: line, nick: nick });
		rl.prompt(true);
	}
});

如果输入行的第一个字符是斜杠,我们就知道这是一个命令,这将需要更多的处理。否则,我们只是发送常规聊天消息并重置提示。请注意此处通过套接字发送的数据与上一步中的加入消息之间的差异。它使用不同的 type,因此接收客户端知道如何格式化消息,并且我们还传递 nick 变量。

命令名称(cmd)和后面的文本(arg)用一些正则表达式和子字符串魔术隔离,然后我们将它们传递给处理函数命令。

function chat_command(cmd, arg) {
    switch (cmd) {

		case 'nick':
			var notice = nick + " changed their name to " + arg;
			nick = arg;
			socket.emit('send', { type: 'notice', message: notice });
			break;

		case 'msg':
			var to = arg.match(/[a-z]+\b/)[0];
			var message = arg.substr(to.length, arg.length);
			socket.emit('send', { type: 'tell', message: message, to: to, from: nick });
			break;

		case 'me':
			var emote = nick + " " + arg;
			socket.emit('send', { type: 'emote', message: emote });
			break;

		default:
			console_out("That is not a valid command.");

	}
}

如果用户输入 /nick gollum,则 nick 变量将重置为 gollum,它可能是 smeagol 之前,并将通知推送到服务器。

如果用户输入 /msg bilbo 珍贵在哪里?,使用相同的正则表达式来分隔接收者和消息,然后是一个类型为 tell 被推送到服务器。这将与普通消息的显示方式略有不同,并且其他用户不应该看到。诚然,我们过于简单的服务器会盲目地将消息推送给每个人,但客户端会忽略未发送到正确昵称的通知。更强大的服务器可以更加离散。

表情命令的使用形式为/我正在吃第二顿早餐。昵称以任何使用过 IRC 或玩过多人角色扮演游戏的人都应该熟悉的方式添加到表情符号中,然后将其推送到服务器。

客户端:处理传入消息

现在客户端需要一种接收消息的方法。我们需要做的就是挂钩 Socket.io 客户端的 message 事件并适当地格式化数据以进行输出。

socket.on('message', function (data) {
    var leader;
	if (data.type == 'chat' && data.nick != nick) {
		leader = color("<"+data.nick+"> ", "green");
		console_out(leader + data.message);
	}
	else if (data.type == "notice") {
		console_out(color(data.message, 'cyan'));
	}
	else if (data.type == "tell" && data.to == nick) {
		leader = color("["+data.from+"->"+data.to+"]", "red");
		console_out(leader + data.message);
	}
	else if (data.type == "emote") {
		console_out(color(data.message, "cyan"));
	}
});

客户端使用我们的昵称发送的类型为 chat 的消息将与昵称和聊天文本一起显示。用户已经可以看到他们在 Readline 中输入的内容,因此没有必要再次输出它。在这里,我使用 ansi-color 包对输出进行一点着色。这并不是绝对必要的,但它使聊天更容易理解。

类型为 noticeemote 的消息按原样打印,但颜色为青色。

如果消息是 tell,且昵称等于此客户端的当前名​​称,则输出采用 [Somebody->You] Hi! 的形式。当然,这并不是非常私密的事情。如果您想查看每个人的消息,您只需取出 && data.to == nick 部分即可。理想情况下,服务器应该知道将消息推送到哪个客户端,而不是将其发送给不需要它的客户端。但这增加了不必要的复杂性,超出了本教程的范围。

点燃它!

现在让我们看看是否一切正常。要对其进行测试,请通过运行 node server.js 启动服务器,然后打开几个新的终端窗口。在新窗口中,运行 node client.js 并输入昵称。假设一切顺利,那么您应该能够在他们之间聊天。

希望本教程向您展示了 Readline 模块的入门是多么容易。您可能想尝试向聊天应用程序添加更多功能,以进行更多练习。最后,查看 Readline 文档以获取完整的 API。

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn