您的位置:首页 > 其它

MFC基于对话框框架的简易飞鸽系统(四)----群发信息

2018-03-11 12:23 489 查看
实现过程第一篇已经写了,这里就是具体的代码实现过程了。先看一下群发信息的界面:



GroupChatDlg.h#pragma once
#include "afxwin.h"
#include "afxcmn.h"
#include <WinSock2.h>
#include <stdio.h>
#include <iostream>

using namespace std;

#pragma comment(lib, "ws2_32.lib")

#define GROUP_PORT 12822

#define WM_UPDATE_GROUP (WM_USER + 100)

// GroupChatDlg 对话框

class GroupChatDlg : public CDialog
{
DECLARE_DYNAMIC(GroupChatDlg)

public:
GroupChatDlg(CWnd* pParent = NULL); // 标准构造函数
virtual ~GroupChatDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_DIALOG1 };
#endif

protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
virtual BOOL OnInitDialog();
DECLARE_MESSAGE_MAP()
public:
CStatic group_name; //显示群的名字
CListBox group_infList; // 显示群成员发送的消息列表
CEdit group_Msg; // 显示在群里发送的消息

CWinThread * recvThread; // 接收普通udp信息的线程
CFont cfont2; // 自定义的字体
CString group_names; // 所有的群成员名字用一个CString来表示,中间用!隔开
CString group_ips; // 所有的群成员的ip用一个CString来表示,中间用!隔开
//vector<CString> names; // 将所有的成员名解析到一个vector中
//vector<CString> ips; // 将所有成员的ip解析到一个vector中
static UINT RecvUDPThread(LPVOID pParam); // 自定义的接收普通udp信息的线程
afx_msg LRESULT OnUpdateGroup(WPARAM wParam, LPARAM lParam); // 处理接收到的自定义消息
afx_msg void OnBnClickedSendgMsg();
};
GroupChatDlg.cpp// GroupChatDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "FeiGe.h"
#include "GroupChatDlg.h"
#include "afxdialogex.h"
#include <vector>
#include "string"
#include <tchar.h>

vector<CString> names; // 存放群内所有主机名
vector<CString> ips; // 存放群里所有主机ip
static CListCtrl group_memberList;// 显示群成员信息列表
// GroupChatDlg 对话框

IMPLEMENT_DYNAMIC(GroupChatDlg, CDialog)

GroupChatDlg::GroupChatDlg(CWnd* pParent /*=NULL*/)
: CDialog(IDD_DIALOG1, pParent)
{

}

GroupChatDlg::~GroupChatDlg()
{
}

void GroupChatDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_GROUP_NAME, group_name);
DDX_Control(pDX, IDC_GINF_LIST, group_infList);
DDX_Control(pDX, IDC_EDITG_MSG, group_Msg);
DDX_Control(pDX, IDC_GROUP_LIST, group_memberList);
}

BEGIN_MESSAGE_MAP(GroupChatDlg, CDialog)
ON_BN_CLICKED(IDC_SENDG_MSG, &GroupChatDlg::OnBnClickedSendgMsg)
ON_MESSAGE(WM_UPDATE_GROUP, &GroupChatDlg::OnUpdateGroup)
END_MESSAGE_MAP()
// 分割字符串
// 将结果以一个vector<CString>形式返回
vector<CString> split3(CString strSource, CString ch) {
vector<CString> result;
int iPos = 0;
CString strTmp;
strTmp = strSource.Tokenize(ch, iPos);
while (strTmp.Trim() != _T(""))
{
result.push_back(strTmp);
strTmp = strSource.Tokenize(ch, iPos);
}
return result;
}

// 获取本地主机的主机名
CString GetMyName()
{
//1.初始化wsa
WSADATA wsaData;
int ret = WSAStartup(MAKEWORD(2, 2), &wsaData);
//2.获取主机名
char hostname[256];
ret = gethostname(hostname, sizeof(hostname));
if (ret == SOCKET_ERROR)
{
return false;
}
::WSACleanup();
return hostname;
}
// 接受自定义的消息,并更新控件
LRESULT GroupChatDlg::OnUpdateGroup(WPARAM wParam, LPARAM lParam)
{
CString inf;
inf = *((CString*)wParam);

if (split3(inf, "!").size() == 2)
{
// 如果是想要发送文本信息
// 将要发送的字符串以一定格式输出
CString myText;
myText += split3(inf, "!")[0];
myText += " :(";
CTime m_time;
CString time;
m_time = CTime::GetCurrentTime(); //获取当前时间日期
time = m_time.Format(_T("%Y-%m-%d %H:%M:%S %A")); //格式化日期时间
myText += time;
myText += ")";
myText += "\r\n";
int length = group_infList.GetCount();
group_infList.InsertString(length, myText);
CString content = " ";
content += split3(inf, "!")[1];
int length2 = group_infList.GetCount();
group_infList.InsertString(length2, content);
}

return 0;
}
// 接受UDP信息线程
UINT GroupChatDlg::RecvUDPThread(LPVOID pParam)
{
GroupChatDlg *pDlg = (GroupChatDlg *)pParam;
//初始化网络环境
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
{
AfxMessageBox("WSAStartup failed\n", MB_OK, 0);
return -1;
}

//建立一个UDP的socket
SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == SOCKET_ERROR)
{

AfxMessageBox("create socket failed\n", MB_OK, 0);
return -1;
}

