一共有六处需要解释
这是一个多线程扫描端口的程序
我想知道,这个程序在多线程扫描时,每个线程扫描的起始和结束端口是怎么处理的
注:NowWhere是个全局变量void CMyScanPortDlg::OnStart()
{
UpdateData(true);
if(m_threadnum<1)
{
AfxMessageBox("您至少需运行一个线程。");
return ;
}
DWORD dword=WaitForSingleObject(g_Busy,1000); //解释第一处
if(dword==WAIT_TIMEOUT)
{
AfxMessageBox("您只能同时执行一个程序");
ReleaseSemaphore(g_Busy,1,NULL);
return;
} GetDlgItem(IDC_STOP)->EnableWindow(true);
IsStop=false;
ReleaseSmp=false;
REPORT_SUCCEED=m_succeed; REPORT_FAILED=m_failed; NowWhere=m_startport;
BYTE a,b,c,d;
m_ipaddress.GetAddress(a,b,c,d);
g_message="";
threadparam1.a=a;
threadparam1.b=b;
threadparam1.c=c;
threadparam1.d=d;
threadparam1.EndPort=m_endport;
threadparam1.StartPort=m_startport;
threadparam1.hwnd=GetDlgItem(IDC_MESSAGE)->GetSafeHwnd();
for(int i=0;i<m_threadnum;i++)
AfxBeginThread(MyThread,&threadparam1,THREAD_PRIORITY_IDLE); //解释第二处
}UINT MyThread(LPVOID pParam)
{
THREADPARAM* threadparam=(THREADPARAM*)pParam;
sockaddr_in addr;
addr.sin_family=AF_INET;
addr.sin_addr.S_un.S_un_b.s_b1=threadparam->a;
addr.sin_addr.S_un.S_un_b.s_b2=threadparam->b; addr.sin_addr.S_un.S_un_b.s_b3=threadparam->c; addr.sin_addr.S_un.S_un_b.s_b4=threadparam->d; for(int i=threadparam->StartPort;(i<threadparam->EndPort)&&(!IsStop)&&(NowWhere<=threadparam->EndPort);i++)
{
SOCKET sck_Conn; sck_Conn=socket(AF_INET,SOCK_STREAM,0);
if(sck_Conn==INVALID_SOCKET)
{
return 0;
} criticalSection.Lock(); //解释第三处
i=NowWhere;
NowWhere++;
criticalSection.Unlock(); //解释第四处 addr.sin_port=htons(i);
sck_Conn=socket(AF_INET,SOCK_STREAM,0);
if(sck_Conn==INVALID_SOCKET)
{
return 0;
}
int ddd=connect(sck_Conn,(sockaddr*)&addr,sizeof(addr));
CString aa="";
char buffer[80];
strcpy(buffer,"");
if(ddd==SOCKET_ERROR)
{
if(REPORT_FAILED)
aa.Format("failed! port:%d\r\n",i);
}
else
{
if(REPORT_SUCCEED)
aa.Format("succeed! port:%d\r\n",i);
}
PORTPARAM *portparam=new PORTPARAM;
portparam->a=threadparam->a;
portparam->b=threadparam->b;
portparam->c=threadparam->c;
portparam->d=threadparam->d;
portparam->hwnd=threadparam->hwnd;
portparam->iPort=i; AfxBeginThread(GetPortMessage,portparam,THREAD_PRIORITY_IDLE);//解释第五处
closesocket(sck_Conn);
if(g_message.GetLength()>30000)
g_message="";
g_message=aa+g_message; //CString aa="";
if(i==threadparam->EndPort)
{
g_message="scan port complete!\r\n\r\n"+g_message;
}
::SetWindowText(threadparam->hwnd,g_message);
}//for循环结束 if(!ReleaseSmp)
{
if(ReleaseSemaphore(g_Busy,1,NULL)) //解释第六处
ReleaseSmp=true;
}
return 0;
}
这是一个多线程扫描端口的程序
我想知道,这个程序在多线程扫描时,每个线程扫描的起始和结束端口是怎么处理的
注:NowWhere是个全局变量void CMyScanPortDlg::OnStart()
{
UpdateData(true);
if(m_threadnum<1)
{
AfxMessageBox("您至少需运行一个线程。");
return ;
}
DWORD dword=WaitForSingleObject(g_Busy,1000); //解释第一处
if(dword==WAIT_TIMEOUT)
{
AfxMessageBox("您只能同时执行一个程序");
ReleaseSemaphore(g_Busy,1,NULL);
return;
} GetDlgItem(IDC_STOP)->EnableWindow(true);
IsStop=false;
ReleaseSmp=false;
REPORT_SUCCEED=m_succeed; REPORT_FAILED=m_failed; NowWhere=m_startport;
BYTE a,b,c,d;
m_ipaddress.GetAddress(a,b,c,d);
g_message="";
threadparam1.a=a;
threadparam1.b=b;
threadparam1.c=c;
threadparam1.d=d;
threadparam1.EndPort=m_endport;
threadparam1.StartPort=m_startport;
threadparam1.hwnd=GetDlgItem(IDC_MESSAGE)->GetSafeHwnd();
for(int i=0;i<m_threadnum;i++)
AfxBeginThread(MyThread,&threadparam1,THREAD_PRIORITY_IDLE); //解释第二处
}UINT MyThread(LPVOID pParam)
{
THREADPARAM* threadparam=(THREADPARAM*)pParam;
sockaddr_in addr;
addr.sin_family=AF_INET;
addr.sin_addr.S_un.S_un_b.s_b1=threadparam->a;
addr.sin_addr.S_un.S_un_b.s_b2=threadparam->b; addr.sin_addr.S_un.S_un_b.s_b3=threadparam->c; addr.sin_addr.S_un.S_un_b.s_b4=threadparam->d; for(int i=threadparam->StartPort;(i<threadparam->EndPort)&&(!IsStop)&&(NowWhere<=threadparam->EndPort);i++)
{
SOCKET sck_Conn; sck_Conn=socket(AF_INET,SOCK_STREAM,0);
if(sck_Conn==INVALID_SOCKET)
{
return 0;
} criticalSection.Lock(); //解释第三处
i=NowWhere;
NowWhere++;
criticalSection.Unlock(); //解释第四处 addr.sin_port=htons(i);
sck_Conn=socket(AF_INET,SOCK_STREAM,0);
if(sck_Conn==INVALID_SOCKET)
{
return 0;
}
int ddd=connect(sck_Conn,(sockaddr*)&addr,sizeof(addr));
CString aa="";
char buffer[80];
strcpy(buffer,"");
if(ddd==SOCKET_ERROR)
{
if(REPORT_FAILED)
aa.Format("failed! port:%d\r\n",i);
}
else
{
if(REPORT_SUCCEED)
aa.Format("succeed! port:%d\r\n",i);
}
PORTPARAM *portparam=new PORTPARAM;
portparam->a=threadparam->a;
portparam->b=threadparam->b;
portparam->c=threadparam->c;
portparam->d=threadparam->d;
portparam->hwnd=threadparam->hwnd;
portparam->iPort=i; AfxBeginThread(GetPortMessage,portparam,THREAD_PRIORITY_IDLE);//解释第五处
closesocket(sck_Conn);
if(g_message.GetLength()>30000)
g_message="";
g_message=aa+g_message; //CString aa="";
if(i==threadparam->EndPort)
{
g_message="scan port complete!\r\n\r\n"+g_message;
}
::SetWindowText(threadparam->hwnd,g_message);
}//for循环结束 if(!ReleaseSmp)
{
if(ReleaseSemaphore(g_Busy,1,NULL)) //解释第六处
ReleaseSmp=true;
}
return 0;
}
关键段是用于互斥的内核对象,当一个线程进入关键段之后,其他线程将无法进入关键段,而是挂起,直到前者离开关键段。这样,对于一些共享数据的访问就可以实现互斥了。5 和2一样6 信号量减一。你学过操作系统,对PV操作就一定不陌生。作为线程池的类似实现,通讯原语是必要的。这里的信号量,就类似于PV操作,直到所有的线程都停止,信号量才会变成0,你才有可能执行一次新的扫描,参见1。很高兴你能信任我,让我来解释这段代码中对几个内核对象的调用,不知道上面的解释你是不是满意:)
哈 我看了一些帖子,觉得你挺棒的,解释的不错
我对这个程序的理解(你看对不对):
第二处 假如m_threadnum为10,这里要创建10个线程
for(int i=0;i<m_threadnum;i++)
AfxBeginThread(MyThread,&threadparam1,THREAD_PRIORITY_IDLE);每个线程去执行MyThread函数,通过参数threadparam1 赋值给threadparam
THREADPARAM* threadparam=(THREADPARAM*)pParam
我的问题:
然后--这里循环时,每个线程扫描的起始和结束端口是怎么确定的呢?
for(int i=threadparam->StartPort;(i<threadparam->EndPort)&&(!IsStop)&&(NowWhere<=threadparam->EndPort);i++)能保证多个线程同步对端口进行扫描吗?
criticalSection.Lock(); // 进入关键段
i = NowWhere;
NowWhere++;
criticalSection.Unlock(); // 离开关键段
addr.sin_port = htons(i);巧妙的地方就在这里,通过互斥的递增NowWhere来决定当前扫描的是哪个端口。
在这个程序里面,哪一个线程扫描哪一个端口并不一定,而是每个线程进入关键段,NowWhere就是下一个要扫描的端口,拿过来扫描,同时把NowWhere加一。因为同一时间只能有一个线程进入关键段,因此端口不会被重复扫描。
你可以进一步了解的是关键段的相关知识,加深对这段代码的理解。
:)g_Busy是一个全局变量,它是一个Semaphore(信号量)对象的句柄。信号量作为内核对象,起计数器的作用,当计数器达到0的时候,自动设为Singned状态。这里,是要等到信号量置零g_Busy是对哪个资源起到信号量的作用criticalSection.Lock(); // 进入关键段
这个是对哪个资源的锁定?