DWORD dwListenThreadId;
hThread[0] = CreateThread(NULL, 0, ListenThread, NULL, 0, &dwListenThreadId);
DWORD dwWorkThreadId;
hThread[1] = CreateThread(NULL, 0, WorkThread, NULL, 0, &dwWorkThreadId);
DWORD dwLogicThreadId;DWORD WINAPI CServerDlg::ListenThread(LPVOID)
{

WSADATA wsaData; int nRet; nRet=WSAStartup(MAKEWORD(2,2),&wsaData);                      
if(nRet!=0)
{
AfxMessageBox("Load winsock2 failed");
WSACleanup();
return -1;
}

SOCKET sockListen;
sockListen = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);             //创建服务套接字(TCP)

if(sockListen == INVALID_SOCKET)
{
AfxMessageBox("Create Listening Socket Fail!");
}

// BOOL bReuseaddr=TRUE;
// setsockopt(sockListen,SOL_SOCKET ,SO_REUSEADDR,(const char*)&bReuseaddr,sizeof(BOOL)); SOCKADDR_IN ServerAddr;                                           //分配端口及协议族并绑定 ServerAddr.sin_family=AF_INET;                                
ServerAddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);          
ServerAddr.sin_port=htons(DE_PORT); nRet=bind(sockListen,(LPSOCKADDR)&ServerAddr,sizeof(ServerAddr)); // 绑定套接字 if(nRet==SOCKET_ERROR)
{
AfxMessageBox("Bind Socket Fail!");
closesocket(sockListen);
WSACleanup();
return -1;
} nRet=listen(sockListen,1);                                        //开始监听,并设置监听客户端数量
if(nRet==SOCKET_ERROR)     
{
AfxMessageBox("Listening Fail!");
return -1;
} SOCKADDR_IN ClientAddr;                                  // 定义一个客户端得地址结构作为参数
int addr_length=sizeof(ClientAddr);
while(true)
{
if(bThreadRun)
{
sockNew = accept(                            // 接收连入的客户端
sockListen,
(SOCKADDR*)&ClientAddr,
&addr_length
);  if(sockNew  == INVALID_SOCKET)                       // 检测SOCKET是否有效
{
AfxMessageBox("Accept Connection failed!");

continue;
} CString strSock;

strSock.Format("SOCKET编号:%d",sockNew); ::SendMessage(
hWnd,
WM_MSG_NEW_SOCKET,
(LPARAM)(LPCTSTR)strSock,
(LPARAM)(LPCTSTR)"连接到服务器"
);
bNewSocket = TRUE; 
}
else
{
break;
}
}
return 0;
}
DWORD WINAPI CServerDlg::WorkThread(LPVOID)
{
LPPER_IO_OPERATION_DATA lpPerIOData = NULL; while(true)
{
if(bThreadRun)
{
if(bNewSocket)
{
lpPerIOData = (LPPER_IO_OPERATION_DATA)HeapAlloc(
GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(PER_IO_OPERATION_DATA));
lpPerIOData->Buffer.len = SZ_HEAD;
lpPerIOData->Buffer.buf = lpPerIOData->szMessage;
lpPerIOData->sClient = sockNew;
lpPerIOData->nTotal = 0;
lpPerIOData->str = ""; //投递接收请求
if(WSARecv(lpPerIOData->sClient,
 &lpPerIOData->Buffer,
 1,
 &lpPerIOData->NumberOfBytesRecvd,
 &lpPerIOData->Flags,
 &lpPerIOData->overlap,
 CompletionROUTINE) == SOCKET_ERROR)
{
//接收函数失败,释放内存
if(WSAGetLastError() != WSA_IO_PENDING)
{
closesocket(lpPerIOData->sClient);
HeapFree(GetProcessHeap(), 0, lpPerIOData);
AfxMessageBox("WSARecv函数失败!");
continue;
}
}
bNewSocket = false;
} SleepEx(1000, TRUE);
}
else
break;
} return 0;
}下面UI按钮函数
void CServerDlg::OnCancel() 
{
bThreadRun = false;
::WaitForSingleObject(hThread[0],INFINITE);
::CloseHandle(hThread[0]);
::WaitForSingleObject(hThread[1],INFINITE);
::CloseHandle(hThread[1]);
closesocket(sockNew);
WSACleanup();

CDialog::OnCancel();
}
不知道为什么线程就是不退出,一点击退出按钮,程序就没有反应了,难道是accept阻塞了线程?请各位大侠帮忙!!!

解决方案 »

  1.   

    如果是同步socket,accept当然会阻塞线程啊。
    除了使用异步socket之外,一种比较粗暴的做法是在关闭时,让另一个线程把server socket给强行close掉,那样一来,accept应该就回返回了。 
      

  2.   

    看样子确实是某个线程被阻塞了。INFINITE就是一直等到它结束位置,其实可以改成等待的时间。而且WaitForSingleObject可以使用WaitForMultipleObject来把2个线程合起来写。至于这个函数用法在Google上搜,很多。