Rumah  >  Artikel  >  Tutorial CMS  >  Sembang masa nyata menggunakan Readline dan Socket.io untuk Node.js

Sembang masa nyata menggunakan Readline dan Socket.io untuk Node.js

WBOY
WBOYasal
2023-08-31 18:09:071398semak imbas

Sembang masa nyata menggunakan Readline dan Socket.io untuk Node.js

Node.js mempunyai modul yang kurang dihargai, tetapi sangat berguna dalam perpustakaan standardnya. Modul Readline melakukan apa yang tertulis pada kotak: membaca baris input dari terminal. Ini boleh digunakan untuk bertanya kepada pengguna satu atau dua soalan, atau membuat gesaan di bahagian bawah skrin. Dalam tutorial ini, saya akan menunjukkan keupayaan Readline dan membuat ruang sembang CLI secara langsung yang dikuasakan oleh Socket.io. Pelanggan bukan sahaja boleh menghantar mesej ringkas, tetapi juga menggunakan /me untuk menghantar arahan emotikon, gunakan /msg untuk menghantar mesej peribadi , dan Membenarkan penggunaan /nick. /me 发送表情命令,使用 /msg 发送私人消息,并允许使用 /nick

关于 Readline 的一点

这可能是 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();
});

我们包含该模块,使用标准输入和输出流创建 Readline 接口,然后向用户询问一个一次性问题。这是Readline的第一个用法:提问。如果您需要与用户确认某些内容,可能采用流行的形式,“您想这样做吗?(y/n)”,这种形式普遍存在于 CLI 工具中,readline.question () 就是这样做的方法。

Readline 提供的另一个功能是提示,可以根据其默认的“>”字符进行自定义,并暂时暂停以防止输入。对于我们的 Readline 聊天客户端,这将是我们的主要界面。将会出现一次 readline.question() 来询问用户昵称,但其他所有内容都将是 readline.prompt()

管理您的依赖项

让我们从无聊的部分开始:依赖关系。该项目将使用 socket.iosocket.io-client 包和 ansi-color。您的 packages.json 文件应如下所示:

{
    "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
}

运行 npm install 就可以了。

服务器

在本教程中,我们将使用一个非常简单的 Socket.io 服务器。没有比这更基本的了:

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);
    });

});

它所做的只是从一个客户端接收传入消息并将其传递给其他所有人。对于更大规模的应用程序来说,服务器可能会更加健壮,但对于这个简单的示例来说,它应该足够了。

这应该保存在项目目录中,名称为 server.js

客户端:包括和设置

在我们开始有趣的部分之前,我们需要包含我们的依赖项,定义一些变量,并启动 Readline 接口和套接字连接。

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);

此时,代码几乎是不言自明的。我们已经有了昵称变量、套接字连接(通过 socket.io-client 包)和 Readline 接口。

在此示例中,Socket.io 将通过端口 3636 连接到本地主机,当然,如果您正在制作生产聊天应用程序,这将更改为您自己的服务器的域和端口。 (与自己聊天没有多大意义!)

客户端:询问用户名

现在我们第一次使用 Readline!我们想询问用户选择的昵称,这将在聊天室中识别他们。为此,我们将使用 Readline 的 question() 方法。

// 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);
});

我们将之前的 nick 变量设置为从用户收集的值,向服务器发送一条消息(该消息将转发到其他客户端)我们的用户已加入聊天,然后将 Readline 界面切换回提示模式。传递给 prompt()true 值可确保正确显示提示符。 (否则光标可能会移动到该行的零位置,并且不会显示“>”。)

不幸的是,Readline 在 prompt() 方法方面存在令人沮丧的问题。它与 console.log() 配合得不太好,它会将文本输出到与提示字符相同的行,从而在各处留下杂散的“>”字符和其他字符怪异。为了解决这个问题,我们不会在此应用程序中的任何位置使用 console.log,仅保留一个位置。相反,输出应该传递给此函数:

function console_out(msg) {
    process.stdout.clearLine();
	process.stdout.cursorTo(0);
	console.log(msg);
	rl.prompt(true);
}

这个稍微的hacky解决方案可确保控制台中的当前行为空,并且在打印输出之前光标位于零位置。然后它明确要求再次输出提示。

因此,在本教程的其余部分中,您将看到 console_out() 而不是 console.log()

Sedikit tentang Readline

Ini mungkin cara paling mudah untuk menggunakan Readline:

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);
	}
});

Kami menyertakan modul ini untuk mencipta antara muka Baris Baca menggunakan aliran input dan output standard dan kemudian bertanya kepada pengguna soalan sekali sahaja. Ini adalah penggunaan pertama Readline: bertanya soalan. Jika anda perlu mengesahkan sesuatu dengan pengguna, ini mungkin dalam bentuk popular, "Adakah anda mahu melakukan ini? (y/n)", yang terdapat di mana-mana dalam alatan CLI, readline. soalan () ialah cara untuk melakukan ini.

