您的位置:首页 > 理论基础 > 计算机网络

MFC基于对话框框架的简易飞鸽系统(三)--单发文本信息和收发文件

2018-03-11 12:20 609 查看
实现过程第一篇已经写过了,这里就是具体的代码实现过程。
单发文本信息对话窗口:



选择文件对话窗口:



接收文件:



SecWin.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 UDP_PORT 12895
#define TCP_PORT 12811
#define WM_UPDATE_STATIC (WM_USER + 100)
#define BUFFER_SIZE 8192
#define FILE_NAME_MAX_SIZE 512
// SecWin 对话框

class SecWin : public CDialog
{
DECLARE_DYNAMIC(SecWin)

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

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

protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
virtual BOOL OnInitDialog();
DECLARE_MESSAGE_MAP()
public:
         CListBox infList; // 显示聊天记录的List Box
// 接收普通udp信息的线程
CWinThread * m_pThread;
// 接收tcp文件信息的线程
CWinThread * recvFileThread;
// 发送tcp文件信息的线程
CWinThread * sendFileThread;
static UINT ThreadFunction(LPVOID pParam);
static UINT RecvFileThread(LPVOID pParam);
static UINT SendFileThread(LPVOID pParam);
afx_msg LRESULT OnUpdateStatic(WPARAM wParam, LPARAM lParam);
afx_msg void OnBnClickedSendMsg();
std::string client_name; // 进行对话的主机名
std::string client_ip; // 进行对话的主机IP
CStatic friend_name;
CFont cfont;// 自定义的字体
afx_msg void OnClose();
CButton btn_recvFile;
CButton btn_rejectFile;
afx_msg void OnBnClickedReceiveFile();
afx_msg void OnBnClickedRejectFile();
afx_msg void OnBnClickedSendFile();
void SendIPAndFileName(CString inf);
};
SecwWin.cpp:
子线程不能更新主线程控件,只能发送一个消息主线程,然后主线程再更新界面控件
// SecWin.cpp : 实现文件
//

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

// 发送文件的主机ip
static CString host_ip ;
// 发送的文件名
static CString send_file_name ;
// 接收的文件名
static CString recv_file_name;
// SecWin 对话框

IMPLEMENT_DYNAMIC(SecWin, CDialog)

SecWin::SecWin(CWnd* pParent /*=NULL*/)
: CDialog(IDD_CHATTING_DIALOG, pParent)
{

}

SecWin::~SecWin()
{
}

void SecWin::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_HISTORY, infList);
DDX_Control(pDX, IDC_FRIEND_NAME, friend_name);
DDX_Control(pDX, IDC_RECEIVE_FILE, btn_recvFile);
DDX_Control(pDX, IDC_REJECT_FILE, btn_rejectFile);
}

BEGIN_MESSAGE_MAP(SecWin, CDialog)

ON_BN_CLICKED(IDC_SEND_MSG, &SecWin::OnBnClickedSendMsg)
ON_MESSAGE(WM_UPDATE_STATIC, &SecWin::OnUpdateStatic) // 自定义的消息
ON_WM_CLOSE()
ON_BN_CLICKED(IDC_RECEIVE_FILE, &SecWin::OnBnClickedReceiveFile)
ON_BN_CLICKED(IDC_REJECT_FILE, &SecWin::OnBnClickedRejectFile)
ON_BN_CLICKED(IDC_SEND_FILE, &SecWin::OnBnClickedSendFile)
END_MESSAGE_MAP()

// 以分隔符分割字符串
// 将结果以一个vector<CString>形式返回
vector<CString> split2(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;
}

// 获取本地主机的ip
bool GetMyIP(char* ip)
{
//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;
}
//3.获取主机ip
HOSTENT* host = gethostbyname(hostname);
if (host == NULL)
{
return false;
}
//4.转化为char*并拷贝返回
strcpy(ip, inet_ntoa(*(in_addr*)*host->h_addr_list));
::WSACleanup();
return true;
}
// 获取本地主机的主机名
CString GetLocalHostName()
{
//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 SecWin::OnUpdateStatic(WPARAM wParam, LPARAM lParam)
{
CString inf;
inf = *((CString*)wParam);
if (split2(inf,":").size() == 2)
{
// 如果是想要发送文件,提示接收
host_ip = split2(inf, ":")[0];
CString filename = split2(inf, ":")[1];
recv_file_name = "F:\\ClientRoot\\"+ filename;
CString inf = "请点击'接收文件'按钮接收:" + filename;
AfxMessageBox(inf,MB_OK, 0);
// 设置接收和拒接文件按钮可点击
btn_recvFile.EnableWindow(1);
btn_rejectFile.EnableWindow(1);
}
if (split2(inf, "!").size() == 2)
{
// 如果是想要发送文本信息
// 将要发送的字符串以一定格式输出
// 由于CListBox不能换行,所以只能将名字内容放两行,以实现换行效果
CString myText;
myText += split2(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 = infList.GetCount();
infList.InsertString(length, myText);
CString content = " ";
content += split2(inf, "!")[1];
int length2 = infList.GetCount();
infList.InsertString(length2, content);

}

return 0;
}
// 接受UDP信息的线程
UINT SecWin::ThreadFunction(LPVOID pParam)
{
SecWin *pDlg = (SecWin *)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(UDP_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_STATIC, (WPARAM)(&inf), 0);
}
Sleep(1000);
}
return 0;
}

