从别人那里看到的一篇关于select模型开发的文章,不一定好用,但先留下。

来源:互联网 发布:淘宝推广软件免费的 编辑:程序博客网 时间:2024/05/01 14:11
一、客户端
1。初始化连接即启动连接
 if (iError = WSAStartup (MAKEWORD(2,0), &WSAData))//
 {
  TRACE1(TEXT("Startup error #%i./r/n"),iError);
  return false;
 }
 
2。m_gCnSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//创建一个socket
 
3。if(SOCKET_ERROR==WSAAsyncSelect(m_gCnSocket,m_hWnd,WM_SOCKET_NOTIFY,
  FD_WRITE|FD_READ|FD_ACCEPT|FD_CONNECT|FD_CLOSE))//注册网络异步事件,m_hWnd为应用程序的主对话框或主窗口的句柄
  
 {
  TRACE1(TEXT("WSAAsyncSelect error #%i./r/n"),WSAGetLastError());
  closesocket(m_gCnSocket);
  //  WSACleanup();
  
  return false;
 }
 
4。 向服务端发送连接请求
 sa.sin_family = AF_INET;
 sa.sin_port = htons(atoi(connectPort));
 sa.sin_addr.S_un.S_addr = inet_addr(connectIP);
int  iRetErr=connect(m_gCnSocket,(SOCKADDR *)&sa,sizeof(sa));
 
5。在 stdafx.h 中加入 #define WM_SOCKET_NOTIFY WM_USER + 101
 
6.下面中加入如下一行
BEGIN_MESSAGE_MAP(CECAS3to5Dlg, CDialog)
//{{AFX_MSG_MAP(CECAS3to5Dlg)
...............
ON_MESSAGE(WM_SOCKET_NOTIFY,OnMyMessage)
...............
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
 
7.在这个项目的构造函数在加入最后的一行
......................
afx_msg void OnPaint();
 afx_msg HCURSOR OnQueryDragIcon();
 afx_msg LRESULT OnMyMessage(WPARAM wParam,LPARAM lParam);
.....................
 
