读书人

vc socket采用异步多线程有关问题请

发布时间: 2012-01-08 22:48:50 作者: rapoo

vc socket采用异步多线程问题,请高手帮忙解答?
我要完成的是服务器端等待客户端连接,当有客户端请求连接时,服务器就建立一个线程来处理客户端的连接服务器继续等待其他客户端的连接。线程还要处理把客户端传来的数据存进数据库并把结果返回给客户端。客户端大概有六十个不间断的连接服务器。因我是新手初学者对socket 多线程不了解所以这个程序对我来说很难,请求大家高手们帮帮我谢谢。我写了一个大概请大家帮我改正完善它谢谢。
我采用异步多线程的方式,线程方面我不会写还请高手帮我。
以下是代码:

这部分是创建socket
void CServerDlg::OnButton1()
{
// TODO: Add your control notification handler code here
ADO.OnInitADOConn();
//初始化与绑定服务器
WSADATA wsaData;
int iErrorCode;
if (WSAStartup(MAKEWORD(2,1),&wsaData)) //调用Windows Sockets DLL
{
m_list.InsertString(0, "初始套接字失败! ");
WSACleanup();
return;
}

m_list.InsertString(0, "服务器开始创建SOCKET。 ");

ServerSocket=socket(PF_INET,SOCK_STREAM,0); //创建服务器端Socket,类型为SOCK_STREAM,面向连接的通信

if(ServerSocket == INVALID_SOCKET)
{
m_list.InsertString(0, "无法创建服务器socket! ");
WSACleanup();
return;
}

m_sockServerAddr.sin_family = AF_INET;
m_sockServerAddr.sin_addr.s_addr=inet_addr( "192.168.0.109 "); //INADDR_ANY; //向所有的IP地址发送消息
m_sockServerAddr.sin_port = htons(8001);

if (bind(ServerSocket,(LPSOCKADDR)&m_sockServerAddr,sizeof(m_sockServerAddr)) == SOCKET_ERROR) //与选定的端口绑定
{
m_list.InsertString(0, "无法绑定服务器。 ");
closesocket(ServerSocket);
WSACleanup();
return;
}

m_list.InsertString(0, "服务器端口:8001. ");

iErrorCode=WSAAsyncSelect(ServerSocket,m_hWnd,WM_CLIENT_ACCEPT,FD_ACCEPT);
// 产生相应传递给窗口的消息为WM_SERVER_ACCEPT ,这是自定义消息

if (iErrorCode == SOCKET_ERROR)
{
m_list.InsertString(0, "WSAAsyncSelect设定失败!——用于连接请求的消息 ");
return;
}

if (listen(ServerSocket,5) == SOCKET_ERROR) //开始监听客户连接请求
{
m_list.InsertString(0, "服务器监听失败! ");
return;
}

IsTrue = TRUE;

m_list.InsertString(0, "服务器绑定监听成功。 ");
GetDlgItem(IDC_BUTTON1)-> EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON2)-> EnableWindow(TRUE);
}
//这是关闭socket
void CServerDlg::OnButton2()
{
// TODO: Add your control notification handler code here
ADO.ExitConnect();
//当程序退出时,把SOCKET清空
closesocket(ServerSocket);
WSACleanup();
m_list.InsertString(0, "服务器停止! ");


GetDlgItem(IDC_BUTTON1)-> EnableWindow(TRUE);
GetDlgItem(IDC_BUTTON2)-> EnableWindow(FALSE);
}
//这是自定义连接事件
LRESULT CServerDlg::OnAccept(WPARAM wParam, LPARAM lParam)
{
//自定义接收客户机请求的消息 ON_MESSAGE(WM_CLIENT_ACCEPT,OnAccept)
if (WSAGETSELECTERROR(lParam))
{
m_list.InsertString(0, "Error detected on entry into OnServerAccept. ");
return 0L;
}

if(WSAGETSELECTEVENT(lParam) == FD_ACCEPT)//如果
{
Client = accept(ServerSocket,(LPSOCKADDR)&m_sockClientAddr,0);
//是不是在这里创建线程

AfxBeginThread(AcceptThreadProc,(LPVOID)&Client,0,0,0,NULL);

/* if (Client == INVALID_SOCKET)
{
m_list.InsertString(0, "Server socket failed to accept connection. ");
return 0L;
}
int len=sizeof(m_sockClientAddr);
getpeername( Client,(LPSOCKADDR)&m_sockClientAddr,&len);
CString add;
add=inet_ntoa(m_sockClientAddr.sin_addr);
m_list.InsertString(0,add+ "工作站连接上了服务器。 ");

WSAAsyncSelect(Client,m_hWnd,WM_CLIENT_READCLOSE,FD_READ|FD_CLOSE);

IsTrue = TRUE;*/
}

return 0L;
}
//这是自定义事件读和关闭
LRESULT CServerDlg::OnReadClose(WPARAM wParam, LPARAM lParam)
{
//自定义的关闭与缓冲区有消息
if(!IsTrue)
{
m_list.InsertString(0, "有数据到达,但是没有工作站连接。 ");
}

CString str;
switch (WSAGETSELECTEVENT(lParam))
{
case FD_READ:
{
if(recv(Client,(char *)&msg,sizeof(msg),0) == SOCKET_ERROR)
{
m_list.InsertString(0, "接收数据发生错误。 ");
return 0;
}
str.Format( "%s ",msg.msg);
m_list.InsertString(0,str);
/*_bstr_t sql= "select * from Act_Tickets where cTicketNum= ' "+str+ " ' ";
rs=ADO.GetRecordSet(sql);
int i=ADO.GetRecordCount(rs);
CString s;
if(i> 0){
s= "真票 ";
}else{
s= "没有此票信息 ";
}
strcpy(msg.msg,s);*/
int i=ADO.CallProc(str);
CString a;
a.Format( "%d ",i);
strcpy(msg.msg,a);
//AfxMessageBox(a);
send(Client,(char *)&msg,sizeof(msg),0);
break;
}
case FD_CLOSE:
CString add;
add=inet_ntoa(m_sockClientAddr.sin_addr);
str = _T( "工作站退出。 ");
m_list.InsertString(0,add+str);
closesocket(Client);
IsTrue = FALSE;
break;
}
return 0L;
}


