پشتیبانی از چندریسه در کلاینت‌های ایمیل

کلاینت‌های ایمیل مانند ImapClient و Pop3Client به کاربران امکان استفاده از آنها در محیط چندنخی را می‌دهند. این کلاینت‌ها می‌توانند یک یا چند اتصال با سرور داشته باشند. برای مدیریت مجموعه‌ای از اتصالات داخل کلاینت‌ها از استخر اتصال استفاده می‌شود. تعداد اتصالاتی که می‌توانند همزمان ایجاد و استفاده شوند، توسط ویژگی CredentialsByHostClient.MaxConnectionsPerServer محدود می‌شود. این ویژگی می‌تواند به مقدار 1 یا بزرگ‌تر تنظیم شود. به‌طور پیش‌فرض این مقدار برابر 10 است. صف دستورات برای اتصال پیاده‌سازی شده است تا از عملیات چندنخی پشتیبانی کند. دستورات ساده‌ای که در پروتکل تعریف شده‌اند مانند Noop، Authenticate و غیره اجرا می‌شوند. کاربر ممکن است تعداد دستورات بیشتری نسبت به تعداد اتصالات موجود شروع کند. اما این دستورات تنها زمانی اجرا می‌شوند که کلاینت بتواند برای عملیات یک اتصال ایجاد کند.

روش‌های استفاده از کلاینت‌های ایمیل در محیط چندنخی

کلاینت‌های ایمیل رفتارهای زیر را دارند:

1. در صورتی که MaxConnectionsPerServer = 1 باشد، کلاینت یک اتصال ایجاد می‌کند، احراز هویت و مجوزدهی را انجام می‌دهد. این اتصال تا زمان از بین رفتن کلاینت در حالت کاری حفظ می‌شود. تمام عملیات‌ها از ریسمان‌های مختلف به یک صف دستورات که در اتصال اصلی قرار دارد هدایت می‌شوند.

2. در صورتی که MaxConnectionsPerServer > 1 باشد، کلاینت تعداد مورد نیاز اتصالات را ایجاد می‌کند و برای هر اتصال احراز هویت و مجوزدهی را انجام می‌دهد. یک اتصال به عنوان اتصال اصلی رزرو می‌شود. این اتصال تا زمانی که کلاینت از بین برود در حالت کاری حفظ می‌شود. سایر اتصالات بر حسب نیاز ایجاد و از بین می‌روند. حداکثر تعداد این اتصالات توسط ویژگی MaxConnectionsPerServer تعریف می‌شود، به طور مثال اگر MaxConnectionsPerServer = 2 باشد، یک اتصال به عنوان اصلی رزرو می‌شود و اتصال دوم به عنوان اضافه برای عملیات‌هایی که در ریسمان‌های دیگر اجرا می‌شوند استفاده می‌شود. به همین ترتیب اگر MaxConnectionsPerServer = 3 باشد، اولین اتصال به عنوان اصلی رزرو شده و دو اتصال دیگر به عنوان اضافه برای عملیات‌های اجرا شده در ریسمان‌های دیگر استفاده می‌شوند. در صورتی که درخواست بعدی برای اتصال از ریسمان جدیدی بیاید و تمام اتصالات در حال استفاده باشند، کلاینت تا کاهش تعداد اتصالات استفاده‌شده صبر می‌کند….

مثال‌ها

کاربر می‌تواند عملیات‌ها را در ریسمان‌های مختلف به چند روش اجرا کند. این روش‌ها به دو نوع تقسیم می‌شوند:

1. کاربر از متدهای ناهمزمان (Begin/End) تعریف شده در کلاینت استفاده می‌کند. در این حالت کلاینت ایمیل وقتی نیاز باشد ریسمان‌های جدیدی راه‌اندازی می‌کند. در کلاینت یک صف وظایف پیاده‌سازی شده است (لطفاً آن را با صف دستورات در اتصال اشتباه نگیرید). یک وظیفه می‌تواند اجرا شود اگر اتصال در دسترس باشد. زمانی که تعداد اتصالات استفاده‌شده کمتر از مقدار محدودیت می‌شود، کلاینت یک اتصال جدید ایجاد می‌کند، ریسمان برای وظیفه فعلی می‌سازد و این وظیفه را اجرا می‌کند. مثال استفاده از عملیات‌های ناهمزمان:

۲. کاربر می‌تواند با استفاده از اشیائی مانند Thread، ThreadPool، Task یا هر شیء دیگری برای این منظور، رشته‌ها (threads) ایجاد کند. همچنین کاربر می‌تواند از رشته‌های ایجاد شده در کدهای شخص ثالث استفاده کند. در این حالت، کلاینت دو مدل رفتار دارد

a. اگر کاربر ایجاد اتصالات اضافه برای عملیات در ریسمان را در نظر نگرفته باشد، تمام عملیات‌های این ریسمان به صف دستورات برای اتصال اصلی ارسال می‌شوند. یک مثال از عملیات‌ها در یک ریسمان اضافه بدون ایجاد اتصال جدید، تمام تراکنش‌ها از طریق اتصال اصلی انجام می‌شود:

b. وقتی کاربر متدی را اجرا می‌کند تا اتصال جدیدی برای ریسمان اضافه ایجاد کند، این ریسمان تا زمانی که مقدار سهمیه برای اتصالات جدید تغییر کند مسدود می‌شود تا اتصال جدید مجاز شود. سپس اتصال جدید ایجاد می‌شود. این اتصال به عنوان اتصال پیش‌فرض برای تمام عملیات‌ها در این ریسمان تنظیم می‌گردد. پس از اتمام تمام عملیات‌ها در این ریسمان، باید اتصال را از بین برد. برای ایجاد اتصالات جدید از متد CredentialsByHostClient.CreateConnection استفاده کنید. این متد شی‌ای را برمی‌گرداند که اینترفیس IDisposable را پیاده‌سازی می‌کند. برای آزادسازی اتصال باید متد Dispose فراخوانی شود. ایجاد و از بین بردن اتصال باید در داخل ریسمانی که عملیات‌های ایمیل در آن اجرا می‌شود انجام شود. تلاش برای ایجاد اتصال جدید در ریسمانی که کلاینت ایمیل در آن ساخته شده است منجر به خطا می‌شود، زیرا این ریسمان در این لحظه نمی‌تواند برای ایجاد اتصال جدید استفاده شود. همچنین ایجاد اتصال جدید زمانی ممکن نیست که MaxConnectionsPerServer = 1 باشد. یک مثال کد برای ایجاد اتصال جدید در ریسمان اضافه:

پیشنهادات

شایان ذکر است که اگر کاربر تمام دستورات را به اتصال اصلی ارسال کند، ممکن است وضعیتی پیش آید که دستورات از ریسمان‌های متفاوت با هم مخلوط شوند. کاربر باید بفهمد که کدام دستورات به ترتیب خود وابسته هستند و برای همگام‌سازی این دستورات اقدامات لازم را انجام دهد. همچنین لازم است امکان اجرای دستورات در جلسات متفاوت (IMAP/POP3) در نظر گرفته شود. عملیات‌های پرهزینه زمانی، مانند FetchMessage، AppendMessage و Send. احتمالاً منطقی است که این عملیات‌ها را با ریسمان و اتصال جدید انجام داد. اما عملیات‌های سریع مانند Delete منطقی است که با اتصال اصلی انجام شوند. لطفاً توجه داشته باشید که مقداردهی اولیه اتصال جدید یک عملیات زمان‌بر است.