8。下面是自己定义的网络异步事件
LRESULT Class::OnMyMessage(WPARAM wParam,LPARAM lParam)//定义网络事件的响应函数
{
 
    char szMsg[256]="";
    int byteReceived;
 SYSTEMTIME tm;
 char buf[20]="";
 char szRecvBuf[512];
 if ((DWORD)wParam == (DWORD)m_gCnSocket )
 {
  
  switch WSAGETSELECTEVENT(lParam)//调用API函数,得到网络事件类型
  {
  case FD_CONNECT://发送连接请求后,服务器返回的结果,连接成功或者不成功
   
   if (WSAGETSELECTERROR(lParam) != 0)
    //提取错误时没的错误即WSAGETSELECTERROR(lParam)==0
   {
    closesocket(m_gCnSocket);
    
    GetLocalTime(&tm);
    sprintf(buf,"%04d-%02d-%02d %02d:%02d:%02d",
     tm.wYear,tm.wMonth,tm.wDay,tm.wHour,tm.wMinute,tm.wSecond);
    CString str="连接不成功!";
    m_list3.InsertItem(iii,(LPCTSTR)(_bstr_t)buf);
    m_list3.SetItemText(iii,1,(LPCTSTR)(_bstr_t)str);
    iii++; 
    m_list3.SendMessage(WM_VSCROLL, SB_BOTTOM, NULL);//滚动条总是在最近的记录处
    
    SetTimer(2,3000,NULL); //定时器用来再连接不成功时重连接服务器
   }
   else
   {
    KillTimer(2);
    GetLocalTime(&tm);
    sprintf(buf,"%04d-%02d-%02d %02d:%02d:%02d",
     tm.wYear,tm.wMonth,tm.wDay,tm.wHour,tm.wMinute,tm.wSecond);
    CString str = "连接服务器成功.";
    m_list3.InsertItem(iii,(LPCTSTR)(_bstr_t)buf);
    m_list3.SetItemText(iii,1,(LPCTSTR)(_bstr_t)str);
    iii++; 
    m_list3.SendMessage(WM_VSCROLL, SB_BOTTOM, NULL);//滚动条总是在最近的记录处
  
    SetTimer(1,time,NULL); //一个1秒一次的定时器,这个里面处理要做的事向服务器发包
    //进入程序真正要做的工作    
   }  
   break;
   
        case FD_ACCEPT:
   break;
   
        case FD_READ://接收包消息发生时接收包
            {
    
             memset(szRecvBuf,0,sizeof(szRecvBuf));//清空收包缓存,
    
                byteReceived=recv(wParam,szRecvBuf,sizeof(szRecvBuf),0);//接收包
    
                if (byteReceived==SOCKET_ERROR)
                {
     GetLocalTime(&tm);
     sprintf(buf,"%04d-%02d-%02d %02d:%02d:%02d",
      tm.wYear,tm.wMonth,tm.wDay,tm.wHour,tm.wMinute,tm.wSecond);
     CString str = "在接收包时错误!";
     m_list3.InsertItem(iii,(LPCTSTR)(_bstr_t)buf);
                    m_list3.SetItemText(iii,1,(LPCTSTR)(_bstr_t)str);
     iii++; 
     m_list3.SendMessage(WM_VSCROLL, SB_BOTTOM, NULL);//滚动条总是在最近的记录处
     
     break;
                }
    else
    {
  /*   char buff[200]="";
     
                    GetLocalTime(&tm);
     sprintf(buf,"%04d-%02d-%02d %02d:%02d:%02d",
      tm.wYear,tm.wMonth,tm.wDay,tm.wHour,tm.wMinute,tm.wSecond);
     CString str = "收包";
     {
     // m_list2.InsertItem(ii,(LPCTSTR)(_bstr_t)buf);
     // m_list2.SetItemText(ii,1,(LPCTSTR)(_bstr_t)str);
     // m_list2.SetItemText(ii,2,(LPCTSTR)(_bstr_t)"1111");
     // ii++;
     }
     m_list2.SendMessage(WM_VSCROLL, SB_BOTTOM, NULL);//滚动条总是在最近的记录处
     //此处做从服务器端收包成功后的处理
   */  
     
    }
    
                break;
            }
   
        case FD_WRITE:
   break;
   
        case FD_CLOSE:
   {
    KillTimer(1);
    GetLocalTime(&tm);
    sprintf(buf,"%04d-%02d-%02d %02d:%02d:%02d",
     tm.wYear,tm.wMonth,tm.wDay,tm.wHour,tm.wMinute,tm.wSecond);
    CString str = "服务器主动关闭Socket!";
    m_list3.InsertItem(iii,(LPCTSTR)(_bstr_t)buf);
    m_list3.SetItemText(iii,1,(LPCTSTR)(_bstr_t)str);
    iii++;     
    m_list3.SendMessage(WM_VSCROLL, SB_BOTTOM, NULL);//滚动条总是在最近的记录处
    
    closesocket(m_gCnSocket);
    SetTimer(2,3000,NULL);
    break;
   }
  }
 }
 
 return 0;
}
 
二。服务器端
1。初始化连接即启动连接
 if (iError = WSAStartup (MAKEWORD(2,0), &WSAData))//
 {
  TRACE1(TEXT("Startup error #%i./r/n"),iError);
  return false;
 }
 
2。m_gCnSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//创建一个socket
 
3。if(SOCKET_ERROR==WSAAsyncSelect(m_gCnSocket,m_hWnd,WM_SOCKET_NOTIFY,
  FD_WRITE|FD_READ|FD_ACCEPT|FD_CONNECT|FD_CLOSE))//注册网络异步事件,m_hWnd为应用程序的主对话框或主窗口的句柄
  
 {
  TRACE1(TEXT("WSAAsyncSelect error #%i./r/n"),WSAGetLastError());
  closesocket(m_gCnSocket);
  //  WSACleanup();
  
  return false;
 }
 
