0Pricing
Lua Academy · درس

إنشاء عميل

اطلب البيانات من خادم

إنشاء عميل درس مجاني في Lua Academy على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Lua Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Lua Academy 4 دروس في المجموع.

دورة حياة العميل

يمر عميل TCP بدورة حياة واضحة: إنشاء مقبس، والاتصال بخادم، وتبادل البيانات، ثم الإغلاق.

في LuaSocket، تمثّل كل خطوة استدعاءَ طريقة واحدة، وقد تفشل كل منها. ويتحقق العميل المكتوب جيدًا من كل قيمة معادة وينظّف مقبسه عند أي مسار خطأ.

local socket = require("socket")
local client = assert(socket.tcp())

الاتصال بأمان

اضبط مهلة اتصال قبل استدعاء connect حتى لا يتسبب مضيف متوقف في تعليق برنامجك. وتُعد بضع ثوانٍ مدةً معتادة.

إذا أعاد connect القيمة nil، فسجّل الخطأ وأوقف التنفيذ. لا تفترض أبدًا نجاح المصافحة.

client:settimeout(5)
local ok, err = client:connect("127.0.0.1", 8080)
if not ok then
  client:close()
  error("connect failed: " .. err)
end

استخدام socket.connect

في الحالة الشائعة، يغلّف socket.connect(host, port) عمليتي الإنشاء والاتصال. ويعيد كائن عميل جاهزًا، أو nil وخطأً.

هذا الأسلوب موجز، لكنه لا يتيح لك ضبط مهلة قبل المصافحة، لذا يُفضَّل استخدام الصيغة الصريحة في الشبكات غير الموثوقة.

local socket = require("socket")
local client, err = socket.connect("example.com", 13)
if not client then error(err) end

إرسال طلب

بعد الاتصال، اكتب بايتات طلبك باستخدام send. تحدد العديد من البروتوكولات النصية الأسطر بمحرف إرجاع العربة متبوعًا بسطر جديد (\r\n).

بما أن TCP عبارة عن تدفق، فاحرص على إنهاء كل رسالة منطقية بوضوح حتى يعرف الخادم موضع انتهائها.

local msg = "PING\r\n"
local sent, err = client:send(msg)
if not sent then error("send failed: " .. err) end

قراءة رد على سطر

في البروتوكولات المعتمدة على الأسطر، كرّر القراءة باستخدام النمط "*l". يعيد كل استدعاء سطرًا واحدًا من دون مُنهيه.

عند الحصول على nil، افحص الخطأ: تعني "closed" أن الخادم أنهى الاتصال، بينما تعني "timeout" عدم وصول بيانات في الوقت المحدد.

client:settimeout(5)
local line, err = client:receive("*l")
if line then
  print("server said:", line)
else
  print("recv error:", err)
end

قراءة استجابة كاملة

غالبًا ما تقرأ بروتوكولات الطلب/الاستجابة كل شيء حتى يغلق الخادم الاتصال. استخدم "*a" لالتقاط الجسم كاملًا.

إذا أغلقت جانب الإرسال إغلاقًا نصفيًا أولًا باستخدام shutdown("send")، فسيرى الخادم نهاية الإدخال ويتمكن من إكمال رده.

client:send("GET DATA\r\n")
client:shutdown("send")
local body, err = client:receive("*a")
print(#(body or ""), "bytes received")

التأطير بطول ثابت

غالبًا ما تضع البروتوكولات الثنائية طول كل رسالة في بدايتها. اقرأ ترويسة الطول أولًا، ثم اقرأ عدد البايتات المحدد تمامًا.

يؤدي تمرير رقم إلى receive إلى الانتظار حتى وصول ذلك العدد أو حدوث خطأ في المقبس، ما يوفر تأطيرًا دقيقًا ضمن تدفق البايتات.

local header = client:receive(4)
local len = string.unpack(">I4", header)
local payload = client:receive(len)

عميل صدى مكتمل

إليك التدفق كاملًا: الاتصال، وإرسال سطر، وقراءة السطر المُعاد، ثم الإغلاق. هذا هو الشكل المعتاد لعميل LuaSocket.

لاحظ أن كل استدعاء قابل للفشل محمي باستخدام assert للاختصار، لكن العميل الحقيقي سيتعامل مع الأخطاء بطريقة ملائمة.

local socket = require("socket")
local c = assert(socket.connect("127.0.0.1", 8080))
assert(c:send("hello\r\n"))
print(c:receive("*l"))
c:close()

معالجة قطع الاتصال

يمكن للخوادم قطع الاتصالات في أي وقت. قد يعيد استدعاء send إلى طرف مغلق nil, "closed"، بينما يعيد receive البيانات الجزئية مع الخطأ.

تعامل مع "closed" باعتباره حالة نهائية طبيعية، لا انهيارًا. وينبغي وضع منطق إعادة الاتصال في غلاف لإعادة المحاولة حول العميل.

local data, err, partial = client:receive("*a")
if err == "closed" then
  print("peer closed, got", #partial, "bytes")
end

العملاء غير الحاجبين

اضبط المهلة على 0 للحصول على عميل غير حاجب بالكامل. عندئذٍ تعيد الاستدعاءات النتيجة فورًا، وتشير إلى "timeout" عندما يتعذر إحراز أي تقدم.

اجمع ذلك مع socket.select للانتظار بكفاءة حتى تصبح العديد من المقابس جاهزة، من دون الدوران المشغول.

client:settimeout(0)
local r = socket.select({client}, nil, 5)
if #r > 0 then print(client:receive("*l")) end

حل أسماء المضيفين

إذا اتصلت باستخدام اسم مضيف، فسيحلّه LuaSocket بالنيابة عنك. وللاطلاع على نتيجة الحل أو تخزينها مؤقتًا، استدعِ socket.dns.toip أو socket.dns.getaddrinfo بنفسك.

يؤدي إجراء الحل مرة واحدة ثم الاتصال باستخدام IP إلى تجنب استعلامات DNS المتكررة داخل حلقة إعادة اتصال ضيقة.

local socket = require("socket")
local ip = assert(socket.dns.toip("example.com"))
local c = assert(socket.connect(ip, 80))

تحقق سريع

اختر الطريقة الصحيحة لقراءة كل ما يرسله الخادم حتى يغلق الاتصال.

مراجعة

أنشأت عميل TCP من البداية إلى النهاية: اتصلت بمهلة، وأطّرت الطلبات وأرسلتها، وقرأت استجابات على هيئة أسطر أو بعدد بايتات محدد أو كتدفق كامل، ثم أغلقت الاتصال بطريقة سليمة.

كما تعرّفت إلى معالجة قطع الاتصال، والوضع غير الحاجب باستخدام select، وتخزين DNS مؤقتًا. بعد ذلك ستكتب جانب الخادم الذي يجيب عن هذه العملاء.

الأسئلة الشائعة

هل درس «إنشاء عميل» مجاني؟

نعم — نص درس «إنشاء عميل» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Lua Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Lua Academy 4 دروس في المجموع.

ماذا ستتعلم في «إنشاء عميل»؟

اطلب البيانات من خادم تتمرن على Lua Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Lua Academy؟

لا تُشترط خبرة سابقة. Lua Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.

كم من الوقت يستغرق درس «إنشاء عميل»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Lua Academy هذا؟

نعم. كل درس في Lua Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. أساسيات TCP
  2. إنشاء عميل
  3. إنشاء خادم
  4. طلبات HTTP
← العودة إلى Lua Academy