// 初始化SecWin窗口
BOOL SecWin::OnInitDialog()
{
CDialog::OnInitDialog();

// TODO: 在此添加额外的初始化代码
// 设置对话人标题字体
cfont.CreatePointFont(150, _T("黑体"), NULL);
GetDlgItem(IDC_FRIEND_NAME)->SetFont(&cfont);
friend_name.SetWindowTextA(client_name.c_str());
// 设置接收和拒接文件按钮不可点击
btn_recvFile.EnableWindow(0);
btn_rejectFile.EnableWindow(0);
// 启动接收普通信息的线程
m_pThread = AfxBeginThread((AFX_THREADPROC)ThreadFunction, this);

return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}

// 发送消息
void SecWin::OnBnClickedSendMsg()
{
// 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);

// 填写要发送信息的地址
sockaddr_in toAddr;
toAddr.sin_family = AF_INET;
toAddr.sin_port = htons(UDP_PORT);
toAddr.sin_addr.S_un.S_addr = inet_addr(client_ip.c_str());
// 将要发送的字符串以一定格式输出
CString sendText,edit_text;
// 给发送的信息之前加上主机名
CString host_name = GetLocalHostName();
sendText += host_name;
sendText += "!";
CString 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 list_length = infList.GetCount();
infList.InsertString(list_length, myText);
GetDlgItem(IDC_EDIT_MSG)->GetWindowText(edit_text);
// 将自己发的消息添加到消息列表中
std::string content = " ";
content += edit_text;
int list_length2 = infList.GetCount();
infList.InsertString(list_length2, content.c_str());
sendText += edit_text;

int length = sendto(udp_socket, sendText, strlen(sendText), 0, (SOCKADDR*)&toAddr, sizeof(SOCKADDR));
if (SOCKET_ERROR == length)
{
AfxMessageBox("发送UDP信息错误", MB_OK);
}

// 清空文本编辑框
GetDlgItem(IDC_EDIT_MSG)->SetWindowTextA("");
closesocket(udp_socket);
::WSACleanup();
}

// 通过udp将自己的ip和选中的文件名发送目标
void SecWin::SendIPAndFileName(CString inf)
{
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);

// 填写要发送信息的地址
sockaddr_in toAddr;
toAddr.sin_family = AF_INET;
toAddr.sin_port = htons(UDP_PORT);
toAddr.sin_addr.S_un.S_addr = inet_addr(client_ip.c_str());

int length = sendto(udp_socket, inf, strlen(inf), 0, (SOCKADDR*)&toAddr, sizeof(SOCKADDR));
if (SOCKET_ERROR == length)
{
AfxMessageBox("发送UDP信息错误", MB_OK);
}
closesocket(udp_socket);
::WSACleanup();
}