#🎜🎜# #🎜🎜#Ciri lain yang disediakan oleh Readline ialah gesaan, yang boleh disesuaikan dengan aksara lalai ">" mereka dan dijeda buat sementara waktu untuk mengelakkan penaipan. Untuk pelanggan sembang Readline kami, ini akan menjadi antara muka utama kami. Akan ada satu readline.question() untuk meminta nama panggilan pengguna, tetapi yang lain ialah readline.prompt() . #🎜🎜##🎜🎜# #🎜🎜#Urus tanggungan anda#🎜🎜# #🎜🎜# Mari kita mulakan dengan bahagian yang membosankan: kebergantungan. Projek ini akan menggunakan pakej socket.io, socket.io-client dan ansi- warna . Fail packages.json anda sepatutnya kelihatan seperti ini: #🎜🎜#
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.");

	}
}
#🎜🎜#Hanya jalankan npm install. #🎜🎜##🎜🎜##🎜🎜# #🎜🎜#pelayan#🎜🎜# #🎜🎜#Dalam tutorial ini, kami akan menggunakan pelayan Socket.io yang sangat mudah. Ia tidak menjadi lebih asas daripada ini: #🎜🎜#
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"));
	}
});
#🎜🎜#Apa yang dilakukannya ialah menerima mesej masuk daripada seorang pelanggan dan menyampaikannya kepada orang lain. Untuk aplikasi skala yang lebih besar pelayan mungkin lebih mantap, tetapi untuk contoh mudah ini ia sepatutnya mencukupi. #🎜🎜##🎜🎜##🎜🎜# #🎜🎜#Ini harus disimpan dalam direktori projek dengan nama server.js. #🎜🎜##🎜🎜##🎜🎜# #🎜🎜#Pelanggan: Termasuk dan Tetapan#🎜🎜##🎜🎜# #🎜🎜# #🎜🎜# Sebelum kita sampai ke bahagian yang menyeronokkan, kita perlu memasukkan kebergantungan kita, mentakrifkan beberapa pembolehubah dan memulakan antara muka Readline dan sambungan soket. #🎜🎜# rrreee #🎜🎜#Pada ketika ini, kod itu hampir jelas. Kami sudah mempunyai pembolehubah nama panggilan, sambungan soket (melalui pakej socket.io-client) dan antara muka Readline. #🎜🎜# #🎜🎜# Dalam contoh ini Socket.io akan menyambung ke localhost melalui port 3636, sudah tentu jika anda membuat aplikasi sembang pengeluaran ini akan ditukar kepada domain anda sendiri dan pelabuhan pelayan. (Tidak ada gunanya bersembang dengan diri sendiri!) #🎜🎜# #🎜🎜#Pelanggan: Minta nama pengguna#🎜🎜##🎜🎜# #🎜🎜# #🎜🎜#Kini kami menggunakan Readline buat kali pertama! Kami ingin meminta pengguna untuk nama panggilan pilihan mereka, yang akan mengenal pasti mereka dalam bilik sembang. Untuk melakukan ini, kami akan menggunakan kaedah question() Readline. #🎜🎜# rrreee #🎜🎜# Kami menetapkan pembolehubah nama panggilan sebelumnya kepada nilai yang dikumpul daripada pengguna, menghantar mesej kepada pelayan (yang akan dimajukan kepada pelanggan lain) bahawa pengguna kami telah menyertai sembang, dan kemudian menukar antara muka Readline kembali ke gesaan mod. Nilai true dihantar kepada prompt() memastikan gesaan dipaparkan dengan betul. (Jika tidak kursor boleh bergerak ke kedudukan sifar pada baris dan ">" tidak akan dipaparkan.) #🎜🎜##🎜🎜##🎜🎜# #🎜🎜#Malangnya, Readline mempunyai isu yang mengecewakan dengan kaedah prompt(). Ia tidak berfungsi dengan baik dengan console.log(), yang mengeluarkan teks ke baris yang sama dengan aksara gesaan, meninggalkan aksara ">" yang tersesat dan watak pelik yang lain. Untuk menyelesaikan masalah ini, kami tidak akan menggunakan console.log di mana-mana dalam aplikasi ini, kecuali di satu tempat. Sebaliknya, output harus dihantar ke fungsi ini: #🎜🎜# rrreee #🎜🎜# Penyelesaian sedikit meretas ini memastikan baris semasa dalam konsol kosong dan kursor berada pada kedudukan sifar sebelum mencetak output. Kemudian ia secara eksplisit meminta untuk mengeluarkan gesaan sekali lagi. #🎜🎜##🎜🎜##🎜🎜# #🎜🎜# Oleh itu, dalam tutorial ini yang lain, anda akan melihat console_out() dan bukannya console.log() code> . #🎜🎜# #🎜🎜#Pelanggan: memproses input #🎜🎜##🎜🎜# #🎜🎜# #🎜🎜# Pengguna boleh memasukkan dua jenis input: sembang dan arahan. Kami tahu arahan itu didahului dengan garis miring, jadi mudah untuk membezakan antara keduanya. #🎜🎜##🎜🎜##🎜🎜# <p>Readline 有几个事件处理程序,但最重要的无疑是 <code class="inline">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。

Atas ialah kandungan terperinci Sembang masa nyata menggunakan Readline dan Socket.io untuk Node.js. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn