UDP即时通信
式,接收方负责信息的接收,并能够返回给客户端相应的消息;发送方负
责向接收方发送信息。
1.完成实验要求UDP之间通信;
2.实现模拟C/S模型的通信方式,接收方负责信息的接收,并能够返回给客户端相应的消息;发送方负责向接收方发送信息。3.完成数据的传送信息;
完成大致步骤:
1.首先创建一个先项目工程,特别注意是在高级选项卡中选择套接字,然后将工程名为UDProcsComm;项目完成创建完成之后,选择资源视图,然后在对话框中开始设置界面格式:首先将界面设计区的“确定”修改成“启动”,在属性选项卡中选择caption属性,“取消”按钮修改成“退出”;在工具箱中,选择列表框、IP地址,编辑框,按钮,静态编辑框以及组合框等控件,然后选择这些控件,以及在属性中选择ID选项,将控件的ID修改,同时右击控件,选择添加事件处理程序,依次在主对话框中的cpp文件中添加
事件处理程序,实现这些控件的功能需求;
2.编写代码实现:
首先在UDProcsCommDlg.h头文件中定义变量和声明一些方法,用于连接客户端的请求,以及SOCKET的结构,收发消息的结构体;然后在UDProcsCommDlg.cpp文件中完善主对话框的构造函数,将端口等控件的初始值设置成0;同时在主对话框中的初始化函数(OnInitDialog)将界面中的一些控件设置成false;
设置“启动”按钮的事件处理程序:首先添加OnOK函数,在函数中首先将界面用updateData()函数更新一下,然后利用函数判断端口号以及IP是否为空,同时给出相应的提示语句;在函数中首先初始化和绑定IP地址,调用Windows SocketDLL 进行初始化,然后创建本机进程的Socket,建立无连接之间的通信;然后在实现获取IP地址的编程语句,编写语句绑定与设置相同的端口号,自定义消息产生相应传递给窗口的消息,然后调用Enablewindow()函数,设置界面上的控件信息,;
在“stdafx.h”的头文件中,定义宏,以及结构体msg变量;在对话框中cpp文件中定义消息宏映射;
在主对话框中添加OnReadClose()函数中自定义关闭和缓冲区的消息;同时,添加“停止”,“发送”按钮的事件处理函数,在OnStop函数时将界面上的控件设置成false和true;当程序运行停止时,将Socket清空;在OnSend函数中,获取IP地址的相关信息,将数据进行发送;
1.在项目中的资视图中,选择dialog,设置页面布局,在界面上添加一些控件,IP地址、编辑框、按钮等控件,同时在右击各个控件选择添加变量,将控件和变量关联在一起,同时为控件添加事件处理函数;
1.完成程序编写后,启动运行调试程序,首先设置本机IP地址为127.0.0.1,端口号设置为1035,然后点击启动,同时在信息列表框中提示启动成功等信息;
源代码:
// UDProcsComm.cpp : 定义应用程序的类行为。
//
#include "stdafx.h"
#include "UDProcsComm.h"
#include "UDProcsCommDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CUDProcsCommApp
BEGIN_MESSAGE_MAP(CUDProcsCommApp, CWinApp)
ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()
// CUDProcsCommApp 构造
CUDProcsCommApp::CUDProcsCommApp()
{
// 支持重新启动管理器
m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;
// TODO: 在此处添加构造代码,
// 将所有重要的初始化放置在 InitInstance 中
}
// 唯一的一个 CUDProcsCommApp 对象
CUDProcsCommApp theApp;
// CUDProcsCommApp 初始化
BOOL CUDProcsCommApp::InitInstance()
{
// 如果一个运行在 Windows XP 上的应用程序清单指定要
// 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式,
//则需要 InitCommonControlsEx()。否则,将无法创建窗口。
INITCOMMONCONTROLSEX InitCtrls;
InitCtrls.dwSize = sizeof(InitCtrls);
// 将它设置为包括所有要在应用程序中使用的
// 公共控件类。
InitCtrls.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&InitCtrls);
CWinApp::InitInstance();
if (!AfxSocketInit())
{
AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
return FALSE;
}
AfxEnableControlContainer();
// 创建 shell 管理器,以防对话框包含
// 任何 shell 树视图控件或 shell 列表视图控件。
CShellManager *pShellManager = new CShellManager;
// 标准初始化
// 如果未使用这些功能并希望减小
// 最终可执行文件的大小,则应移除下列
// 不需要的特定初始化例程
// 更改用于存储设置的注册表项
// TODO: 应适当修改该字符串,
// 例如修改为公司或组织名
SetRegistryKey(_T("应用程序向导生成的本地应用程序"));
CUDProcsCommDlg dlg;
m_pMainWnd = &dlg;
INT_PTR nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: 在此放置处理何时用
// “确定”来关闭对话框的代码
}
else if (nResponse == IDCANCEL)
{
// TODO: 在此放置处理何时用
// “取消”来关闭对话框的代码
}
// 删除上面创建的 shell 管理器。
if (pShellManager != NULL)
{
delete pShellManager;
}
// 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序,
// 而不是启动应用程序的消息泵。
return FALSE;
}
// UDProcsCommDlg.cpp : 实现文件
//
#include "stdafx.h"
#include "UDProcsComm.h"
#include "UDProcsCommDlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// 对话框数据
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
//ADD
END_MESSAGE_MAP()
//ADD
// CUDProcsCommDlg 对话框
CUDProcsCommDlg::CUDProcsCommDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CUDProcsCommDlg::IDD, pParent)
, LocalPort(_T(""))
, DestPort(_T(""))
, str(_T(""))
{
str=_T("");
m_sport=0;
m_dport=0;
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
IsTrue=FALSE;
Client=INVALID_SOCKET;
}
void CUDProcsCommDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_IPLOCAL, IPLocal);
DDX_Control(pDX, IDC_PORTLOCAL, PortLocal);
DDX_Text(pDX, IDC_PORTLOCAL, LocalPort);
DDX_Control(pDX, IDOK, m_Start);
DDX_Control(pDX, IDC_STOP, m_Stop);
DDX_Control(pDX, IDC_IPDEST, IPDest);
DDX_Control(pDX, IDC_PORTDEST, PortDest);
DDX_Text(pDX, IDC_PORTDEST, DestPort);
DDX_Control(pDX, IDC_EDITWORDS, m_EditWords);
DDX_Text(pDX, IDC_EDITWORDS, str);
DDX_Control(pDX, IDC_SEND, m_Send);
DDX_Control(pDX, IDC_LIST, list);
DDX_Control(pDX, IDCANCEL, m_Exit);
}
BEGIN_MESSAGE_MAP(CUDProcsCommDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_STOP, &CUDProcsCommDlg::OnBnClickedStop)
ON_BN_CLICKED(IDC_SEND, &CUDProcsCommDlg::OnBnClickedSend)
//ADD
ON_MESSAGE(WM_CLIENT_READCLOSE,OnReadClose)
END_MESSAGE_MAP()
// CUDProcsCommDlg 消息处理程序
BOOL CUDProcsCommDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
//ADD
IPLocal.SetFocus();
list.EnableWindow(false);
m_Stop.EnableWindow(false);
IPDest.EnableWindow(false);
PortDest.EnableWindow(false);
m_EditWords.EnableWindow(false);
m_Send.EnableWindow(false);
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CUDProcsCommDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CUDProcsCommDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CUDProcsCommDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CUDProcsCommDlg::OnOK()
{
// TODO: 在此添加专用代码和/或调用基类
//ADD
UpdateData();
if(IPLocal.IsBlank())
{
AfxMessageBox("请设置IP地址!");
return ;
}
if(LocalPort.IsEmpty())
{
AfxMessageBox("请设置端口号!");
return ;
}
WSADATA wsaData;
int iErrorCode;
if(WSAStartup(MAKEWORD(2,1),&wsaData))
{
list.AddString("Winsock无法初始化!");
WSACleanup();
return ;
}
list.AddString("开始创建Socket...");
ServerSocket=socket(PF_INET,SOCK_DGRAM,0);
if(ServerSocket==INVALID_SOCKET)
{
list.AddString("创建Socket失败!");
return ;
}
BYTE nFild[4];
CString sIP;
IPLocal.GetAddress(nFild[0],nFild[1],nFild[2],nFild[3]);
sIP.Format("%d.%d.%d.%d",nFild[0],nFild[1],nFild[2],nFild[3]);
m_sockServerAddr.sin_family=AF_INET;
m_sockServerAddr.sin_addr.s_addr=inet_addr(sIP);
m_sockServerAddr.sin_port=htons(atoi(LocalPort));
socklen=sizeof(m_sockServerAddr);
if(bind(ServerSocket,(LPSOCKADDR)&m_sockServerAddr,sizeof(m_sockServerAddr))==SOCKET_ERROR)
{
list.AddString("绑定失败!");
return ;
}
iErrorCode=WSAAsyncSelect(ServerSocket,m_hWnd,WM_CLIENT_READCLOSE,FD_READ);
if(iErrorCode==SOCKET_ERROR)
{
list.AddString("WSAAsyncSelect设定失败!--用户连接请求的消息");
return ;
}
list.AddString("本机进程启动成功!");
list.AddString("地址"+sIP+" 端口"+LocalPort);
this->SetWindowTextA("本机应用进程("+sIP+":"+LocalPort+")-UDProcsComm");
IPLocal.EnableWindow(false);
PortLocal.EnableWindow(false);
m_Start.EnableWindow(false);
m_Stop.EnableWindow(true);
IPDest.EnableWindow(true);
IPDest.SetFocus();
PortDest.EnableWindow(true);
m_EditWords.EnableWindow(true);
m_Send.EnableWindow(true);
list.EnableWindow(true);
m_Exit.EnableWindow(false);
return ;
CDialogEx::OnOK();
}
LRESULT CUDProcsCommDlg::OnReadClose(WPARAM wParam,LPARAM lParam)
{
CString str;
switch(WSAGETSELECTEVENT(lParam))
{
case FD_READ:
if(recvfrom(ServerSocket,(char *)&msg,sizeof(msg),0,(LPSOCKADDR)&m_sockServerAddr,(int *)&socklen)==SOCKET_ERROR)
{
list.AddString("发送失败!对方主机或应用进程没有启动");
return 0;
}
str.Format("%s",msg.msg);
list.AddString(str);
break;
}
return 0L;
}
void CUDProcsCommDlg::OnBnClickedStop()
{
// TODO: 在此添加控件通知处理程序代码
list.AddString("正在关闭Socket...");
closesocket(ServerSocket);
WSACleanup();
list.AddString("本机进程停止运行!");
m_Start.EnableWindow(false);
m_Stop.EnableWindow(false);
list.EnableWindow(false);
IPLocal.SetFocus();
IPDest.EnableWindow(false);
PortDest.EnableWindow(false);
m_EditWords.EnableWindow(false);
m_Send.EnableWindow(false);
m_Exit.EnableWindow(true);
}
void CUDProcsCommDlg::OnBnClickedSend()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData();
if(IPDest.IsBlank())
{
AfxMessageBox("请指定目标进程所在主机的IP地址!");
return ;
}
if(DestPort.IsEmpty())
{
AfxMessageBox("请指定目标进程的端口号!");
return ;
}
BYTE nFild[4];
CString sIP;
IPLocal.GetAddress(nFild[0],nFild[1],nFild[2],nFild[3]);
sIP.Format("%d.%d.%d.%d",nFild[0],nFild[1],nFild[2],nFild[3]);
m_sockAddrto.sin_family=AF_INET;
m_sockAddrto.sin_addr.s_addr=inet_addr(sIP);
m_sockAddrto.sin_port=htons(atoi(DestPort));
if(str.IsEmpty())
{
AfxMessageBox("发送的消息不能为空!");
return ;
}
strcpy(msg.msg,(LPCTSTR)str);
msg.i=0;
if(sendto(ServerSocket,(char *)&msg,sizeof(msg),0,(LPSOCKADDR)&m_sockAddrto,sizeof(m_sockAddrto))==SOCKET_ERROR)
{
list.AddString("发送消息失败!");
}
str.Empty();
UpdateData(FALSE);
}
// UDProcsCommDlg.h : 头文件
//
#pragma once
#include "afxcmn.h"
#include "afxwin.h"
// CUDProcsCommDlg 对话框
class CUDProcsCommDlg : public CDialogEx
{
// 构造
public:
CUDProcsCommDlg(CWnd* pParent = NULL); // 标准构造函数
// 对话框数据
enum { IDD = IDD_UDPROCSCOMM_DIALOG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
HICON m_hIcon;
// 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
CIPAddressCtrl IPLocal;
CEdit PortLocal;
CString LocalPort;
CButton m_Start;
CButton m_Stop;
CIPAddressCtrl IPDest;
CEdit PortDest;
CString DestPort;
CEdit m_EditWords;
CString str;
CButton m_Send;
CListBox list;
CButton m_Exit;
//ADD
SOCKET Client;
SOCKET ServerSocket;
SOCKADDR_IN m_sockServerAddr;
SOCKADDR_IN m_sockAddrto;
LRESULT OnReadClose(WPARAM wParam,LPARAM IParam);
int socklen;
BOOL IsTrue;
Msg msg;//收发消息的结构体
UINT m_sport;
UINT m_dport;
virtual void OnOK();
afx_msg void OnBnClickedStop();
afx_msg void OnBnClickedSend();
};