void SecWin::OnClose()
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CDialog::OnClose();
}
// 接收文件线程
UINT SecWin::RecvFileThread(LPVOID pParam)
{
// 初始化socket dll
WSADATA wsaData;
WORD socketVersion = MAKEWORD(2, 0);
if (WSAStartup(socketVersion, &wsaData) != 0)
{
AfxMessageBox("Init socket dll error!", MB_OK);

}
//创建socket
SOCKET c_Socket = socket(AF_INET, SOCK_STREAM, 0);
if (SOCKET_ERROR == c_Socket)
{
AfxMessageBox("Create Socket Error!", MB_OK);
}
//指定服务端的地址
sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.S_un.S_addr = inet_addr(host_ip);
server_addr.sin_port = htons(TCP_PORT);

if (SOCKET_ERROR == connect(c_Socket, (LPSOCKADDR)&server_addr, sizeof(server_addr)))
{
AfxMessageBox("Can Not Connect To Server IP!\n", MB_OK);

}

char buffer[BUFFER_SIZE];
CString err; // 错误提示信息
//打开文件,准备写入
FILE * fp = fopen(recv_file_name, "wb"); //windows下是"wb",表示打开一个只写的二进制文件
if (NULL == fp)
{
err = "File:";
err += recv_file_name;
err += "Can Not Open To Write";
AfxMessageBox(err, MB_OK);

}
else
{
memset(buffer, 0, BUFFER_SIZE);
int length = 0;
while ((length = recv(c_Socket, buffer, BUFFER_SIZE, 0)) > 0)
{
if (fwrite(buffer, sizeof(char), length, fp) < length)
{
err = "File:";
err += recv_file_name;
err += "Write Failed";
AfxMessageBox(err, MB_OK);
break;
}
memset(buffer, 0, BUFFER_SIZE);
}

}

fclose(fp);
closesocket(c_Socket);
AfxMessageBox("成功接收文件", MB_OK);
//释放winsock库
WSACleanup();
return 0;
}
// 发送文件线程
UINT SecWin::SendFileThread(LPVOID pParam)
{
// 声明并初始化一个服务端(本地)的地址结构
sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.S_un.S_addr = INADDR_ANY;
server_addr.sin_port = htons(TCP_PORT);

// 初始化socket dll
WSADATA wsaData;
WORD socketVersion = MAKEWORD(2, 0);
if (WSAStartup(socketVersion, &wsaData) != 0)
{
AfxMessageBox("Init socket dll error!", MB_OK);

}

// 创建socket
SOCKET m_Socket = socket(AF_INET, SOCK_STREAM, 0);
if (SOCKET_ERROR == m_Socket)
{
AfxMessageBox("Create Socket Error!", MB_OK);

}

//绑定socket和服务端(本地)地址
if (SOCKET_ERROR == bind(m_Socket, (LPSOCKADDR)&server_addr, sizeof(server_addr)))
{
//AfxMessageBox("Server Bind Failed", MB_OK);

}
//监听
if (SOCKET_ERROR == listen(m_Socket, 10))
{
//AfxMessageBox("Server Listen Failed : ", MB_OK);
}
bool b_Sending = true;
while (b_Sending)
{
sockaddr_in client_addr;
int client_addr_len = sizeof(client_addr);

SOCKET m_New_Socket = accept(m_Socket, (sockaddr *)&client_addr, &client_addr_len);
if (SOCKET_ERROR == m_New_Socket)
{
//AfxMessageBox("Server Accept Failed:", MB_OK);
break;
}
char buffer[BUFFER_SIZE];
FILE * fp = fopen(send_file_name, "rb"); //windows下是"rb",表示打开一个只读的二进制文件
if (NULL == fp)
{
AfxMessageBox("File: %s Not Found", MB_OK);
}
else
{
memset(buffer, 0, BUFFER_SIZE);
int length = 0;

while ((length = fread(buffer, sizeof(char), BUFFER_SIZE, fp)) > 0)
{

if (send(m_New_Socket, buffer, length, 0) < 0)
{
AfxMessageBox("Send file failed", MB_OK);
break;
}

memset(buffer, 0, BUFFER_SIZE);
}

fclose(fp);

}
closesocket(m_New_Socket);
AfxMessageBox("Send file successful", MB_OK);
b_Sending = false;
}

closesocket(m_Socket);
//释放winsock库
WSACleanup();
return 0;
}
// 接收文件
void SecWin::OnBnClickedReceiveFile()
{
// TODO: 在此添加控件通知处理程序代码
recvFileThread = AfxBeginThread((AFX_THREADPROC)RecvFileThread, this);
// 接受完一次文件后,让接收和拒接按钮变为不可点击
btn_recvFile.EnableWindow(0);
btn_rejectFile.EnableWindow(0);
}

// 拒收文件
void SecWin::OnBnClickedRejectFile()
{
// TODO: 在此添加控件通知处理程序代码
btn_recvFile.EnableWindow(0);
btn_rejectFile.EnableWindow(0);
}

// 发送文件
void SecWin::OnBnClickedSendFile()
{
// TODO: 在此添加控件通知处理程序代码
CFileDialog filedlg(TRUE);

if (IDOK == filedlg.DoModal())
{
CString inf;
CString cstrfilepath;
CString file_name;
POSITION pos = filedlg.GetStartPosition();
while (pos != NULL)
{
cstrfilepath = filedlg.GetNextPathName(pos);//取得文件路径
file_name = filedlg.GetFileName(); // 获取文件名
send_file_name = cstrfilepath; // 将要发送的文件的路径赋给send_file_name
}

char ip[30] = { 0 };
GetMyIP(ip);
inf += ip;
inf += ":";
95d0

inf += file_name;
// 将本机ip和文件名发给目标
SendIPAndFileName(inf);
// 开启接收文件线程
sendFileThread = AfxBeginThread((AFX_THREADPROC)SendFileThread, this);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