UDP即時通信

編寫一個基於某種I/O方法的UDP應用程序:能夠實現模擬C/S模型的通信方

式,接收方負責信息的接收,並能夠返回給客戶端相應的消息;發送方負

責向接收方發送信息。

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();
    
};











發佈了30 篇原創文章 · 獲贊 8 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章