第1部分:更新版说明 第2部分:更新心得 第3部分:更新知识点讲解 第4部分:实例代码与效果图演示--------
------------------第1部分:更新版说明----------------------
更新版1,在以前基础上增加了新的功能,上个版中,只能A方发给B方,B方却不能发给A方,因为当时的版本仅为教学,认清原理,所以不太完善.更新版,就弥补了这个缺陷,A方能发给B方,B方也能发给A方
------------------第2部分:更新心得----------------------
不会前,觉得好难好难,会做后,觉得好简单好简单,现在我都懒的看了,因为那原理实在是太简单了
参考了很多资料:网上的,书上的.论坛的,QQ群的,研究了几天.调试了至少100次以上,几乎是每改动一次,我就运行一次,看下有什么效果,然后把其效果保存下来,一个一个对比,一个一个总结.
这里最大的功臣莫过于,以前自己做的笔记<<初识用UDP协议做的DOS窗口聊天程序---其实是<<初识UDP网络编程>>的增加版而已>>,那是用DOS写的,那是很单纯的原理,一收一接,一接一收,A方能发给B方,为什么B方不能同时发给A方呢?原理上,完全正确.(注意:千万要相信原理,围绕着原理走.)
图中你会发现,有2个发送按钮,有人会问?为什么不把它写到一块呢?这里主要就是教学为主,在出产品的时候肯定不会这样写了.这里主要是让你清楚知道其中的原理,当然你可以定义一个BOOL值,if.else判断下,就可以合二为一个发送按钮了.
最后是使用效果:第1步,A建立服务端.B连接服务端.
第2步:连接客户端的同时要发送一个欢迎消息,或者空消息,给服务端,让服务端接收你的SOCKADDR_IN参数,否则会造成,服务端给客户端第1次发送消息时失败,因为服务端,并不知道客户端是谁
------------------第3部分:更新知识点讲解----------------------
知识点一:摘抄自原书1.1.4 Winsock的异步模式------------WSAAsyncSelect的设定是针对某一个Socket,如果开启了很多Socket,那么必须都呼叫其一一设定
这句话的意思是.服务端要创建一个,客户端也要创建一个
------------------实例代码与效果图演示----------------------
BOOL CMy3Dlg::InitSock()
{
第2步:创建socket//
m_socket=WSASocket(AF_INET,SOCK_DGRAM,0,0,0,0);
if(INVALID_SOCKET==m_socket)
{
MessageBox("创建套接字失败!");
return FALSE;
}
return TRUE;//创建完后就返回了.注:返回1,继续运行
}
void CMy3Dlg::OnRecv(WPARAM wParam,LPARAM lParam)
{
WSABUF wsabuf;wsabuf.buf=new char[50];wsabuf.len=50;
DWORD dwRead=0,dwFlag=0;int len=sizeof(SOCKADDR);
switch(LOWORD(lParam))
{
case FD_READ:
if(SOCKET_ERROR==WSARecvFrom(m_socket,&wsabuf,1,&dwRead,&dwFlag,(SOCKADDR*)&srecv,&len,0,0))
{
MessageBox("接收数据失败!");
return;
}
SetDlgItemText(IDE_RECV,wsabuf.buf);//str_recv.Format("%s",wsabuf.buf);即可实现添加
break;
case FD_WRITE:
新增
if(bw)
{
if(SOCKET_ERROR==WSASendTo(m_socket,&wsabuf,1,&dwRead,0,(SOCKADDR*)&ssend,sizeof(SOCKADDR),0,0))
{
MessageBox("FD_WRITE发送数据失败!");
DWORD dword=GetLastError();//WSANOTINITIALISED;由此可以找到MSDN上对应的错误列表
return;
}
bw=FALSE;
break;
}
}
delete[] wsabuf.buf;//或delete wsabuf.buf;
}
void CMy3Dlg::OnSendTo(WPARAM wParam,LPARAM lParam)
{
WSABUF wsabuf;wsabuf.buf=new char[50];wsabuf.len=50;
DWORD dwRead=0,dwFlag=0;SOCKADDR_IN srecv;
int len=sizeof(SOCKADDR);
switch(LOWORD(lParam))
{
case FD_READ:
if(SOCKET_ERROR==WSARecvFrom(m_socket,&wsabuf,1,&dwRead,&dwFlag,(SOCKADDR*)&srecv,&len,0,0))
{
MessageBox("接收数据失败!");
return;
}
SetDlgItemText(IDE_RECV,wsabuf.buf);//str_recv.Format("%s",wsabuf.buf);即可实现添加
break;
case FD_WRITE:
新增
if(bw)
{
if(SOCKET_ERROR==WSASendTo(m_socket,&wsabuf,1,&dwRead,0,(SOCKADDR*)&ssend,sizeof(SOCKADDR),0,0))
{
MessageBox("FD_WRITE发送数据失败!");
DWORD dword=GetLastError();//WSANOTINITIALISED;由此可以找到MSDN上对应的错误列表
return;
}
bw=FALSE;
break;
}
}
delete[] wsabuf.buf;//或delete wsabuf.buf;
}
void CMy3Dlg::OnSend()
{
CString str_send;GetDlgItemText(IDE_SEND,str_send);
WSABUF wsabuf;wsabuf.buf=str_send.GetBuffer(50);wsabuf.len=50;
DWORD dwSend;
if(SOCKET_ERROR==WSASendTo(m_socket,&wsabuf,1,&dwSend,0,(SOCKADDR*)&ssend,sizeof(SOCKADDR),0,0))
{
MessageBox("onsend发送数据失败!");
return;
}
SetDlgItemText(IDE_SEND,"");
}
void CMy3Dlg::OnS()
{
第3步:创建bind
CString str_cport;GetDlgItemText(IDE_S_PORT,str_cport);UINT m_cport;m_cport=UINT(atoi(LPCSTR(str_cport)));
sbind.sin_family=AF_INET;
sbind.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
sbind.sin_port=htons(m_cport);
if(SOCKET_ERROR==bind(m_socket,(SOCKADDR*)&sbind,sizeof(SOCKADDR)))
{
// MessageBox("绑定失败!");
closesocket(m_socket);
::PostMessage(m_hWnd,WM_RBIND,0,0);
return;
}
if(SOCKET_ERROR==WSAAsyncSelect(m_socket,m_hWnd,WM_RECV,FD_READ|FD_WRITE))
{
MessageBox("注册网络读取事件失败!");
return;
}
}
void CMy3Dlg::OnC()
{
/复制原有的
char serverIP[16]; CString str_cip;GetDlgItemText(IDE_C_IP,str_cip);strncpy(serverIP,LPCTSTR(str_cip),16);
CString str_cport;GetDlgItemText(IDE_C_PORT,str_cport);UINT m_cport;m_cport=UINT(atoi(LPCSTR(str_cport)));
ssend.sin_family=AF_INET;
ssend.sin_addr.S_un.S_addr=inet_addr(serverIP);
ssend.sin_port=htons(m_cport);
/复制完成//
//新增///
SetDlgItemText(IDE_SEND,"");
CString str_send;GetDlgItemText(IDE_SEND,str_send);
WSABUF wsabuf;wsabuf.buf=str_send.GetBuffer(50);wsabuf.len=50;
DWORD dwSend;
if(SOCKET_ERROR==WSASendTo(m_socket,&wsabuf,1,&dwSend,0,(SOCKADDR*)&ssend,sizeof(SOCKADDR),0,0))
{
MessageBox("onsend发送数据失败!");
return;
}
SetDlgItemText(IDE_SEND,"");
//新增
if(SOCKET_ERROR==WSAAsyncSelect(m_socket,m_hWnd,WM_SENDTO,FD_READ|FD_WRITE))
{
MessageBox("注册网络读取事件失败!");
return;
}
}
void CMy3Dlg::OnRbind()
{
InitSock();
OnS();
}
void CMy3Dlg::OnButton1()
{
CString str_send;GetDlgItemText(IDE_SEND,str_send);
WSABUF wsabuf;wsabuf.buf=str_send.GetBuffer(50);wsabuf.len=50;
DWORD dwSend;
if(SOCKET_ERROR==WSASendTo(m_socket,&wsabuf,1,&dwSend,0,(SOCKADDR*)&srecv,sizeof(SOCKADDR),0,0))
{
MessageBox("服务按钮发送数据失败!");
return;
}
SetDlgItemText(IDE_SEND,"");
bw=TRUE;
}
以上为全部代码(部分头文件与宏变量那些除外)
--------------------------------------------------------------
这仅仅是一个最基本的模型,有待后续...
附注:本例代码与编译结果,已保存至邮箱,即取即用
****************************************
以下是VS2010平台写的.最好的模型完成端口,是这个程序的升级版.代码如下
----------服务端
//第2步:创建套接字/
SOCKET sServer=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,NULL,WSA_FLAG_OVERLAPPED);//前面都是默认的,最后一个参数表示重叠的
if(sServer==INVALID_SOCKET){cout<<"创建套接字错误!"<<endl;closesocket(sServer);WSACleanup();}//或SOCKET_ERROR
//第3步:绑定套接字bind
SOCKADDR_IN addr_bind;
addr_bind.sin_family=AF_INET;
addr_bind.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
addr_bind.sin_port=htons(6000);
bind(sServer,(SOCKADDR*)&addr_bind,sizeof(SOCKADDR));
第4步:接受信息//
WSABUF wsabuf;wsabuf.buf=new char[50];wsabuf.len=50;
DWORD dwRead=0,dwFlag=0;int len=sizeof(SOCKADDR);SOCKADDR_IN addr_RecvFrom;
if(SOCKET_ERROR==WSARecvFrom(sServer,&wsabuf,1,&dwRead,&dwFlag,(SOCKADDR*)&addr_RecvFrom,&len,0,0))
{cout<<"接收数据错误!"<<endl;return 1;}//发布版时要删除,另外WSARecvFrom会执行等待,等有消息的到来
cout<<wsabuf.buf<<endl;
closesocket(sServer);WSACleanup();
return 0;
}
---------------------客户端:
//第2步:创建套接字/
sClient=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,NULL,WSA_FLAG_OVERLAPPED);//前面都是默认的,最后一个参数表示重叠的
if(sClient==INVALID_SOCKET){MessageBox(_T("创建套接字错误!"));closesocket(sClient);}//或SOCKET_ERROR
//第3步:发送消息///
WSABUF wsabuf;wsabuf.buf="你好";wsabuf.len=50;
DWORD dwSend;
SOCKADDR_IN addr_SendTo;
addr_SendTo.sin_family=AF_INET;
addr_SendTo.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
addr_SendTo.sin_port=htons(6000);
if(SOCKET_ERROR==WSASendTo(sClient,&wsabuf,1,&dwSend,0,(SOCKADDR*)&addr_SendTo,sizeof(SOCKADDR),0,0))
{
MessageBox(_T("发送数据失败!"));
return;
}
}