4。绑定指定端口
 sa.sin_family           = AF_INET;
 sa.sin_port             = htons(server_port);
 sa.sin_addr.S_un.S_addr = INADDR_ANY;//inet_addr(szFmIP);  //INADDR_ANY;szFmIP //inet_addr(szIPaddress);
 
 int iRetErr;
 if ((iRetErr=bind(gsocketEcas,(SOCKADDR *)&sa,sizeof(sa)))<0)
 {
  closesocket(gsocketEcas);
  
  GetLocalTime(&tm);
  sprintf(buf,"%04d-%02d-%02d %02d:%02d:%02d",tm.wYear,
   tm.wMonth,tm.wDay,tm.wHour,tm.wMinute,tm.wSecond);
  m_list3.InsertItem(iii,(LPCTSTR)(_bstr_t)buf);
 m_list3.SetItemText(iii,1,(T("Bind失败."));
 iii++;
  
  return false;
 }
 
5.侦听此端口
 if (listen(gsocketEcas,20)<0)
 {
  closesocket(gsocketEcas);
  
  GetLocalTime(&tm);
  sprintf(buf,"%04d-%02d-%02d %02d:%02d:%02d",tm.wYear,
   tm.wMonth,tm.wDay,tm.wHour,tm.wMinute,tm.wSecond);
  
  m_list3.InsertItem(iii,(LPCTSTR)(_bstr_t)buf);
 m_list3.SetItemText(iii,1,(T("Listen失败."));
  iii++;
  return false;
 }
 
6。在 stdafx.h 中加入 #define WM_SOCKET_NOTIFY WM_USER + 101
 
7.下面中加入如下一行
BEGIN_MESSAGE_MAP(CECAS3to5Dlg, CDialog)
//{{AFX_MSG_MAP(CECAS3to5Dlg)
...............
ON_MESSAGE(WM_SOCKET_NOTIFY,OnMyMessage)
...............
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
 
8.在这个项目的构造函数在加入最后的一行
......................
afx_msg void OnPaint();
 afx_msg HCURSOR OnQueryDragIcon();
 afx_msg LRESULT OnMyMessage(WPARAM wParam,LPARAM lParam);
.....................
 
9.下面是自己定义的网络异步事件
LRESULT Class::OnMyMessage(WPARAM wParam,LPARAM lParam)//定义网络事件的响应函数
{
CString m_strHostIP;
 
 char szRecvData[512];
 SYSTEMTIME tm;
 int i;
 char buf[20];
 struct sockaddr_in addr;
 int addrlen = sizeof(addr);
 
 switch WSAGETSELECTEVENT(lParam)
 {
 case FD_CONNECT://针对客户端连接服务器端后服务器端发回的连接结果,成功与否
  if (WSAGETSELECTERROR(lParam) != 0)
  {
................
  }
  else
  {
..............
  }
  
  break;
  
 case FD_ACCEPT://针对服务器端接收到客户端的连接请求后服务器端的处理
  for (i=0;i<MaxQSize;i++)
  {
   if (m_gSocketEcas[gsocketcount]>0)
    gsocketcount=(gsocketcount+1)%MaxQSize;
   else
    break;
  }
  
  m_gSocketEcas[gsocketcount]=accept(wParam,(sockaddr*)&addr,&addrlen);
  gsocketcount=(gsocketcount+1)%MaxQSize;
  
  break;
  
 case FD_READ:
  {
   memset(szRecvData,0,sizeof(szRecvData));
   
   //According to the socket,Get oppisize computer IP Address.
   m_strHostIP.Empty();
   m_strHostIP=GetHostName(wParam);

   int byteReceived=recv(wParam,szRecvData,sizeof(szRecvData),0);
   
   if (byteReceived==SOCKET_ERROR)
   {
    break;
   }
   //收到的包内容和IP一一对应的进队列,等待处理
   //Add the receive data to a Queue
   if (((rear+1) % MaxQSize)==front)
   {//队列满
    break;
   }
   
   if (byteReceived>510)
    byteReceived=510;
   
   qlist[rear].m_strIP=m_strHostIP;
   memset(qlist[rear].m_Buffer,0,sizeof(qlist[rear].m_Buffer));
   memcpy(qlist[rear].m_Buffer,szRecvData,byteReceived);
   rear = (rear+1) % MaxQSize;
   
   break;
  }
  
 case FD_WRITE:
  break;
  
 case FD_CLOSE://服务端或者客户端关闭连接后的处理
 /*  if (wParam==gsockHkGw)
 {
 closesocket(gsockHkGw);
 gbHkGwConFlag=false;
 
   GetLocalTime(&tm);
   sprintf(buf,"%04d-%02d-%02d %02d:%02d:%02d",tm.wYear,
      tm.wMonth,tm.wDay,tm.wHour,tm.wMinute,tm.wSecond);
      
        }
  */
  for (i=0;i<MaxQSize;i++)
  {
   if (m_gSocketEcas[i]==wParam)
   {
    //    closesocket(m_gSocketEcas[i]);
    m_gSocketEcas[i]=0;
   }
  }
  
  shutdown(wParam,SD_BOTH);
  
  closesocket(wParam);
  
  break;
 }
 
 return 0;
}