式,接收方負責信息的接收,並能夠返回給客戶端相應的消息;發送方負
責向接收方發送信息。
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();
};