孙鑫 异步原始套接字字聊天室 代码能运行吗

异步套接字编程问题,为什么在虚拟机中运行程序,不能首先向实体机运行的程序发送消息?_百度知道
异步套接字编程问题,为什么在虚拟机中运行程序,不能首先向实体机运行的程序发送消息?
我按视频中讲述的用多线程和采用异步套接字编程分别编写了一个聊天室(chat)程序,但是我用虚拟机测试时却出现了问题;;while(TRUE){retval=recvfrom(}下面是发送函数代码.com/zhidao/pic/item/9c16fdfaaf51f3debe440ab995eef01f3b29797c.baidu首先声明我是个新手;SOCKADDR_IN addrTo,0.hiphotos:OnBtnSend() {// TODO.}return 0:,&int len=sizeof(SOCKADDR),发现windows根本没有调用这个函数,编写完成后,向其发送消息时;addrTo://c,strSend,请问这是为什么呢,strSend: %s&quot.jpg" target="_blank" title="点击查看大图" class="ikqb_img_alink"><img class="ikqb_img" src="http.S_addr=htonl(dwIP);char recvBuf[200],遗忘了释放内存的操作,又会出现上述部问题;hwnd.sin_port=htons(6000):://c,也就是在IP地址框中输入本地IP 127,然而在虚拟机上的程序却没能接收到消息;addrFrom://c;GetDlgItemText(IDC_EDIT_SEND;addrTo;len).0,然而当我在虚拟机中的程序的IP地址框中输入实体机的IP地址,在学习孙鑫老师的MFC视频网络编程当中;int retval.S_un.1时.0;);if(SOCKET_ERROR==retval)sendto(m_socket,这时再通过实体机上的程序向虚拟机上的程序发送消息;char tempBuf[300].jpg" esrc="http:void CChatDaddrTo.sin_CString strSend,sizeof(SOCKADDR));((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))-&gt.com/zhidao/wh%3D600%2C800/sign=defd1ea156/9c16fdfaaf51f3debe440ab995eef01f3b29797c,(SOCKADDR*)&amp,WM_RECVDATA: Add your control notification handler code hereDWORD dwIP.baidu.jpg" />这是接收函数代码。测试如下,0:我在实体机和虚拟机分别运行chat程序.sin_family=AF_INET,0。sunxinSOCKADDR_IN addrFrom,消息就能被收到了;sock。但是在隔一段时间不退出程序的情况下,strSend);delete lpParameter:DWORD WINAPI CChatDlg.GetLength()+1,在实体机上的程序的IP地址框中填写虚拟机的IP地址;&;GetAddress(dwIP);HWND hwnd=((RECVPARAM*)lpParameter)-&%s说:,(SOCKADDR*)& //视频讲述时;sprintf(tempBuf,然后向其发送消息,在虚拟机中的接收消息函数中设置断点,&/zhidao/wh%3D450%2C600/sign=043f9d38ac6eddc426b2bcff0ceb9acb/9c16fdfaaf51f3debe440ab995eef01f3b29797c,(LPARAM)tempBuf):PostMessage(SetDlgItemText(IDC_EDIT_SEND.sin_addr)?<a href="http,运行没有任何问题,先用实体机向虚拟机发送消息.hiphotos,inet_ntoa(addrFrom,&addrTo,200:RecvProc(LPVOID lpParameter){SOCKET sock=((RECVPARAM*)lpParameter)-&gt,实体机上运行的程序就能收到消息,recvBuf),测试运行,recvBuf,在本地测试
提问者采纳
比如windows防火墙,在防火墙开启的情况下,默认是开启的你的虚拟机里面有防火墙之类的东西吗
刚才将虚拟机里的防火墙关闭了,果然测试成功,谢谢。补充下,我的实体机装的Win7,虚拟机上装的XP,在实体机上装有杀毒软件,虚拟机上什么都没装,防火墙倒是默认打开的,但是我也勾选了当Windows阻止程序时通知我,在我发送消息时,为什么Windows什么也没做,根本没提示我是否允许程序访问网络?这是为什么呢?
因为这个阻止的是端口不是程序。你看你的防火墙设置有两项,一项是“添加程序”,一项是“添加端口”,如果是不在白名单的程序访问网络,那么会有提示;但是其他机器试图连接不在白名单里面的端口时不会有通知。
提问者评价
哦,原来是这样,谢谢了
其他类似问题
为您推荐:
套接字的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁5744人阅读
事件对象:来实现线程的同步。与互斥对象一样均属于内核对象。
当人工重置有信号时,所有线程均得到信号,所以不能设为人工重置。代码就不贴了,通过创建匿名的事件对象,也可以让一个程序只能运行一个实例。
关键代码段实现线程的同步:类&#20284;公用电话亭,只有当电话亭里面没人了,其它人才可以再进去打电话。用了个函数,这种方法比较简单!但缺点是如果使用了多少关键代码码,容易赞成线程的死锁
线程死锁,用关键代码示例,用了两个临界区对象,实战中要注意避免这种错误!
使用异步套接字编写网络聊天室
1)加载套接字库,进行版本协商,包含头文件,链接库文件,这次请示的是版本!
2)在类中增加一个成员变量在析构函数中释放这个变量
3)利用创建套接字(数据报类型的型的)
4)然后调用为网络事件定义消息!此时如果发生消息,系统会发送消息给应用程序!程序并不会阻塞在这儿了!
以上是在完成
5)然后完成消息响应!
头文件中:WM_USER&#43;1
afx_msg void OnSock(WPARAM,LPARAM);
源文件中:
ON_MESSAGE(UM_SOCK,OnSock)
实现消息响应函数:
switch(LOWORD(lParam))
case FD_READ:
wsabuf.buf=new char[200];
wsabuf.len=200;
DWORD dwFlag=0;
SOCKADDR_IN addrF
int len=sizeof(SOCKADDR);
CString strT
HOSTENT *pH
if(SOCKET_ERROR==WSARecvFrom(m_socket,&wsabuf,1,&dwRead,&dwFlag,
(SOCKADDR*)&addrFrom,&len,NULL,NULL))
MessageBox(&接收数据失败!
pHost=gethostbyaddr((char*)&addrFrom.sin_addr.S_un.S_addr,4,AF_INET);
//str.Format(&%s说
str.Format(&%s说
str&#43;=&\r\n&;
GetDlgItemText(IDC_EDIT_RECV,strTemp);
str&#43;=strT
SetDlgItemText(IDC_EDIT_RECV,str);
6)完成数据发送的功能!
void CChatDlg::OnBtnSend()
// TOD Add your control notification handler code here
DWORD dwIP;
CString strS
CString strHostN
SOCKADDR_IN addrTo;
HOSTENT* pH
if(GetDlgItemText(IDC_EDIT_HOSTNAME,strHostName),strHostName==&&)
((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))-&GetAddress(dwIP);
addrTo.sin_addr.S_un.S_addr=htonl(dwIP);
pHost=gethostbyname(strHostName);
addrTo.sin_addr.S_un.S_addr=*((DWORD*)pHost-&h_addr_list[0]);
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&#43;1; SetDlgItemText(IDC_EDIT_SEND,&&); if(SOCKET_ERROR==WSASendTo(m_socket,&wsabuf,1,&dwSend,0,
(SOCKADDR*)&addrTo,sizeof(SOCKADDR),NULL,NULL))
MessageBox(&发送数据失败!
7)完成将主机名转换为地址的功能,以前将地址转换为主机名的功能,单线程的聊天室创建完毕!性能并且非常出色!
下面是一些具体的代码:
#include&windows.h&
#include&iostream.h&
DWORD WINAPI ThreadProc1(
LPVOID lpParameter
DWORD WINAPI ThreadProc2(
LPVOID lpParameter
int tickes=100;
int main()
HANDLE hThread1=CreateThread(NULL,0,ThreadProc1,NULL,0,NULL);
HANDLE hThread2=CreateThread(NULL,0,ThreadProc2,NULL,0,NULL);
hEvent=CreateEvent(NULL,FALSE,TRUE,NULL);//自动,有信号
CloseHandle(hThread1);
CloseHandle(hThread2);
Sleep(4000);
DWORD WINAPI ThreadProc1(
LPVOID lpParameter
// thread data
while(TRUE)
SetEvent(hEvent);
WaitForSingleObject(hEvent,INFINITE);
if(tickes&0)
cout&&&thread1 sell ticke: &&&tickes--&&
//ReleaseMutex(hEvent);
ResetEvent(hEvent);
DWORD WINAPI ThreadProc2(
LPVOID lpParameter
// thread data
while(TRUE)
SetEvent(hEvent);
WaitForSingleObject(hEvent,INFINITE);
if(tickes&0)
cout&&&thread2 sell ticke: &&&tickes--&&
//ReleaseMutex(hEvent);
ResetEvent(hEvent);
//CreateEvent设置自定的,并且初始有信号
/*#include&windows.h&
#include&iostream.h&
DWORD WINAPI ThreadProc1(
LPVOID lpParameter
DWORD WINAPI ThreadProc2(
LPVOID lpParameter
int tickes=100;
int main()
HANDLE hThread1=CreateThread(NULL,0,ThreadProc1,NULL,0,NULL);
HANDLE hThread2=CreateThread(NULL,0,ThreadProc2,NULL,0,NULL);
hEvent=CreateEvent(NULL,FALSE,TRUE,NULL);//自动,有信号
CloseHandle(hThread1);
CloseHandle(hThread2);
Sleep(4000);
DWORD WINAPI ThreadProc1(
LPVOID lpParameter
// thread data
while(TRUE)
WaitForSingleObject(hEvent,INFINITE);
if(tickes&0)
cout&&&thread1 sell ticke: &&&tickes--&&
DWORD WINAPI ThreadProc2(
LPVOID lpParameter
// thread data
while(TRUE)
WaitForSingleObject(hEvent,INFINITE);
if(tickes&0)
cout&&&thread2 sell ticke: &&&tickes--&&
//结论是,设置自动的,并且开始有信号(无信号可以调用SetEvent来使无信号到有信号的一个转变)
//只有一个线程获得了信号,并且运行完后(时间片到了),则下一个线程是无法运行的,因为此时只有一个
//线程有信号,并且运行完后,马上使得事件对象无信号
//CreateEvent手动,一开始就无信号
/*#include&windows.h&
#include&iostream.h&
DWORD WINAPI ThreadProc1(
LPVOID lpParameter
DWORD WINAPI ThreadProc2(
LPVOID lpParameter
int tickes=100;
int main()
HANDLE hThread1=CreateThread(NULL,0,ThreadProc1,NULL,0,NULL);
HANDLE hThread2=CreateThread(NULL,0,ThreadProc2,NULL,0,NULL);
hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);//手动,无信号
SetEvent(hEvent);
CloseHandle(hThread1);
CloseHandle(hThread2);
Sleep(4000);
DWORD WINAPI ThreadProc1(
LPVOID lpParameter
// thread data
while(TRUE)
WaitForSingleObject(hEvent,INFINITE);
if(tickes&0)
cout&&&thread1 sell ticke: &&&tickes--&&
DWORD WINAPI ThreadProc2(
LPVOID lpParameter
// thread data
while(TRUE)
WaitForSingleObject(hEvent,INFINITE);
if(tickes&0)
cout&&&thread2 sell ticke: &&&tickes--&&
//使用手动设置,则任何线程都获得了信号,都可以运行,可以使用ResetEvent使得信号变得无效
//关键代码段,临界区域
//如果只是Enter了但是没有Leave则下一个线程获取不了信号,下一个线程得不到执行
#include&windows.h&
#include&iostream.h&
DWORD WINAPI ThreadProc1(
LPVOID lpParameter
DWORD WINAPI ThreadProc2(
LPVOID lpParameter
int tickes=100;
CRITICAL_SECTION
int main()
HANDLE hThread1=CreateThread(NULL,0,ThreadProc1,NULL,0,NULL);
HANDLE hThread2=CreateThread(NULL,0,ThreadProc2,NULL,0,NULL);
CloseHandle(hThread1);
CloseHandle(hThread2);
InitializeCriticalSection(§ion);
Sleep(4000);
DeleteCriticalSection(§ion);
DWORD WINAPI ThreadProc1(
LPVOID lpParameter
// thread data
while(TRUE)
EnterCriticalSection(§ion);
if(tickes&0)
cout&&&thread1 sell ticke: &&&tickes--&&
LeaveCriticalSection(§ion);
DWORD WINAPI ThreadProc2(
LPVOID lpParameter
// thread data
while(TRUE)
EnterCriticalSection(§ion);
if(tickes&0)
cout&&&thread2 sell ticke: &&&tickes--&&
LeaveCriticalSection(§ion);
//死锁的体现
/*#include&windows.h&
#include&iostream.h&
DWORD WINAPI ThreadProc1(
LPVOID lpParameter
DWORD WINAPI ThreadProc2(
LPVOID lpParameter
int tickes=100;
CRITICAL_SECTION sectionA;
CRITICAL_SECTION sectionB;
int main()
HANDLE hThread1=CreateThread(NULL,0,ThreadProc1,NULL,0,NULL);
HANDLE hThread2=CreateThread(NULL,0,ThreadProc2,NULL,0,NULL);
CloseHandle(hThread1);
CloseHandle(hThread2);
InitializeCriticalSection(§ionA);
InitializeCriticalSection(§ionB);
Sleep(4000);
DeleteCriticalSection(§ionB);
DeleteCriticalSection(§ionA);
DWORD WINAPI ThreadProc1(
LPVOID lpParameter
// thread data
while(TRUE)
EnterCriticalSection(§ionA);
EnterCriticalSection(§ionB);
if(tickes&0)
cout&&&thread1 sell ticke: &&&tickes--&&
LeaveCriticalSection(§ionB);
LeaveCriticalSection(§ionA);
DWORD WINAPI ThreadProc2(
LPVOID lpParameter
// thread data
while(TRUE)
EnterCriticalSection(§ionB);
EnterCriticalSection(§ionA);
if(tickes&0)
cout&&&thread2 sell ticke: &&&tickes--&&
LeaveCriticalSection(§ionA);
LeaveCriticalSection(§ionB);
下面是用异步套接字写的聊天程序,跟前面的多线程对比一下:
1新建一个基于单文档的MFC程序
2拉控件成这样:
3在CXXAPP文件中的InitInstance中添加WSAStartupXX库添加函数,查看MSDN的WSAStartup
4在CXXDlg中添加成员变量SOCKET m_socket和成员函数 InitS
BOOL CNewChatDlg::InitSocket()
m_socket=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,0);
if(!m_socket)
AfxMessageBox(&创建套接字失败&);
return FALSE;
SOCKADDR_IN
sockaddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
sockaddr.sin_family=AF_INET;
sockaddr.sin_port=htons(6000);
returnbind=bind(m_socket,(SOCKADDR*)&sockaddr,sizeof(SOCKADDR));
if(SOCKET_ERROR==returnbind)
AfxMessageBox(&绑定失败&);
return FALSE;
se=WSAAsyncSelect(m_socket,m_hWnd,WM_RECV,FD_READ);
if(SOCKET_ERROR==se)
AfxMessageBox(&创建网络读取时间失败&);
return FALSE;
return TRUE;
并在CXXDlg中的OnInitDialog中调用InitSocket();
5自定义消息响应事件
a #define WM_RECV WM_USER&#43;1
b afx_msg void OnRecv(WPARAM wParam,LPARAM lParam);
c ON_MESSAGE(WM_RECV,OnRecv)
void CNewChatDlg::OnRecv(WPARAM wParam,LPARAM lParam)
switch(LOWORD(lParam))
case FD_READ:
wsabuf.buf=new char[200];
wsabuf.len=200;
DWORD dwflag=0;
SOCKADDR_IN
int len=sizeof(SOCKADDR);
if(SOCKET_ERROR ==WSARecvFrom(m_socket,&wsabuf,1,&dwread,&dwflag,
(SOCKADDR*)&sockaddr,&len,NULL,NULL))
AfxMessageBox(&接收数据失败&);
char temp[200];
sprintf(temp,&%s 说 %s &,inet_ntoa(sockaddr.sin_addr),wsabuf.buf);
GetDlgItemText(ID_JIESHOU,jieshou);
if(jieshou!=&&)
jieshou+=&\r\n&;
SetDlgItemText(ID_JIESHOU,jieshou);
6添加发送按钮事件:
void CNewChatDlg::OnSend()
// TODO: Add your control notification handler code here
DWORD dwIp;
((CIPAddressCtrl*)GetDlgItem(ID_IPADDRESS))-&GetAddress(dwIp);
SOCKADDR_IN
sockaddr.sin_addr.S_un.S_addr=htonl(dwIp);
sockaddr.sin_family=AF_INET;
sockaddr.sin_port=htons(6000);
GetDlgItemText(ID_FASONG,strsend);
wsabuf.buf=strsend.GetBuffer(strsend.GetLength());
wsabuf.len=strsend.GetLength()+1;
SetDlgItemText(ID_FASONG,&&);
int len=sizeof(SOCKADDR);
if(SOCKET_ERROR ==WSASendTo(m_socket,&wsabuf,1,&dwsent,0,
(SOCKADDR*)&sockaddr,len,NULL,NULL))
AfxMessageBox(&发送数据失败&);
CNewChatDlg::~CNewChatDlg()
closesocket(m_socket);
CNewChatDlg::~CNewChatDlg()
closesocket(m_socket);
要熟悉异步套接字和多线程的编程,这个很重要,一定要熟练。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:300174次
积分:5105
积分:5105
排名:第3535名
原创:174篇
转载:16篇
评论:60条
(1)(1)(5)(1)(3)(4)(1)(1)(13)(62)(98)转载的孙鑫vc++视频笔记(19)
&a target=_blank href=&.cn/s/articlelist__0_1.html&&.cn/s/articlelist__0_1.html&/a&
1.事件对象:来实现线程的同步。与互斥对象一样均属于内核对象。
当人工重置有信号时,所有线程均得到信号,所以不能设为人工重置。代码就不贴了。
通过创建匿名的事件对象,也可以让一个程序只能运行一个实例。
2.关键代码段实现线程的同步:类似公用电话亭,只有当电话亭里面没人了,其它人才可以再进去打电话。用了4个函数,这种方法比较简单!但缺点是如果使用了多少关键代码码,容易赞成线程的死锁
3.线程死锁,用关键代码示例,用了两个临界区对象,实战中要注意避免这种错误!
4.使用异步套接字编写网络聊天室
1)加载套接字库,进行版本协商,包含头文件,链接库文件,这次请示的是2.2版本!
2)在类CChatDlg中增加一个成员变量m_socket,在析构函数中释放这个变量
3)利用WSASocket()创建套接字(数据报类型的UDP型的)
4)然后调用WSAAsyncSelect(m_socket,m_hWnd,UM_SOCK,FD_READ)为网络事件定义消息!此时如果发生FD_READ消息,系统会发送UM_SOCK消息给应用程序!程序并不会阻塞在这儿了!
以上是在BOOL CChatDlg::OnInitDialog()完成
5)然后完成消息响应!
头文件中:#define UM_SOCK
afx_msg void OnSock(WPARAM,LPARAM);
源文件中:
ON_MESSAGE(UM_SOCK,OnSock)
实现消息响应函数:void CChatDlg::OnSock(WPARAM wParam,LPARAM lParam)
switch(LOWORD(lParam))
case FD_READ:
wsabuf.buf=new char[200];
wsabuf.len=200;
DWORD dwFlag=0;
SOCKADDR_IN addrF
int len=sizeof(SOCKADDR);
CString strT
HOSTENT *pH
if(SOCKET_ERROR==WSARecvFrom(m_socket,&wsabuf,1,&dwRead,&dwFlag,
(SOCKADDR*)&addrFrom,&len,NULL,NULL))
MessageBox(&接收数据失败!&);
pHost=gethostbyaddr((char*)&addrFrom.sin_addr.S_un.S_addr,4,AF_INET);
//str.Format(&%s说 :%s&,inet_ntoa(addrFrom.sin_addr),wsabuf.buf);
str.Format(&%s说 :%s&,pHost-&h_name,wsabuf.buf);
str+=&\r\n&;
GetDlgItemText(IDC_EDIT_RECV,strTemp);
SetDlgItemText(IDC_EDIT_RECV,str);
6)完成数据发送的功能!
void CChatDlg::OnBtnSend()
// TOD Add your control notification handler code here
DWORD dwIP;
CString strS
CString strHostN
SOCKADDR_IN addrTo;
HOSTENT* pH
if(GetDlgItemText(IDC_EDIT_HOSTNAME,strHostName),strHostName==&&)
((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))-&GetAddress(dwIP);
addrTo.sin_addr.S_un.S_addr=htonl(dwIP);
pHost=gethostbyname(strHostName);
addrTo.sin_addr.S_un.S_addr=*((DWORD*)pHost-&h_addr_list[0]);
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;
SetDlgItemText(IDC_EDIT_SEND,&&);
if(SOCKET_ERROR==WSASendTo(m_socket,&wsabuf,1,&dwSend,0,
(SOCKADDR*)&addrTo,sizeof(SOCKADDR),NULL,NULL))
MessageBox(&发送数据失败!&);
7)完成将主机名转换为IP地址的功能,以前将IP地址转换为主机名的功能
嘿嘿,单线程的聊天室创建完毕!性能并且非常出色!
//---------------------------------------------------------------------------
事件对象也属于内核对象,包含一个使用计数,一个用于指明该事件是一个自动重置的事件还是一个人工重置的事件的布尔值,另一个用于指明该事件处于已通知状态还是为通知状态的布尔值
有两种不同类型的事件对象。一种是人工重置的事件,另一种是自动重置的事件,当人工重置的事件得到通知时,等待该事件的所有线程均变为可调度线程。当一个自动重置的事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程。
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes,
// pointer to security attributes,指定安全属性
BOOL bManualReset,
// flag for manual-reset event
//为TRUE表示手动,否则为自动,看上边文字说明
BOOL bInitialState, // flag for initial state
//为TRUE表示有信号
LPCTSTR lpName
// pointer to event-object name
事件对象代码如下(经本人修改,此代码与视频源码有一些差别):
#include &windows.h&
#include &iostream.h&
DWORD WINAPI Fun1Proc(
LPVOID lpParameter
// thread data
DWORD WINAPI Fun2Proc(
LPVOID lpParameter
// thread data
int tickets=100;
HANDLE g_hE
void main()
HANDLE hThread1;
HANDLE hThread2;
g_hEvent=CreateEvent(NULL,FALSE,true,&tickets&);
ResetEvent(g_hEvent);//重置事件
//g_hEvent=CreateEvent(NULL,FALSE,false,&tickets&);
if(g_hEvent)
if(ERROR_ALREADY_EXISTS==GetLastError())
cout&&&only instance can run!&&&
hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(hThread1);
CloseHandle(hThread2);
//g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
SetEvent(g_hEvent);
Sleep(4000);
CloseHandle(g_hEvent);
DWORD WINAPI Fun1Proc(
LPVOID lpParameter
// thread data
while(TRUE)
WaitForSingleObject(g_hEvent,INFINITE);// 等待事件置位
ResetEvent(g_hEvent);
if(tickets&0)
cout&&&thread1 sell ticket : &&&tickets--&&
SetEvent(g_hEvent);// 处理完成后即将事件对象置位
DWORD WINAPI Fun2Proc(
LPVOID lpParameter
// thread data
while(TRUE)
WaitForSingleObject(g_hEvent,INFINITE);
ResetEvent(g_hEvent);
if(tickets&0)
cout&&&thread2 sell ticket : &&&tickets--&&
SetEvent(g_hEvent);
只有当 g_hEvent=CreateEvent(NULL,FALSE,TRUE,&ticket&);第四个参数有值时才能进行事件对象的判断:
if(g_hEvent)
if(ERROR_ALREADY_EXISTS==GetLastError())
cout&&&Only one instance can runs!&&&
//---------------------------------------------------------------------------
关键代码段
关键代码段(临界区)工作在用户方式下。
关键代码段(临界区)是指一个小代码段,在代码能够执行前,它必须独占对某资源的访问权。
VOID InitializeCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
// address of critical
// section object
VOID DeleteCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
// pointer to critical
// section object
VOID EnterCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
// pointer to critical
// section object
VOID LeaveCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
// address of critical
// section object
原代码如下:
#include &windows.h&
#include &iostream.h&
int ticket=100;
DWORD WINAPI Fun1Proc(LPVOID lpParameter);
DWORD WINAPI Fun2Proc(LPVOID lpParameter);
CRITICAL_SECTION g_
void main()
InitializeCriticalSection(&g_cs);
HANDLE thread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
HANDLE thread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(thread1);
CloseHandle(thread2);
Sleep(4000);
DeleteCriticalSection(&g_cs);
DWORD WINAPI Fun1Proc(LPVOID lpParameter)
while(TRUE)
EnterCriticalSection(&g_cs);
if(ticket&0)
cout&&&thread1 sells : &&&ticket--&&
LeaveCriticalSection(&g_cs);
DWORD WINAPI Fun2Proc(LPVOID lpParameter)
while(TRUE)
EnterCriticalSection(&g_cs);
if(ticket&0)
cout&&&thread2 sells : &&&ticket--&&
LeaveCriticalSection(&g_cs);
互斥对象、事件对象与关键代码段的比较
互斥对象和事件对象属于内核对象,利用内核对象进行线程同步,速度较慢,但利用互斥对象和事件对象这样的内河对象,可以在多个进程中的各个线程间进行同步。
关键代码段时工作在用户方式下,同步速度较快,但在使用关键代码段时,很容易进入死锁状态,因为在等待进入关键代码段时无法设定超时值
//---------------------------------------------------------------------------
基于消息的异步套接字
Windows套接字在两种模式下执行I/O操作,阻塞和非阻塞。在阻塞模式下,在I/O操作完成前,执行操作的Winsock函数会一直等待下去,不会立即返回程序(将控制权交还给程序)。而在非阻塞模式下,Winsock函数无论如何都会立即返回。
Windows Sockets为了支持Windows消息驱动机制,使应用程序开发者能够方便地处理网络通信,它对网络事件采用了基于消息的异步存取策略。
Windows Sockets的异步选择函数WSAAsyncSelect()提供了消息机制的网络事件选择,当使用它登记的网络事件发生时,Windows应用程序相应的窗口函数将收到一个消息,消息中指示了发生的网络事件,以及与事件相关的一些信息。
Win32平台支持多种不同的网络协议,采用Winsock2就可以编写可直接使用任何一种协议的网络应用程序了。通过WSAEnumProtocols可以获得系统中安装的网络协议的的相关信息。
int WSAEnumProtocols (
LPINT lpiProtocols,
//若为NULL,返回所有可用协议信息,
//否则返回数组中所列协议信息。
LPWSAPROTOCOL_INFO lpProtocolBuffer,
//WSAPROTOCOL_INFO用来存放或得到一个指定协议的完整信息
ILPDWORD lpdwBufferLength
//指定传递给函数的缓冲区长度
SOCKET WSASocket (
int protocol,
LPWSAPROTOCOL_INFO lpProtocolInfo,
DWORD dwFlags
lpProtocolInfo 是指向WSAPROTOCOL_INFO结构体的指针,该结构定义了所创建的套接字的特性。如果为NULL,WinSock2.DLL使用前三个参数来决 定使用哪一个服务提供者,他选择能够支持规定的抵制族、套接字类型和协议值的第一个传输提供者。如果不为NULL,则套接字绑定到与指定的结构 WSAPROTOCOL_INFO相关的提供者
调用WSAAsyncSelect请求一个windows的基于消息的网络事件通知
int WSAAsyncSelect (
HWND hWnd,
unsigned int wMsg,
long lEvent
接收数据:
int WSARecvFrom (
//标识套接字的描述符
LPWSABUF lpBuffers,
//指向WSABUF的指针,每一个包含WSABUF包含一个
//缓冲区的指针和缓冲区的长度
DWORD dwBufferCount,
//lpBuffers数组中WSABUF结构体的长度
LPDWORD lpNumberOfBytesRecvd,
//如果接收操作立即完成,则为指向本次调用接受
//字节数的指针
LPDWORD lpFlags,
struct sockaddr FAR * lpFrom,
//指向重叠操作完成后存放原地址的缓冲区
LPINT lpFromlen,
//指向From缓冲区大小的指针,制定了 lpFrom才需要
LPWSAOVERLAPPED lpOverlapped, //指向WSAOVERLAPPED
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionROUTINE
//指向接收操作完成时调用的完成例程的指针
为了调用高版本的套接字,我们要调用WSAStartup来制定套接字版本:
在BOOL CChatApp::InitInstance()中添加代码如下:
WORD wVersionR
WSADATA wsaD
wVersionRequested = MAKEWORD( 2, 2 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 )
return FALSE;
if ( LOBYTE( wsaData.wVersion ) != 2 ||
HIBYTE( wsaData.wVersion ) != 2 )
WSACleanup( );
return FALSE;
接下来编写函数初始化套接字,步骤如下:
1。新建套接字
2。新建地址。
4。请求一个windows的基于消息的网络事件通知
5。在BOOL CChatDlg::OnInitDialog()中调用BOOL CChatDlg::InitSocket()
代码如下:
BOOL CChatDlg::InitSocket()
m_socket=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,0);
if(INVALID_SOCKET=m_socket)
MessageBox(&套接字创建失败&);
return FALSE;
SOCKADDR_IN addrS
addrSock.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
addrSock.sin_family=AF_INET;
addrSock.sin_port=htons(6000);
if(SOCKET_ERROR==bind(m_socket,(SOCKADDR*)&addrSock,sizeof(SOCKADDR)))
MessageBox(&绑定失败!&);
return FALSE;
if(SOCKET_ERROR==WSAAsyncSelect(m_socket,m_hWnd,UM_SOCK,FD_READ))
MessageBox(&注册网络读取事件失败!&);
return FALSE;
自定义消息响应函数步骤:
1。在ChatDlg.h中定义#define UM_SOCK
//{{AFX_MSG(CChatDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
afx_msg LRESULT OnSock(WPARAM wParam,LPARAM lParam);
//注意返回值类型
BEGIN_MESSAGE_MAP(CChatDlg, CDialog)
//{{AFX_MSG_MAP(CChatDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
中添加消息映射
ON_MESSAGE(UM_SOCK,OnSock)
//此处不加标点
4。实现消息响应函数
LRESULT CChatDlg::OnSock(WPARAM wParam,LPARAM lParam)
switch(LOWORD(lParam))
case FD_READ:
wsabuf.buf=new char[200];
wsabuf.len=200;
DWORD dwFlag=0;
SOCKADDR_IN addrF
int len=sizeof(SOCKADDR);
CString strT
if(SOCKET_ERROR==WSARecvFrom(m_socket,&wsabuf,1,&dwRead,&dwFlag,
(SOCKADDR*)&addrFrom,&len,NULL,NULL))
MessageBox(&接收数据失败!&);
return FALSE;
str.Format(&%s speak : %s&,inet_ntoa(addrFrom.sin_addr),wsabuf.buf);
str+=&\r\n&;
GetDlgItemText(IDC_EDIT_RECV,strTemp);
SetDlgItemText(IDC_EDIT_RECV,str);
注意,此程序的接收端和发送端是在同一个线程下完成的,如果我们采用阻塞套接字会因为接收函数的调用而使主线程暂停运行。这样我们采用异步选择的机制完成了主线程的接收端和发送端
如果我们不想总是输入IP地址而是想输入主机名,可以调用函数
struct hostent* FAR gethostbyname(
const char* name
在对话框上新建一个文本框
HOSTENT * pH
GetDlgItemText(IDC_EDIT_HOSTNAME,strHostName);
if(strHostName==&&)
((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS))-&GetAddress(dwIP);
addrTo.sin_addr.S_un.S_addr=htonl(dwIP);
pHost=gethostbyname(strHostName);
addrTo.sin_addr.S_un.S_addr=*((DWORD*)pHost-&h_addr_list[0]);
用DWORD取出的四个字节,正好是网络字节序表示的ULONG类型的地址。
这段代码在教学视频上在文本框中输入的是“sunxin”,我认为那是那台电脑的在网络上的主机名,而在我的电脑上只能输入“localhost”,或者我的主机名,否则程序异常中止。
如果要在接收数据框中显示主机名,
在LRESULT CChatDlg::OnSock(WPARAM wParam,LPARAM lParam)中添加如下代码:
HOSTENT *pH pHost=gethostbyaddr((char*)&addrFrom.sin_addr.S_un.S_addr,4,AF_INET);
str.Format(&%s speak : %s&,pHost-&h_name,wsabuf.buf);
注意:指针之间可以任意转换,以上代码把一个ulong类型转换为char*,要先取地址再进行转换。
记住两个函数
The inet_ntoa function converts an (Ipv4) Internet network address into a string in Internet standard dotted format.
The inet_addr function converts a string containing an (Ipv4) Internet Protocol dotted address into a proper address for the IN_ADDR structure.
代码:// ChatDlg.cpp : implementation file
CChatDlg::~CChatDlg()
if(m_socket)
closesocket(m_socket);
BOOL CChatDlg::OnInitDialog()
CDialog::OnInitDialog();
............
InitSocket();
.............
BOOL CChatDlg::InitSocket()
m_socket=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,0);
if(INVALID_SOCKET==m_socket)
MessageBox(&创建套接字失败!&);
return FALSE;
SOCKADDR_IN addrS
addrSock.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
addrSock.sin_family=AF_INET;
addrSock.sin_port=htons(6000);
if(SOCKET_ERROR==bind(m_socket,(SOCKADDR*)&addrSock,sizeof(SOCKADDR)))
MessageBox(&绑定失败!&);
return FALSE;
if(SOCKET_ERROR==WSAAsyncSelect(m_socket,m_hWnd,UM_SOCK,FD_READ))//启用异步
MessageBox(&注册网络读取事件失败!&);
return FALSE;
return TRUE;
void CChatDlg::OnSock(WPARAM wParam,LPARAM lParam)
switch(LOWORD(lParam))
case FD_READ:
wsabuf.buf=new char[200];
wsabuf.len=200;
DWORD dwFlag=0;
SOCKADDR_IN addrF
int len=sizeof(SOCKADDR);
CString strT
HOSTENT *pH
if(SOCKET_ERROR==WSARecvFrom(m_socket,&wsabuf,1,&dwRead,&dwFlag,
(SOCKADDR*)&addrFrom,&len,NULL,NULL))
MessageBox(&接收数据失败!&);
pHost=gethostbyaddr((char*)&addrFrom.sin_addr.S_un.S_addr,4,AF_INET);
//str.Format(&%s说 :%s&,inet_ntoa(addrFrom.sin_addr),wsabuf.buf);
str.Format(&%s说 :%s&,pHost-&h_name,wsabuf.buf);
str+=&\r\n&;
GetDlgItemText(IDC_EDIT_RECV,strTemp);
SetDlgItemText(IDC_EDIT_RECV,str);
void CChatDlg::OnBtnSend()
// TODO: Add your control notification handler code here
DWORD dwIP;
CString strS
CString strHostN
SOCKADDR_IN addrTo;
HOSTENT* pH
if(GetDlgItemText(IDC_EDIT_HOSTNAME,strHostName),strHostName==&&)
((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))-&GetAddress(dwIP);
addrTo.sin_addr.S_un.S_addr=htonl(dwIP);
pHost=gethostbyname(strHostName);
addrTo.sin_addr.S_un.S_addr=*((DWORD*)pHost-&h_addr_list[0]);
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;
SetDlgItemText(IDC_EDIT_SEND,&&);
if(SOCKET_ERROR==WSASendTo(m_socket,&wsabuf,1,&dwSend,0,
(SOCKADDR*)&addrTo,sizeof(SOCKADDR),NULL,NULL))
MessageBox(&发送数据失败!&);
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:144205次
积分:3087
积分:3087
排名:第7612名
原创:162篇
转载:76篇
(4)(5)(1)(7)(5)(6)(5)(7)(5)(31)(5)(8)(10)(1)(5)(1)(5)(24)(19)(9)(19)(8)(20)(28)}

我要回帖

更多关于 原始套接字 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信