//我写的线程函数不对不可以成为类成员函数不知怎么解决

//DEL UINT CServerDlg::AcceptThreadProc(LPVOID pParam)
//DEL {
//DEL SOCKET ClientSocket=(SOCKET)(LPVOID)pParam;
//DEL if (ClientSocket == INVALID_SOCKET)
//DEL {
//DEL m_list.InsertString(0, "Server socket failed to accept connection. ");
//DEL return 0L;
//DEL }
//DEL int len=sizeof(m_sockClientAddr);
//DEL getpeername( ClientSocket,(LPSOCKADDR)&m_sockClientAddr,&len);
//DEL CString add;
//DEL add=inet_ntoa(m_sockClientAddr.sin_addr);


//DEL m_list.InsertString(0,add+ "工作站连接上了服务器。 ");
//DEL //创建线程
//DEL //getpeername(ServerSocket,(struct sockaddr FAR *)&m_sockClientAddr,&len);
//DEL WSAAsyncSelect(Client,m_hWnd,WM_CLIENT_READCLOSE,FD_READ|FD_CLOSE);
//DEL
//DEL IsTrue = TRUE;
//DEL
//DEL return 0;
//DEL }
//还请高手帮帮我谢谢了。

[解决办法]
正确的是:
static DWORD WINAPI AcceptThreadProc( LPVOID pParam );
或者定义成全局的函数
DWORD WINAPI AcceptThreadProc( LPVOID pParam );
[解决办法]
个人建议,请参考,以FD_READ为例:
获得FD_READ消息后开始线程处理
AfxBeginThread(HandleFon,&m_sockClient,THREAD_PRIORITY_LOWEST );

HandleFon是线程处理函数,
m_sockClient是Accept返回的socket,

在ServerDlg.cpp开头声明
UINT HandleFon(LPVOID lparam);
.........................
UINT HandleFon(LPVOID lparam)
{
SOCKET* socket = (SOCKET*)lparam;//获得传递过来的m_sockClient

//如果是对话框程序,用下句获得CServerDlg指针
CServerDlg *pFrame=(CServerDlg*)AfxGetApp()-> m_pMainWnd;

//否则先获得应用程序指针,再指向CServerDlg,假设应用程序类CMyApp
CMyApp *pFrame=(CMyApp*)AfxGetApp()-> m_pMainWnd;
CServerDlg *pSdlg=pFrame-> GetServerDlg();//GetServerDlg()是自定义获取CServerDlg类指
//针的函数.
......................
//接下来就可以使用CServerDlg中公有成员了.
}
不知道是否是你需要的,仅供交流参考:)
有出错的地方请各位指正,谢谢.

读书人网 >VC/MFC

热点推荐