//绑定地址信息
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(GROUP_PORT);
serverAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);

bind(sock, (sockaddr*)&serverAddr, sizeof(sockaddr));
char buf[512];
while (true)
{
memset(buf, 0, 512);
// 网络节点的信息,用来保存客户端的网络信息
sockaddr_in clientAddr;

memset(&clientAddr, 0, sizeof(sockaddr_in));

int clientAddrLen = sizeof(sockaddr);
//接收客户端发来的数据
int ret = recvfrom(sock, buf, 512, 0, (sockaddr*)&clientAddr, &clientAddrLen);
CString inf = buf;
if (strlen(inf) >= 1)
{

// 发送消息通知主线程更新控件内容
::PostMessage(pDlg->m_hWnd, WM_UPDATE_GROUP, (WPARAM)(&inf), 0);
}
Sleep(1000);
}
return 0;
}
// 初始化群成员对话框
BOOL GroupChatDlg::OnInitDialog()
{

CDialog::OnInitDialog();

// TODO: 在此添加额外的初始化代码
// 初始化表格
group_memberList.ModifyStyle(0, LVS_REPORT); // 报表模式
group_memberList.SetExtendedStyle(group_memberList.GetExtendedStyle() | LVS_EX_GRIDLINES ); // 间隔线
// 插入表头
group_memberList.InsertColumn(0, "群成员");
group_memberList.InsertColumn(1, "IP");
CRect rect;
group_memberList.GetClientRect(rect); //获得当前客户区信息
group_memberList.SetColumnWidth(0, rect.Width()/2); //设置列的宽度。
group_memberList.SetColumnWidth(1, rect.Width() / 2); //设置列的宽度。

// 设置对话群的名称字体
cfont2.CreatePointFont(150, _T("黑体"), NULL);
GetDlgItem(IDC_GROUP_NAME)->SetFont(&cfont2);
group_name.SetWindowTextA("简易飞鸽开发交流群");

// 初始化群成员信息列表
names = split3(group_names, "!");
ips = split3(group_ips, "!");
for (int i = 0; i < names.size(); i++)
{
group_memberList.InsertItem(i,names[i]);
group_memberList.SetItemText(i,1,ips[i]);
}

// 启动接收普通信息的线程
recvThread = AfxBeginThread((AFX_THREADPROC)RecvUDPThread, this);
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}

// 群发消息
void GroupChatDlg::OnBnClickedSendgMsg()
{
// TODO: 在此添加控件通知处理程序代码
WORD wVersionRequested;
WSADATA wsaData;
int err;
// 启动socket api
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0)
{
AfxMessageBox("不支持2.2版本", MB_OK);
}
// 创建并绑定udp套接字
//建立一个UDP的socket
SOCKET udp_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

// 将要发送的字符串以一定格式输出
CString sendText, edit_text;
// 给发送的信息之前加上主机名
CString host_name = GetMyName();
sendText += host_name;
sendText += "!";

GetDlgItem(IDC_EDITG_MSG)->GetWindowText(edit_text);
// 将自己发的消息添加到消息列表中
sendText += edit_text;
// 发送文本信息sd
// 添加一个“回车换行”
// 注意,添加它并不是必须的,但是如果使用本软件作为客户端调试网络协议,
// 比如SMTP、FTP等,就要添加它了。因为这些协议都要求使用“回车换行”作为一个命令的结束标记
sendText += "\r\n";
// 通过遍历ips中的所有ip地址,将消息发给每一个人
for (int i =
a34b
0; i < ips.size(); i++)
{
// 填写要发送信息的地址
sockaddr_in toAddr;
toAddr.sin_family = AF_INET;
toAddr.sin_port = htons(GROUP_PORT);
toAddr.sin_addr.S_un.S_addr = inet_addr(ips[i]);
int length = sendto(udp_socket, sendText, strlen(sendText), 0, (SOCKADDR*)&toAddr, sizeof(SOCKADDR));
if (SOCKET_ERROR == length)
{
AfxMessageBox("发送UDP信息错误", MB_OK);
}
}
// 清空文本编辑框
group_Msg.SetWindowTextA("");
closesocket(udp_socket);
::WSACleanup();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  MFC UDP群发消息