1、线程同步与异步套接字编程1.利用事件对象来实现线程间的同步新建一个 win32 console application,取名 Event,再建一个 Event 源文件,编辑:#include #include DWORD WINAPI Fun1Proc(LPVOID lpParameter); DWORD WINAPI Fun2Proc(LPVOID lpParameter); int tickets=100; HANDLE g_hEvent; void main() HANDLE hThread1; HANDLE hThread2; hThread1=CreateThread(NULL,0,
2、Fun1Proc,NULL,0,NULL); hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL); CloseHandle(hThread1); CloseHandle(hThread2); /g_hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);/创建一个匿名的有信号状态的事件对象 /g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);/创建一个匿名的无信号状态的事件对象 g_hEvent=CreateEvent(NULL,FALSE,FALSE,“tickets“);/创建
3、一个命名的无信号状态的事件对象 SetEvent(g_hEvent);/将事件对象设置为有信号状态 if(g_hEvent) if(ERROR_ALREADY_EXISTS=GetLastError() cout0) Sleep(1); SetEvent(g_hEvent); cout0) Sleep(1); SetEvent(g_hEvent); cout #include DWORD WINAPI Fun1Proc(LPVOID lpParameter); DWORD WINAPI Fun2Proc(LPVOID lpParameter); int tickets=100; CRITICA
4、L_SECTION g_cs; /定义一个全局的临界区对象 void main() HANDLE hThread1; HANDLE hThread2; hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL); hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL); CloseHandle(hThread1); CloseHandle(hThread2); InitializeCriticalSection(/初始化一个临界区对象 Sleep(4000); DeleteCriticalSection(/
5、释放这个临界区对象 DWORD WINAPI Fun1Proc( LPVOID lpParameter / thread data ) while(TRUE) EnterCriticalSection(/获得临界区的所有权,进入临界区 if(tickets0) Sleep(1); cout0) Sleep(1); cout #include DWORD WINAPI Fun1Proc(LPVOID lpParameter); DWORD WINAPI Fun2Proc(LPVOID lpParameter); int tickets=100; CRITICAL_SECTION g_csA; /
6、定义一个全局的临界区对象 CRITICAL_SECTION g_csB; void main() HANDLE hThread1; HANDLE hThread2; hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL); hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL); CloseHandle(hThread1); CloseHandle(hThread2); InitializeCriticalSection(/初始化一个临界区对象 InitializeCriticalSection( Sl
7、eep(4000); DeleteCriticalSection(/释放这个临界区对象 DeleteCriticalSection( DWORD WINAPI Fun1Proc( LPVOID lpParameter / thread data ) while(TRUE) EnterCriticalSection(/获得临界区的所有权,进入临界区 Sleep(1); EnterCriticalSection( if(tickets0) Sleep(1); cout0) Sleep(1); cout /使用 winsock 函数要使用它 #pragma comment(lib,“Ws2_32.l
8、ib“) 编辑函数 InitInstance:BOOL CChat2App:InitInstance() WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 2, 2 ); err = WSAStartup( wVersionRequested, if ( err != 0 ) return FALSE; if ( LOBYTE( wsaData.wVersion ) != 2 | HIBYTE( wsaData.wVersion ) != 2 ) WSACleanup( ); retu
9、rn FALSE; AfxEnableControlContainer(); 添加虚函数:Chat2.h 中编辑 :class CChat2App : public CWinApp public: CChat2App(); CChat2App();/增加一个析构函数,去调用 WSACleanup Chat2.cpp 中编辑:CChat2App:CChat2App()WSACleanup();并在 CChat2Dlg.h 中添加:public: CChat2Dlg(CWnd* pParent = NULL); / standard constructor CChat2Dlg();/析构函数 pr
10、ivate: SOCKET m_socket; 在 CChat2Dlg.cpp 中添加:CChat2Dlg:CChat2Dlg() if(m_socket) closesocket(m_socket); 再添加成员函数 BOOL CChat2Dlg:InitSocket,编辑:BOOL CChat2Dlg:InitSocket() m_socket=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,0); if(INVALID_SOCKET=m_socket) MessageBox(“创建套接字失败!“); return FALSE; SOCKADDR_IN addr
11、Sock; addrSock.sin_addr.S_un.S_addr=htol(INADDR_ANY); addrSock.sin_family=AF_INET; addrScok.sin_port=htons(6000); if(SOCKET_ERROR=bind(m_socket,(SOCKET*) return FALSE; if(SOCKET_ERROR=WSAAsyncSelect(m_socket,m_hWnd,WM_SOCK,FD_READ)/请求一个基于消息的网络读取事件通知 MessageBox(“注册网络读取事件失败!“); return FALSE; return TR
12、UE; 并在 BOOL CChat2Dlg:OnInitDialog()调用一下:BOOL CChat2Dlg:OnInitDialog() / TODO: Add extra initialization here InitSocket(); return TRUE; / return TRUE unless you set the focus to a control 接着编写 WM_SOCK 消息:在 Chat2Dlg.h 中添加:#define UM_SOCK WM_USER+1 /消息定义 afx_msg void OnSock(WPARAM,LPARAM);/消息函数声明在 Cha
13、t2Dlg.cpp 中编辑:添加消息映射:BEGIN_MESSAGE_MAP(CChat2Dlg, CDialog) /AFX_MSG_MAP(CChat2Dlg) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() /AFX_MSG_MAP ON_MESSAGE(UM_SOCK,OnSock) /消息映射 END_MESSAGE_MAP() 消息函数实现:void CChat2Dlg:OnSock(WPARAM wParam,LPARAM lParama) switch(LOWORD(lParama) case FD_READ: WS
14、ABUF wsabuf; wsabuf.buf=new char200; wsabuf.len=200; DWORD dwRead; DWORD dwFlag=0; SOCKADDR_IN addrFrom; int len=sizeof(SOCKADDR); CString str; CString strTemp; if(SOCKET_ERROR=WSARecvFrom(m_socket, return ; str.Format(“%s 说:%s“,inet_ntoa(addrFrom.sin_addr),wsabuf.buf); str+=“rn“; GetDlgItemText(IDC
15、_EDIT_RECV,strTemp); str+=strTemp; SetDlgItemText(IDC_EDIT_RECV,str); break; 双击发送按钮,接下来编写发送端:void CChat2Dlg:OnBtnSend() / TODO: Add your control notification handler code here DWORD dwIP; CString strSend;/用于存放发送的字节数 WSABUF wsabuf; DWORD dwSend; int len; (CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1)-Ge
16、tAddress(dwIP); SOCKADDR_IN addrTo; addrTo.sin_addr.S_un.S_addr=htonl(dwIP); addrTo.sin_family=AF_INET; addrTo.sin_port=htons(6000); GetDlgItemText(IDC_EDIT_SEND,strSend);/获取要发送的数据 len=strSend.GetLength(); wsabuf.buf=strSend.GetBuffer(len); wsabuf.len=len+1;/有一个0作为结尾 SetDlgItemText(IDC_EDIT_SEND,“);
17、 if(SOCKET_ERROR=WSASendTo(m_socket, return; 5.利用主机名发送数据void CChat2Dlg:OnSock(WPARAM wParam,LPARAM lParama) switch(LOWORD(lParama) case FD_READ: WSABUF wsabuf; wsabuf.buf=new char200; wsabuf.len=200; DWORD dwRead; DWORD dwFlag=0; SOCKADDR_IN addrFrom; int len=sizeof(SOCKADDR); CString str; CString s
18、trTemp; HOSTENT *pHost;/定义一个 HOSTENT 结构体指针 if(SOCKET_ERROR=WSARecvFrom(m_socket, return ; pHost=gethostbyaddr(char *)/将地址转换成 主机名/str.Format(“%s 说:%s“,inet_ntoa(addrFrom.sin_addr),wsabuf.buf); str.Format(“%s 说:%s“,pHost-h_name,wsabuf.buf); str+=“rn“; GetDlgItemText(IDC_EDIT_RECV,strTemp); str+=strTem
19、p; SetDlgItemText(IDC_EDIT_RECV,str); break; void CChat2Dlg:OnBtnSend() / TODO: Add your control notification handler code here DWORD dwIP; CString strSend;/用于存放发送的字节数 WSABUF wsabuf; DWORD dwSend;/用于指向存放 the number of bytes sent by this call int len; CString strHostName; SOCKADDR_IN addrTo; HOSTENT*
20、 pHost;/定义一个 HOSTENT 结构体 if(GetDlgItemText(IDC_EDIT_HOSTNAME,strHostName),strHostName=“NULL“)/获取主机名,并判断其是否为空 (CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1)-GetAddress(dwIP);/从 IP 地址控件中获取IP 地址 addrTo.sin_addr.S_un.S_addr=htonl(dwIP); else pHost=gethostbyname(strHostName);/根据主机名获取地址 addrTo.sin_addr.S_un.
21、S_addr=*(DWORD*)pHost-h_addr_list0); (CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1)-GetAddress(dwIP); addrTo.sin_family=AF_INET; addrTo.sin_port=htons(6000); GetDlgItemText(IDC_EDIT_SEND,strSend);/获取要发送的数据 len=strSend.GetLength(); wsabuf.buf=strSend.GetBuffer(len); wsabuf.len=len+1;/有一个0作为结尾 SetDlgItemText(IDC_EDIT_SEND,“); if(SOCKET_ERROR=WSASendTo(m_socket, return; 运行,OK!