初识用UDP协议做的windows窗口聊天程序---此处是双向的"异步"多线程对话框通信.

第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;
}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值