چگونه در ویندوز بفهمیم کدام فرایند یک پورت را گرفته است؟
روش عملی یافتن PID پشت پورت در ویندوز: netstat -ano، Get-NetTCPConnection، اتصال به Get-Process و آزاد کردن پورت بدون ریبوت.
بنیانگذار و مهندس محصول

پیامهایی شبیه address already in use یا فقط Unable to bind به پورت ۳۰۰۰، ۵۰۰۰ یا ۷۲۲۸ معمولاً یک معنی دارند: فرایند دیگری روی همان پورت listen میکند یا در حالتی گیر کرده که کرنل هنوز پورت را آزاد نکرده است. ریبوت کار میکند، ولی کند و غیرحرفهای است. راه درست: PID را پیدا کنید، صاحبش را بشناسید، بعد آگاهانه تصمیم بگیرید.
این مقاله دو مسیر رسمی را پوشش میدهد: netstat و Get-NetTCPConnection، سپس اتصال به Get-Process و نکات UDP، مجوز، و زمانهایی که پورت آزاد به نظر میرسد ولی نیست.

پاسخ کوتاه
با netstat -ano پورت را پیدا و PID را بخوانید، یا در PowerShell از Get-NetTCPConnection -LocalPort استفاده کنید و OwningProcess را به Get-Process بدهید. وقتی مطمئن شدید فرایند مال شماست، با Stop-Process متوقفش کنید و دوباره وضعیت listen را چک کنید. اگر سرویس است، Stop-Service مناسبتر است.
اول مالک را بشناس، بعد بکش. کشتن PID اشتباه یعنی از دست دادن کار ذخیرهنشده یا قطع سرویس حیاتی.
چرا این مشکل اینقدر تکرار میشود؟
- سرور توسعه در پسزمینه مانده و ترمینال بسته شده.
- دو پروژه با پورت پیشفرض یکسان.
- IDE یا debugger نمونهٔ قبلی را رها نکرده.
- سرویس ویندوزی (دیتابیس، IIS) همان پورت را گرفته.
در هر چهار حالت، ابزار یکی است؛ فقط تصمیم بعد از شناسایی فرق میکند.
روش ۱: netstat
netstat ابزار کلاسیک ویندوز برای اتصالات و پورتهای گوشدهنده است. پارامتر -a همه را نشان میدهد، -n عدد خام میدهد، -o PID را اضافه میکند. برای نام اجرایی، -b نیاز به ارتفاع مجوز دارد و خروجی شلوغتری میسازد.
cmd
netstat -ano | findstr :3000
در خروجی به ستون State و PID دقت کنید. حالت LISTENING همان چیزی است که معمولاً جلوی bind جدید را میگیرد. سپس:
cmd
tasklist /FI "PID eq 12345"
powershell
netstat -ano | findstr :3000
مستند رسمی netstat پارامترها را دقیق شرح میدهد؛ برای عیبیابی TCP، ترکیب -ano رایجترین است.
روش ۲: Get-NetTCPConnection
در PowerShell مدرن، خروجی ساختیافتهتر است و پایپ مستقیم به Get-Process میخورد:
powershell
Get-NetTCPConnection -LocalPort 3000 -ErrorAction SilentlyContinue | Select-Object LocalAddress,LocalPort,State,OwningProcess
powershell
$p = (Get-NetTCPConnection -LocalPort 3000 -State Listen -ErrorAction SilentlyContinue).OwningProcess if ($p) { Get-Process -Id $p | Select-Object Id,ProcessName,Path }
اگر چند ردیف دیدید، روی State=Listen تمرکز کنید. اتصالهای Established داستان کلاینت/سرور فعالاند و لزوماً مانع bind روی همان پورت listen نمیشوند — هرچند جزئیات stack پیچیدهتر است.
آزاد کردن پورت
powershell
Stop-Process -Id $p # اگر جواب نداد: Stop-Process -Id $p -Force
سپس تأیید:
powershell
Get-NetTCPConnection -LocalPort 3000 -ErrorAction SilentlyContinue
اگر خالی بود، دوباره سرور را بالا بیاورید. اگر PID به سرویس تعلق داشت:
powershell
Get-CimInstance Win32_Service | Where-Object { $_.ProcessId -eq $p }
در آن صورت Restart-Service یا Stop-Service را بررسی کنید نه فقط kill.
UDP چطور؟
بعضی ابزارها روی UDP گوش میدهند. Get-NetUDPEndpoint یا netstat با فیلتر UDP مسیر موازی است. الگوی فکری همان است: پورت محلی → PID → فرایند.
powershell
Get-NetUDPEndpoint -LocalPort 5353 -ErrorAction SilentlyContinue | Select-Object LocalAddress,LocalPort,OwningProcess
جدول عیبیابی سریع
| نشانه | احتمال | اقدام |
|---|---|---|
| Listen روی پورت با PID اپ خودتان | instance قبلی | Stop-Process |
| Listen با نام sql/iis/nginx | سرویس زیرساخت | Services / Stop-Service |
| هیچ Listen نیست ولی bind شکست | مجوز، فایروال، یا پورت دیگر | آدرس bind و دسترسی را چک کنید |
| نیاز به -b در netstat | دیدن exe | ترمینال Elevated |
| PID=0 یا رفتار عجیب | مورد خاص سیستم | مستند و احتیاط؛ ریبوت آخرین |
دامهای رایج
- جستجوی پورت بدون دونقطه در findstr و گرفتن ردیفهای نامرتبط.
- کشتن همهٔ فرایندهای همنام بهجای PID مشخص.
- فرض IPv4 وقتی اپ روی [::1] گوش میدهد یا برعکس.
- نگاه نکردن به LocalAddress؛ 127.0.0.1 با 0.0.0.0 فرق کاربردی دارد.
- فراموش کردن اینکه آنتیویروس/فایروال گاهی علائم گمراهکننده میسازد.
پیشگیری در جریان کار توسعه
- برای هر پروژه پورت منحصربهفرد در مستند README بگذارید.
- اسکریپت stop را کنار start در package.json یا Make نگه دارید.
- در IDE از Stop واقعی debugger استفاده کنید نه فقط بستن تب.
- اگر از سرویس ویندوزی برای دیتابیس استفاده میکنید، وضعیت سرویس را بخشی از checklist صبحگاهی کنید.
سوالات متداول
چرا netstat چیزی نشان نمیدهد ولی پورت اشغال است؟
شاید پورت را اشتباه تایپ کردهاید، یا پروتکل UDP است، یا فرایند بسیار زودگذر. فیلتر و ابزار را عوض کنید و Exact port را تأیید کنید.
آیا Resource Monitor هم کافی است؟
بله، تب Network در Resource Monitor دید UI میدهد. برای اسکریپت و تکرار، PowerShell بهتر است.
در CI هم همین فرمانها؟
روی Agent ویندوزی بله؛ فقط مطمئن شوید ماژول شبکه و مجوز لازم موجود است.
اگر راهحل شما تغییر سطح Machine بود، بگویید چرا User کافی نبود. اگر Force کردید، بگویید چرا توقف ملایم شکست. این انضباط کوچک کیفیت عملیاتی تیم را بالا میبرد.
قبل از اینکه مشکل را بستهشده اعلام کنید: نشست جدید را تست کنید، مسیر یا پورت یا سرویس را دوباره با ابزار ساختیافته تأیید کنید، و یک خط در یادداشت تیمی بنویسید که علت ریشهای چه بود. بدون این سه قدم، همان تیکت هفتهٔ بعد برمیگردد.
چکلیست پایانی قبل از بستن تیکت
سه خط فرمان استاندارد تیم برای پورتهای رایج را در README بگذارید. وقتی عضو جدید با EADDRINUSE روبهرو میشود، نباید از صفر جستجو کند. همین استاندارد کوچک، تیکتهای تکراری را کم میکند.
ثبت در runbook تیم
در کانتینر یا WSL، پورت ممکن است از دید ویندوز میزبان یا از دید لینوکس داخل متفاوت دیده شود. مشخص کنید مشکل کدام لایه است؛ وگرنه PID اشتباه را در لایهٔ غلط میکشید.
اگر سرویس بازیابی خودکار دارد، Stop-Process فقط لحظهای است و دوباره برمیگردد. اگر سوکت در TIME_WAIT گیر کرده باشد، رفتار متفاوت است و معمولاً با صبر کوتاه یا تغییر پورت موقت حل میشود نه با ریبوت فوری.
زمانهایی که kill کافی نیست
گاهی چند سرویس پشت یک پورت با سیاست جدا هستند؛ یا پراکسی محلی پورت را گرفته. نام فرایند را با Path تأیید کنید نه فقط با عدد پورت در مستند قدیمی.
اپ ممکن است فقط روی 127.0.0.1 گوش بدهد یا روی 0.0.0.0 یا روی ::. اگر فقط یک شکل را در فیلتر ببینید، ممکن است اشتباهاً فکر کنید پورت آزاد است. خروجی Get-NetTCPConnection را کامل بخوانید و LocalAddress را جدی بگیرید.
IPv4 و IPv6 و آدرس گوشدادن
نسخهبندی اسکریپتهای عیبیابی را جدی بگیرید. یک gist شخصی یا پوشه در ریپو داخلی با تاریخ و پیشفرضهای ایمن، بهتر از حافظهٔ شفاهی است.
مستند رسمی را نخواندن و اعتماد به اولین نتیجهٔ جستجو، اجرای همیشگی Elevated، و تغییر Machine برای مشکل User، سه الگوی پرهزینهاند. هزینهٔ واقعیشان معمولاً ساعتها بعد معلوم میشود؛ وقتی محیط برای همکار یا CI میشکند.
اشتباههای سطح بالاتر
در پایان تمرین، همه چیز را به حالت اول برگردانید: فرایند تست را ببندید، متغیر موقت را رها کنید، و سرویس را اگر تغییر دادید به Startup Type قبلی برگردانید. پاکسازی بخشی از حرفهایگری است.
یک سرور محلی بالا بیاورید، پورتش را پیدا کنید، فرایند را بشناسید، یک متغیر محیطی موقت ست کنید، PATH را فقط مشاهده کنید بدون تغییر مخرب، وضعیت یک سرویس بیخطر را بخوانید، و پنج رویداد اخیر Application را ببینید. این مدار بسته، دانش را از حالت خواندنی به حالت عضلانی میبرد.
تمرین پیشنهادی سیدقیقهای
اگر از لینوکس آمدهاید، معادل ذهنی بسازید ولی فرمان را عیناً ترجمه نکنید. مدل سرویس ویندوز با systemd شباهت مفهومی دارد و تفاوت ابزاری. مدل env با export شباهت دارد و تفاوت سطح Machine و User.
مفاهیم این مقاله را با Terminal، PowerShell، فرایند، پورت، env، PATH، سرویس و Event Viewer بهصورت حلقه ببینید نه جزایر جدا. بیشتر تیکتهای واقعی دو یا سه حلقه از این زنجیره را درگیر میکنند.
ارتباط با بقیهٔ سری ویندوز
تفاوت محیط خانگی و لپتاپ سازمانی را دستکم نگیرید. آنتیویروس، پروکسی، و سیاست اجرای اسکریپت رفتار ابزارها را عوض میکنند. اگر فقط روی یک ماشین تست میکنید، نتیجه را حقیقت مطلق ندانید.
هر بار که راهحل موقتی پیدا میکنید، همان را به یک فرمان قابلکپی در یادداشت شخصی تبدیل کنید. هفتهٔ بعد همان فرمان را از حافظه نمینویسید؛ از دفترک میآورید و خطا کمتر میشود.
در کار واقعی، مشکلها ترکیبیاند: پورت اشغال، PATH کهنه، سرویس متوقف، و ترمینال با پروفایل غلط همزمان ظاهر میشوند. بهجای تغییر همزمان همه چیز، یک متغیر را ثابت نگه دارید و فقط یک فرض را آزمایش کنید. این نظم علمی سرعت عیبیابی را بیشتر از هر میانبر افزایش میدهد.
عمق عملی بیشتر برای کار روزانه
تغییرات Machine، سیاست دامنه، و آنتیویروس مرکزی معمولاً خارج از اختیار شماست. آنچه در اختیار شماست: پروفایل Terminal، اسکریپت User، انتخاب پورت پروژه، و خواندن لاگ. روی لایهٔ قابلکنترل تمرکز کنید و برای بقیه تیکت شفاف با شاهد بسازید.
مرز مسئولیت توسعهدهنده و IT
اگر وسط راه مجبور به Force شدید، بعداً علت را پیدا کنید که چرا توقف ملایم کار نکرد: قفل فایل، انتظار شبکه، یا بنبست رشتهها. Force بدون یادگیری، همان مشکل را تکرار میکند.
در هر مرحله یک شاهد بنویسید: خروجی کوتاه فرمان یا Event ID. وقتی از کسی کمک میگیرید، شاهد بهتر از توصیف احساسی است. همین عادت در تیمهای دورکاری ارزش دوچندان دارد.
فرض کنید بعد از ریبوت، API محلی بالا نمیآید. اول وضعیت سرویس وابسته را بخوانید، بعد پورت را با Get-NetTCPConnection چک کنید، بعد PATH و متغیرهای لازم اپ را در همان نشست تأیید کنید، و در نهایت اگر سرویس fail شده Event Viewer را روی زمان بوت فیلتر کنید. این ترتیب از پراکنده کاری جلوگیری میکند.
سناریوی ترکیبی که باید یکبار کامل بروید
یکبار این مسیر را روی پورت واقعی پروژهٔ خودتان از ابتدا تا تأیید نهایی اجرا کنید تا فرمانها در حافظهٔ عضلانی بنشینند؛ خواندن بدون اجرا برای این مهارت کافی نیست و در فشار تیکت فراموش میشود.
خلاصه
برای پیدا کردن صاحب پورت در ویندوز: netstat -ano یا Get-NetTCPConnection، خواندن PID، تطبیق با Get-Process، سپس توقف آگاهانه. ریبوت را برای وقتی بگذارید که مالک سیستمسطح و ناشناخته است و زمان ندارید. این مهارت کوچک، ساعتها انتظار بیهوده را حذف میکند.
منابع و مراجع
- Microsoft Learn — netstat — https://learn.microsoft.com/windows-server/administration/windows-commands/netstat
- Microsoft Learn — Get-NetTCPConnection — https://learn.microsoft.com/powershell/module/nettcpip/get-nettcpconnection
- Microsoft Learn — Get-NetUDPEndpoint — https://learn.microsoft.com/powershell/module/nettcpip/get-netudpendpoint
- Microsoft Learn — Get-Process — https://learn.microsoft.com/powershell/module/microsoft.powershell.management/get-process
- Microsoft Learn — TCP/IP connectivity troubleshooting — https://learn.microsoft.com/troubleshoot/windows-client/networking/tcp-ip-connectivity-issues-troubleshooting
نویسنده
سهیل ابراهیمپور بنیانگذار FutureForge است. روی طراحی محصول، معماری و استقرار نرمافزار سفارشی کار میکند.
یادداشتهای مرتبط
اگر در انتخاب معماری یا مسیر توسعه مطمئن نیستید، میتوانید درباره پروژه صحبت کنیم.
مسئله و محدودیت را بنویسید. اگر تطابق داشته باشیم، برای گفتگو هماهنگ میکنیم.




