PDA

View Full Version : سوال: دريافت بلادرنگ! از شبكه



Moharram
چهارشنبه 21 تیر 1391, 09:31 صبح
سلام
يه سخت افزار دارم كه برام يه شمارنده از طريق شبكه ميفرسته و پس از دريافت براي اطمينان از صحت دريافت، اون شمارنده رو چك ميكنم تا ببينم چيزي گم شده يا نه ...
تو بخش سخت افزار يه حافظه اي وجود داره كه ديتا توي اون ريخته ميشه. اين حافظه رو ويندوز ميخونه و بعنوان ديتاي دريافتي از شبكه تحويل ميده.
تو بخش نرم افزار يه برنامه ساده نوشتم. به اين صورت كه يه كلاس از CAsyncSocket مشتق كردم و براي OnReceive اون تابع نوشتم. هر وقت كه رويداد OnReceive فعال بشه ميرم و ديتا رو برميدارم.
ويندوز ممكنه اون حافظه سخت افزار رو نرسه خالي بكنه، واسه همين تو سخت افزار پر بودن حافظه رو چك ميكنم. مثلا اگه پر باشه يعني فعلا نميشه ديتايي فرستاد، بنابراين شمارنده مون رو افزايش نميدم و منتظر ميشيم تا حافظه جاي خالي پيدا كنه.
تا اينجا همه چي درسته و ديتا رو با سرعت 900Mbps دريافت ميكنم بدون گم شدگي ...!!! محاسبه سرعت رو به اين صورت انجام ميدم كه تو يه بازه زماني ديتاي دريافتي رو تقسيم بر زمان ميكنم ...

اما ...

ميخوام برنامه همزمان بشه. يعني فرض كنيم كه به جاي شمارنده ميخواهيم نمونه هاي يه مبدل ADC رو بفرستيم. يعني اين بار نميتونيم مثل حالت شمارنده، وقتي اون حافظه پر شد، دست نگه داريم تا جاي خالي پيدا شه وگرنه ديتا از دست ميره.
دريافت ديتا رو مثل قبل انجام دادم. تا وقتي تو برنامه روي مثلا Title كليك نكنيم تا يه جايي ديتا درست مياد. اما انگار خيلي وابسته به ويندوزه و با يك كليك رو GUI اون حافظه پر ميشه و همين كافيه كه ديتا رو از دست بديم.

سعي كردم خوندن از شبكه رو توي يه Thread، انجام بدم تا مستقل از GUI بشه اما بهتر نشد.

اصلا نميدونم ميشه با شبكه و سوكت چنين انتقال همزماني رو انجام داد يا نه؟ نميدونم شايد هم توي موازي سازي اشتباهي كردم؟

منتظر راهنمايي دوستان هستم
با تشكر از توجهتون

mohamad.zakery
یک شنبه 25 تیر 1391, 01:49 صبح
سلام سوالتون مفهوم نیست!!!
ولی نمیدونم برداشتم درست هست یا نه، فکر می کنم شما برنامه تون زمانی که بصورت موازی اجرا میشه به مشکل میخوره! درست برداشت کردم یا نه؟

اگر مشکل اینه، که این فقط مشکل شما نیست!!! مشکل کلاسیک که قدیم یه صورت بود امروز یک صورت دیگه!!!
مشکل در تئوری بنام ناحیه بحرانی یا منابع مشترک شناخته میشه!!

راه حل های کلاسیکی داره مثل:

Mutex
Semaphore
TimedObject
این ها همشون در Win32 بصورت Win Api پیاده سازی دارن به غیر از Semaphor که نیاز به اجرا شدن بصورت اتمیک داره

خیلی سادست!!

مثلا تابع WaitForSignal یک نمونشه که با Mutex کار میکنه!!!


شما زمانیکه بصورت پارالل یا موازی کد مینویسین با به فکر منابع مشترک باشین که داده لوز یا دچار تغییر اشتباه نشه!!!!


این ها رو چک کنید، انشالله درست میشه

از سبک نوشتنتون معلوم با سخت افزار آشنایی دارین
اگر با سخت افزار و الکترونیک هم آشنا باشید میدونین که با پالس هم این مشکل حل میشه.

Moharram
سه شنبه 03 مرداد 1391, 17:55 عصر
تو حالتي كه با Thread ديتا رو ميخونيم يه مقدار بهتره و ديرتر شروع به گم شدن ديتا ميكنه.

اينجا ديگه از CAsyncSocket استفاده نكردم. روش كارش اينجوريه كه تو يه پروژه MFC اين متغيرهاي كلاس رو تعريف ميكنيم:



struct sockaddr_in m_DestinationAddress;
SOCKET m_ServerSock;
HANDLE hRecThread;


كد مربوط به Connect شدن هم اين شكليه:



void CSendReceive_LANDlg::OnButton5()
{
// TODO: Add your control notification handler code here
m_DestinationAddress.sin_family = AF_INET;
m_DestinationAddress.sin_port = htons(20482);
m_DestinationAddress.sin_addr.S_un.S_addr=inet_add r("192.168.1.111");

if((m_ServerSock = ::socket(AF_INET,SOCK_STREAM,0)) == INVALID_SOCKET)
{
MessageBox(_T("Can't open socket!"), _T("Send Receive LAN"), MB_ICONERROR|MB_OK);
return ;
}
if (connect (m_ServerSock, (PSOCKADDR) &m_DestinationAddress, sizeof (m_DestinationAddress)) == SOCKET_ERROR)
{
MessageBox(_T("Can't connect to Board!"), _T("Send Receive LAN"), MB_ICONERROR|MB_OK);
closesocket (m_ServerSock);
return ;
}

GetDlgItem(IDC_BUTTON2)->EnableWindow();
GetDlgItem(IDC_BUTTON3)->EnableWindow();

// run save thread
hRecThread = CreateThread(NULL, 0, RecThread, this, 0, NULL);
SetThreadPriority(hRecThread, /*THREAD_PRIORITY_NORMAL*/THREAD_PRIORITY_TIME_CRITICAL);
SetThreadAffinityMask(hRecThread,0x8);
}


تابع مربوط به Thread:



DWORD WINAPI RecThread(LPVOID lpParameter)
{
((CSendReceive_LANDlg*)lpParameter)->RecLoop();
return 0;
}

char rbuffer[5*1024*1024];
void CSendReceive_LANDlg::RecLoop()
{
int len,rlen;

len=5*1024*1024;

while(TRUE)
{
rlen=recv(m_ServerSock, rbuffer, len, 0);

}

}


همونطور كه گفتم، دريافت ديتا اينجوري خيلي بهتر شده، اما باز وقتي زياد با GUI كار داشته باشيم يا مثلا تو ويندوز Alt+Tab بزنيم و برنامه پشتي بياد جلو، دريافت خراب ميشه!!!