Socket.IO
یک کتابخانهی بسیار محبوب برای برقراری ارتباط سوکت هست که هم کتابخانه برای کلاینت دارد و هم برای سرور.
ما توی این داکیومنت ورژن ۳ سوکت رو توضیح میدیم. درحالی که ورژن ۴ آمده است.
Cheat Sheet
این چیت شیت با فرض این هست که به مطالب توی داکیومنت و خارج از چیت شیت تسلط داشته باشی
Server Cheat Sheet
io.of("/namespace").on("connection", (socket) => {
// first handshake with namespace
// --- send ---
socket.emit(key, value); // فقط و فقط به یک کانکشن ارسال میکنه
io.emit(key, value); // به تمام کانکشنها ارسال میکنه
io.to(roomName).emit(key, value); // به تمام کانکشن ها که داخل روم جوین هستن ارسال میکنه
io.in(roomName).emit(key, value); // به تمام کانکشنها که داخل روم جوین هستن یکبار ارسال میکنه و سپس اونارو از روم حذف میکنه
// --- get ---
socket.on("key", callBackFunction); // منتظر میمونه هربار که دیتا با کلید مدنظر دریافت بشه تابع کال بک رو کال کنه
socket.once("key", callBackFunction); // تنها یکبار منتظر میمونه که دیتا با کلید مدنظر دریافت بشه و بعدش دیگه منتظر نمیمونه
// --- room ---
socket.join(roomName); // کلاینت رو توی روم مدنظر جوین میکنه
socket.leave(roomName); // کلاینت رو از روم حذف میکنه
// --- query & headers ---
const queries = socket.handshake.query; // دسترسی به کوئریهایی که کلاینت ارسال کرده داریم
const headers = socket.handshake.headers; // دسترسی به هدرهایی که کلاینت ارسال کرده
});
در کل هر عملیاتی رو با socket انجام بدی فقط و فقط به اون کانکشن و یک کانکشن ارسال میکنه.
هر عملیاتی رو با io انجام بدی به تمام کانکشن ها ارسال میکنه که میتونیم محدودترش بکنیم مثلا به روم ها و ...
Client Cheat Sheet
const socket = io("http://localhost:8000/namespace", {
// first handshake with namespace
query: {
field1: "value1", // ارسال کوئری به سرور
},
transportOptions: {
polling: {
extraHeaders: {
Authorization: "Bearer <token>", // ارسال هدر authorization به سرور
},
},
},
});
socket.on("connect", async (data) => {
// --- send ---
socket.emit(key, value); // دیتا رو به سرور ارسال میکنه
// --- get ---
socket.on("key", callBackFunction); // منتظر میمونه هربار که دیتا با کلید مدنظر دریافت بشه تابع کال بک رو کال کنه
socket.once("key", callBackFunction); // تنها یکبار منتظر میمونه که دیتا با کلید مدنظر دریافت بشه و بعدش دیگه منتظر نمیمونه
socket.off("key"); // دیگه لیسنر روی یک کلید نداره و حذفش میکنه. دقیقا مخالف آن
});
// ---- Listener ----
socket.on("connect_error", (err) => {
// وقتی تلاش میکنه کانکت بشه به سرور ولی ارور میگیره
console.log(err);
});
socket.on("disconnect", (reason) => {
// وقتی کانکشنش با سرور قطع میشه
console.log(reason);
});
Start Server
برای راهاندازی سوکت در سمت سرور از پکیج socket.io با ورژن ۳ استفاده میکنیم:
npm install socket.io@3
مانند websocket سروری که ساختیم رو بهش پاس میدیم:
const http = require("http");
const socketIO = require("socket.io");
const server = http.createServer();
const io = socketIO(server, {
cors: {
origin: "*",
},
});
server.listen(8000, () => console.log("Server runned on port 8000"));
همچنین ما cors رو ست میکنیم که مشکلی پیش نیاد
اگرم خواستیم با Express از سوکت استفاده کنیم به صورت زیر عمل میکنیم:
const express = require("express");
const http = require("http");
const socketIO = require("socket.io");
const app = express();
const server = http.createServer(app);
const io = socketIO(server, {
cors: {
origin: "*",
},
});
app.get("/", (req, res, next) => {
io.emit("key", message);
// ...
res.send("salam");
});
server.listen(8000, () => console.log("Server runned on port 8000"));
همونطور که دیده میشه، میتونیم از socket توی restful api هم استفاده کنیم
Connection
زمانی که کانکشن با سوکت کلاینت برقرار شد میتونیم با استفاده از این متد بهش دسترسی داشته باشیم:
io.on("connection", (socket) => {
console.log("Connection created successfully");
});
دقت کن که هر کانکشن توی سرور کاملا ایزوله از بقیهی کانکشنها هست!
یعنی به ازای هر کانکشنی که برقرار میشه محیط کاملا ایزوله از بقیهی کانکشنها خواهد بود و هیچ ارتباطی به هم ندارن. متغیرها داخلش میمونه و بقیهی کانکشن ها دسترسی بهش ندارن
درواقع :
io.on("connection", (socket) => {
console.log("Isolated connection");
});
توی بلاک هایلایت شده هر کدی بنویسی مستقل از بقیه کانکشن ها کاملا اجرا میشه
Disconnect
وقتی که یک سوکت دیسکانکت شد میتونیم از طریف متد disconnect ترکش کنیم:
io.on("connection", (socket) => {
socket.on("disconnect", (e) => {
// code ...
});
});
برای مثال تعداد کانکشنهای برقرار رو اگر بخوایم بگیریم:
let onlines = 0;
io.on("connection", (socket) => {
onlines++;
socket.on("disconnect", (e) => {
onlines--;
});
});
توی این مثال همیشه تعداد آنلاینها درست میموننه
از متد disconnecting هم میشه استفاده کرد فرقش با disconnect اینه که هنوز به طور کامل کانکشن قطع نشده
io.on("connection", (socket) => {
socket.on("disconnecting", (e) => {
// code ...
});
});
Emit
ما برای ارسال دیتا به کلاینت از emit استفاده میکنیم:
io.on("connection", (socket) => {
socket.emit("key", "message");
});
key برای این هست که کلاینت بدونه دیتا رو با کدوم کلید داره دریافت میکنه.
برای مثال برای ارسال خوشامد گویی به صورت زیر عمل میکنیم:
io.on("connection", (socket) => {
socket.emit("welcome-server", "Hello client");
});
کلاینت حالا این پیام رو میتونه با استفاده از socket.on("welcome-server") دریافت کنه
ما اگر بخوایم یک emit رو روی تمام سوکتها بخوابیم انجام بدیم میتونیم از io.emit استفاده کنیم.
درواقع socket.emit پیام رو صرفا توی سوکتی که باز هست میفرسته ولی io.emit برای تمام سورکت ها ارسال میکنه
io.on("connection", (socket) => {
io.emit("brod-cast", "this is message from server to all clients"); // all sockets
socket.emti("private", "this is message from server to just this socket"); // this open socket
});
این پیام به تمامی سوکتهای باز ارسال میشود
به طور خلاصه روی namespace ای که هستیم اگر io.emit بزنیم روی تمام socket های اون namespace که کانکشن برقرار هست emit انجام میشود
و اگر socket.emit بزنیم تنها روی یک کانکشن و کانکشنی که باز هست emit انجام میشه
On
ما برای دریافت دیتا از کلاینت از on استفاده میکنیم:
یعنی کلاینت یک پیام را با یک کلید برای ما emit میکند و ما این پیام رو با on دریافت میکنیم.
io.on("connection", (socket) => {
socket.on("key", (data) => {
console.log(data);
});
});
دیتا شامل پیامی هست که کلاینت برای ما emit کرده. و از طرفی key را باید بدانیم.
برای مثال برای دریافت پیام خوشامدگویی از طرف کلاینت به صورت زیر عمل میکنیم:
io.on("connection", (socket) => {
socket.on("welcome-client", (data) => {
console.log(data);
});
});
Example
یک مثال برای سوکت در سرور داریم که پیام خوش آمدگویی به کلاینت ارسال میکند و پیام خوش آمدگویی آنرا دریافت میکند:
const http = require("http");
const socketIO = require("socket.io");
const server = http.createServer();
const io = socketIO(server, {
cors: {
origin: "*",
},
});
io.on("connection", (socket) => {
socket.on("welcome-from-client", (data) => {
console.log(data);
});
socket.emit("welcome-from-server", "hello client");
});
io.on("close", () => console.log("connection closed"));
io.on("error", (err) => console.log(err));
server.listen(8000, () => console.log("Server runned on port 8000"));
Start Client
برای راهاندازی سوکت در سمت کلاینت از پکیج socket.io-client استفاده میکنیم.
npm install socket.io-client
یا میتونیم از لینک CDN اش توی پروژه استفاده کنیم:
<script src="https://cdn.socket.io/4.7.4/socket.io.min.js"></script>
اگر از CDN استفاده میکنی که معمولا برای پروژههای ریکت و ... از پکیج npm استفاده میکنیم نیازی به ایمپورت کردن نیست. در غیر اینصورت اونو ایمپورت میکنیم و اتصال برقرار میکنیم:
import { io } from "socket.io-client";
const socket = io("http://localhost:8000");
دقت کن که توی استفاده از پکیج socket io دیگه نیازی به پروتکل ws:// نیست و میتونیم با http ارتباط برقرار کنیم
Connection
زمانی که کانکشن برقرار بشه این متد صدا زده میشود:
socket.on("connect", (data) => {
console.log("Connected to server Socket");
});
Disconnect
زمانی که کانکشن قطع میشه این متد کال میشه:
socket.on("disconnect", (reason) => {
console.log(reason);
});
Connect Error
زمانی که هنگام تلاش برای اتصال به سرور ارور میگیره که مقداری که برمیگردونه دلیل ارور هست :
socket.on("connect_error", (reason) => {
console.log(reason);
});
Emit
دقیقا مانند emit در سوکت سرور برای ارسال دیتا استفاده میشه.
یعنی ما با emit از کلاینت به سرور دیتا میفرستیم. و با on دیتایی که از سرور اومده رو میخونیم
socket.on("connect", (data) => {
socket.emit("key", "message");
});
برای مثال برای پیام خوشامد گویی به سرور میتونیم از کد زیر استفاده کنیم:
socket.on("connect", (data) => {
socket.emit("welcome-client", "Hello server");
});
On
دقیقا مانند on درون سرور برای خواندن دیتا هست. از on داخل کلاینت برای خواندن دیتایی که سرور برای ما ارسال کرده استفاده میکنیم:
socket.on("connect", (data) => {
socket.on("key", (data) => {
console.log(data);
});
});
برای مثال برای دریافت پیام خوش آمدگویی از سمت سرور به صورت زیر عمل میکنیم:
socket.on("connect", (data) => {
socket.on("welcome-server", (data) => {
console.log(data);
});
});
Off
وقتی روی یک key ما on کردیم اگر دیگه نیاز نباشه بهش گوش بدیم off میکنیم.
یعنی دیگه منتظر پیام نمیمونه.
socket.of(key);
برای مثال ما یک پیام ارسال کردیم به سرور و منتظر هستیم ببینیم به دستش رسیده یا نه.
بعد از گرفتن نتیجه دیگه نیازی نیس روش on کنیم پس از off استفاده میکنیم:
socket.on("connect", async (data) => {
socket.emit("message", "Salam server");
socket.on("result", (data) => {
console.log("result form server : " + data);
socket.off("result");
});
});
دقت که اکثر عملیاتهای socket.io به صورت synchronized هستش
بعنی وقتی تو emit میزنی درخواست رو به network میفرسته و بعدش میره خط بعد. همینطوری وقتی on میزنی روی اون پیام لیسنر میزنه و بعدش میره خط بعد.
Example
یک مثال در اینجا داریم که به سرور پیام خوش آمدگویی میدهد. و پیام خوشامد گویی سرور رو دریافت میکند
const socket = io("http://localhost:8000");
socket.on("connect", (data) => {
console.log("Connected to server Socket");
socket.emit("welcome-from-client", "hello server");
socket.on("welcome-from-server", (data) => {
console.log(data);
});
});
Namespace
نیماسپیس یک ابزاری هست که چندین تا محیط مختلف و مستقل از هم داشته باشیم.
برای مثال اگر ما ۳ نوع چت داشته باشیم: ادمین با ادمین، ادمین با یوزر و یوزر با یوزر باید برای هرکدوم یک فضای چت جداگانه درست کنیم.
به طوری که چت یوزر با یوزر هیچ دسترسیی به چت ادمین با ادمین یا ادمین با یوزر نداشته باشه.
برای این کار از name space ها استفاده میکنیم.
Server
برای تعریف namespace سمت سرور از متد io.of استفاده میکنیم:
io.of("/user-user").on("connection", (socket) => {
// ...
});
io.of("/admin-user").on("connection", (socket) => {
// ...
});
io.of("/admin-admin").on("connection", (socket) => {
// ...
});
به صورت پیشفرض روی io.of('/').on هست
Client
برای دسترسی به یک namespace صرفا باید هنگام اتصال بهش در انتهای url اونو قرار بدیم:
const userUserSocket = io("http://localhost:8000/user-user");
const adminUserSocket = io("http://localhost:8000/admin-user");
const adminAdminSocket = io("http://localhost:8000/admin-admin");
حالا با هرکدوم میتونیم به صورت یک سوکت نورمال و جداگانه رفتار کنیم.
Example
برای مثال ما ۳ نوع چت داریم. که کد اتصال بین سرور و کلاینتشون به صورت زیر هست:
const http = require("http");
const socketIO = require("socket.io");
const server = http.createServer();
const io = socketIO(server, {
cors: {
origin: "*",
},
});
io.of("/user-user").on("connection", (socket) => {
socket.emit("welcome-server", "this is user-user chat area");
socket.on("welcome-client", (data) => {
console.log("message from user-user client : " + data);
});
});
io.of("/admin-user").on("connection", (socket) => {
socket.emit("welcome-server", "this is admin-user chat area");
socket.on("welcome-client", (data) => {
console.log("message from admin-user client : " + data);
});
});
io.of("/admin-admin").on("connection", (socket) => {
socket.emit("welcome-server", "this is admin-admin chat area");
socket.on("welcome-client", (data) => {
console.log("message from admin-admin client : " + data);
});
});
server.listen(8000, () => console.log("Server runned on port 8000"));
const userUserSocket = io("http://localhost:8000/user-user");
const adminUserSocket = io("http://localhost:8000/admin-user");
const adminAdminSocket = io("http://localhost:8000/admin-admin");
userUserSocket.on("connect", (data) => {
userUserSocket.emit("welcome-client", "hello server");
userUserSocket.on("welcome-server", (data) => {
console.log("message from user-user server : " + data);
});
});
adminUserSocket.on("connect", (data) => {
adminUserSocket.emit("welcome-client", "hello server");
adminUserSocket.on("welcome-server", (data) => {
console.log("message from admin-user server : " + data);
});
});
adminAdminSocket.on("connect", (data) => {
adminAdminSocket.emit("welcome-client", "hello server");
adminAdminSocket.on("welcome-server", (data) => {
console.log("message from admin-admin server : " + data);
});
});
توی این مثال ما ۳ تا محیط مختلف ساختیم که ارتباط بین کلاینت و سرورش برقرار کردیم و هم پیام از کلاینت به سرور و هم از سرور به کلاینت ارسال کردیم
Rooms
هر namespace میتونه شامل چندین room باشه. برای مثال در تلگرام ما namespace رو میتونیم به فولدر ها و room رو به هر چت اختصاص بدیم.
یعنی هر فولدر توی تلگرام یک namespace هست که شامل چندین room هست
Join Room
فرآیند join room به اینصورت هست که سرور یک کلاینت رو داخل یک روم جوین میکنه.
دقت کن که فرآیند جوین کردن به صورت کامل روی سرور هست و کلاینت نیازی نیست کاری کنه. درواقع کلاینت به طور مستقیم نمیتونه توی روم جوین بشه و سرور باید جوینش کنه:
io.on("connection", (socket) => {
console.log("Client connected to socket");
socket.on("join-room", (room) => {
socket.join(room);
});
});
همچنین میتونیم روی چند روم هم جوین بدیم :
socket.join(["room-1", "room-2", "..."]);
برای مثال :
- کلاینت درخواست میده مثلا
socket.emit("join-room",roomName) - سرور روی این درخواست on میکنه:
socket.on("join-room", data=>{}) - سپس با دستور socket.join کلاینت رو جوین روم میکنه !!!
- از این به بعد هر دستوری که سرور روی یک روم بفرسته اون کلاینت به طور اتوماتیک دریافتش میکنه
- درکل نکتهی مهم اینه که: کلاینت نمیتونه مستقیم توی یک روم جوین بشه و باید سرور اونو جوین کنه. از اون به بعد هر دستوری که سرور به روم مدنظرش بفرسته فقط کلاینتهایی که جوین اون روم شدن دریافتش میکنن
Leave Room
برای خارج شدن از یک روم استفاده میشود.
socket.leave("room-name");
دقت کن که فرآیند leave کردن تنها توسط سرور انجام میشه. یعنی یک کلاینت مستقیم توسط سرور به یک روم join داده میشه و مستقیم توسط سرور حذف(leave) میشه.
برای مثال زمانی که ما توکن کاربر رو نتونیم احراز هویت بکنیم اونو از room بیرون پرت میکنیم:
io.on("connection", (socket) => {
const token = socket.handshake.headers.authorization.split(" ")[1];
socket.on("msg", (data) => {
const room = data.room;
if (isValidToken(token)) {
io.to(room).emit("result", data);
} else socket.leave(room);
});
});
Emit to Room
برای اینکه یک دیتا فقط به room خاص مدنظر ما از طرف سرور فرستاده بشه میتونیم از ۲ روش زیر استفاده کنیم:
socket.to(roomName).emit :
توی این روش یک پیغام به تمامی اعضای room مدنظر ارسال میشود بهجز کسی که درخواستش رو فرستاده !!
یعنی برای مثال ۱۰ تا کلاینت توسط سرور توی یک روم join شدن. حالا سرور یکی از کلاینتها یک درخواستی میفرسته که درنتیجهی این درخواست سرور به تمام اعضای این room با استفاده از socket.to.emit یک پیام میفرسته. تمام این اعضای گروه غیر عضوی که درخواستش باعث شده سرور پیام بفرسته این پیام رو دریافت میکنن. یعنی ۹ کلاینت دریافتش میکنن و ۱ کلاینت که خودش باعث ارسال این پیام از سرور شده دریافتش نمیکنه !
دلیل این هم این هست که برای پرفورمنس بهتر به کسی که درخواست فرستاده و نتیجهی درخواستش باعث ساختن پیام از سوی سرور شده پیام سرور رو نمیفرسته چون اون کلاینت میدونه که نتیجش چیه !
برای مثال من با استفاده از یک کلاینت به سرور درخواست join-room میدم. خب میدونم که نتیجهی این درخواست عضویت داخل room هست و نیازی به پاسخ سرور ندارم. در اینصورت از socket.to.emit استفاده میکنم
io.on("connection", (socket) => {
console.log("Client connected to socket");
socket.on("join-room", (room) => {
socket.join(room);
console.log(socket.rooms);
socket.to(room).emit("joined-room", `joined ${room} successfully`);
});
});
io.to(roomName).emit :
توی این روش سرور یک پیغام رو به تمام اعضای room بدون استثنا میفرسته.
یعنی پیغامی که توسط سرور ساخته میشه حتی به کلاینتی که باعث ایجاد این پیام شده هم ارسال میشه. درواقع به تمامی اعضای این room بدون استثنا
io.on("connection", (socket) => {
console.log("Client connected to socket");
socket.on("join-room", (room) => {
socket.join(room);
console.log(socket.rooms);
io.to(room).emit("joined-room", `joined ${room} successfully`);
});
});
خلاصه :
io.to(roomName).emit("key", `message`);
توی این مورد پیام به تمام اعضای روم بدون استثنا ارسال میشه
socket.to(roomName).emit("key", `message`);
توی این مورد پیام به تمام اعضای روم به جز کلاینتی که باعث ایجاد پیام شده ارسال میشه
Emit in Room
فرق socket.in(roomName).emit با socket.to(roomName).emit اینه که بعد از to کلاینت توی روم باقی میمونه ولی بعد از in سرور کلاینت رو از روم میندازه بیرون.
درضمن برای ارسال پیام همگانی به کل اعضای روم باید مثل to از io.in(roomName).emit به جای socket.in(roomName).emit استفاده کرد. چون socket.in(roomName).emit به کلاینتی که باعث ایجاد این پیام شده پیام رو نمیفرسته
io.on("connection", (socket) => {
console.log("Client connected to socket");
socket.on("join-room", (room) => {
socket.join(room);
console.log(socket.rooms);
io.in(room).emit("joined-room", `joined ${room} successfully`);
});
});
به طور خلاصه :
io.in(room).emit("joined-room", `joined ${room} successfully`);
به تمام اعضای روم بلا استثنا پیام را میفرستد و پس از ارسال پیام اونارو از روم حذف میکنه
socket.in(room).emit("joined-room", `joined ${room} successfully`);
به تمام اعزای روم به جز عضوی که باعث ارسال پیام شده میفرسته و بعدش از روم حذفشون میکنه
Query
ما از سمت کلاینت میتونیم header و query ارسال کنیم و سمت سرور اونارو بررسی کنیم. برای مثال اگر توی چتبات ما یکی پیام داد باید token اش رو چک کنیم بعدش پیام رو رد و بدل کنیم
دقت کن که این دیتا روی کلاینت قابل ست کردن هست
Client
در اینجا میگیم که کلاینت چطوری میتونه query ارسال کن
ه. دقت کن که صرفا در handshake اولیه و کانکشن اولیه امکان ارسال query هست. اگر query در وسط کار عوض شد باید کانکشن جدید برقرار شود
const socket = io("http://localhost:8000/", {
query: {
field1: "value1",
field2: "value2",
// ....
},
});
با این روش هنگام ایجاد کانکشن با سوکت سرور این query ها ارسال میشوند
Server
در اینجا میگیم چطور query هایی که کلاینت ارسال کرده رو سمت سرور دریافت کنیم.
دقت کن که در هر پیام کلاینت این query ها ارسال نمیشه. بلکه صرفا هنگام ایجاد کانکشن اولیه این query ها ارسال میشه و تنها یکبار هنگام handshake اولیه دریافت میشه توسط سرور
io.on("connection", (socket) => {
const queries = socket.handshake.query;
});
Headers
ما همچنین میتونیم header هم از سمت کلاینت ارسال کنیم و اونو توی سرور تحلیل کنیم.
برای مثال وقتی ما یک چتبات نوشتیم باید کاربر احراز هویت بشود و این از این طریق اتفاق میفته که token اش توسط header از کلاینت به سرور ارسال بشه
Client
توی اینجا میگیم که چطور میتونیم از کلاینت به سرور header ست بکنیم
دقت کن که این header ها تنها توی برقرای کانکشن اولیه ارسال میشن. نه به ازای هر پیام و emit.
صرفا هنگام handshake اولیه با سوکت سرور این هدر ارسال میوشد
const socket = io("http://localhost:8000/", {
transportOptions: {
polling: {
extraHeaders: {
Authorization: "Bearer <token>",
"X-API-KEY": "<api_key>",
// ... other headers
},
},
},
});
Server
اینجا میگیم چطور header ای که کاربر ست کرده رو دریافت کنیم.
دقت کن که این هدر صرفا هنگام اتصال اولیه(handshake) ارسال میشه نه به ازای هم emit و یا ارسال پیام توسط کلاینت
io.on("connection", (socket) => {
const headers = socket.handshake.headers;
});
Example
برای مثال برای ارسال دریافت همزمان Query ها و Header های درخواست به صورت زیر عمل میکنیم:
const socket = io("http://localhost:8000/", {
query: {
id: "12",
},
transportOptions: {
polling: {
extraHeaders: {
Authorization: "Bearer <token>",
},
},
},
});
socket.on("connect", (data) => {
socket.emit("welcome-client", "hello server");
socket.on("welcome-server", (data) => {
console.log("message form server : " + data);
});
});
const http = require("http");
const socketIO = require("socket.io");
const server = http.createServer();
const io = socketIO(server, {
cors: {
origin: "*",
},
});
io.on("connection", (socket) => {
console.log(socket.handshake.query);
console.log(socket.handshake.headers);
socket.emit("welcome-server", "hello client");
socket.on("welcome-client", (data) => {
console.log("message from client : " + data);
});
});
server.listen(8000, () => console.log("Server runned on port 8000"));
File Upload
اینجا نحوهی آپلود فایل توی سوکت رو میگیم.
Client
توی کلاینت کار خاصی نباید کرد خیلی. صرفا گرفتن فایل از input و emit کردنش به سرور کافی هست.
socket.on("connect", async (data) => {
const files = document.getElementById("file");
socket.emit("upload", files[0]);
});
همین کافی هست. صرفا قابلی که میفرستیم رو توی سرور باید بگیریم و سیوش بکنیم
Server
در کل فرآیند آپلود فایل به اینصورت هست که یک فایل به صورت buffer ارسال میشه. هرچیزی که باشه به صورت buffer ارسال میشه. فرقی نمیکنه ویدیو باشه، عکس باشه، نوشته pdf و ...
همرو به صورت بافر ارسال میکنه
توی سرور باید فایلی که ارسال شده رو دریافت کنیم و با استفاده از fs.writeFile اونو توی مسیری که میخوایم رایت کنیم
socket.on("upload", (file) => {
const ext = path.extname(file.name);
const fileName = Date.now().toString() + ext;
fs.writeFile("/public/files/" + fileName, file, (err) => {
if (err) console.log(err.message);
});
});
درکل خیلی راحت باید با استفاده از سوکت فایل رو بگیریم. و بعدش با استفاده از writeFile توی مسیرمون بنویسیمش