1、構造函數中對套接字對象和其他控制變量初始化
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); m_hSocket = NULL; isServerStart=FALSE; ChatEnable=FALSE;
2、調用WSAStartup函數對WinSock DLL初始化
WSADATA wsaData;//結構體,包含加載庫版本的相關信息 WORD version = MAKEWORD(2, 0);//版本號 int ret = WSAStartup(version, &wsaData);//返回0表示初始化成功 if(ret != 0) TRACE("Initilize Error!\n");
3、創建Socket套接字
//AF_INET表示在Internet域進行通信,SOCK_STREAM表示套接字類型(區別於SOCK_DGRAM),0表示TCP/IP協議 m_hSocket = socket(AF_INET, SOCK_STREAM,0); if (m_hSocket==INVALID_SOCKET) { AfxMessageBox("Socket Create Error!"); return; }
4、將本地地址與套接字綁定
m_addr.sin_family = AF_INET;//Internet域 m_addr.sin_addr.S_un.S_addr = INADDR_ANY;//任意地址 m_addr.sin_port = htons(1029);//端口號 int ret = 0; int error = 0; ret = bind(m_hSocket, (LPSOCKADDR)&m_addr, sizeof(m_addr));//綁定 error = WSAGetLastError(); if(ret == SOCKET_ERROR) { list->AddString("服務器:Bind Error!"); return ; }
5、創建監聽線程
DWORD dwthread;//unsigned long類型 ::CreateThread(NULL,0,listenthread,(LPVOID)m_hSocket,0,&dwthread);//listenthread是一個監聽該線程的函數,(LPVOID)m_hSocket是套接字的指針
6、調用監聽程序Listen函數
DWORD WINAPI listenthread(LPVOID lpparam)//將數據從一個線程傳到另一個線程的唯一方法是在創建線程時傳遞給新線程一個指針參數LPVOID lpparam { SOCKET m_socket=(SOCKET)lpparam;//獲取傳遞進來的套接字句柄 int ret; ret=listen(m_socket,30); if(ret==SOCKET_ERROR) { ListInfo=_T("Listen Error!"); return 0; } SOCKET s; s=accept(m_socket,NULL,NULL); DWORD dwthread; ::CreateThread(NULL,0,Recvthread,(LPVOID)s,0,&dwthread); ::CreateThread(NULL,0,Sendthread,(LPVOID)s,0,&dwthread); return 0; }
7、消息接收和消息發送循環
//消息接收Recvthread while(1) { ret=recv(m_socket,buff,256,0); if(ret==SOCKET_ERROR) { ListInfo=_T("Socket Receive Error!"); closesocket (m_socket); } buff[ret]='\0'; CString str; str="客戶端:"; str=str+buff; ListInfo=str; } //消息發送Sendthread while(1) { if (ChatInfo.GetLength()>0) { ret=send(m_socket,ChatInfo,ChatInfo.GetLength(),0); if(ret==SOCKET_ERROR) { ListInfo=_T("服務器:Data send error!"); return -1; } ListInfo=_T("服務器:"); ListInfo+=ChatInfo; ChatInfo.Empty(); }