18 MFC TCP和UDP 网络通信

TCP服务器

#include <stdio.h>
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib") //包含静态库

/*
.obj + .lib 文件 组合打包成 .exe
*/

int main()
{
	//1.加载套接字库
	//第一个参数:版本
	WORD wVersionRequseted=MAKEWORD(2,2);//低位字节:主版本,高位字节:次版本
	//第二个参数:
	WSADATA wd;
	if (0 != WSAStartup(wVersionRequseted, &wd))
	{
		printf("加载套接字失败!错误代号:%d\n", GetLastError());
		return 0;
	}

	//2.判断实际加载的版本
	if (LOBYTE(wd.wVersion) != 2 || HIBYTE(wd.wVersion) != 2)
	{
		printf("加载套接字版本不一致!错误代号:%d\n", GetLastError());
		return 0;
	}

	//3.创建套接字
	//第一个参数:地址簇 IPV4
	//第二个参数:套接字类型,流式套接字( SOCK_STREAM->TCP) 数据报套接字(SOCK_DGRAM->UDP)
	//第三个参数:待定协议
	SOCKET sockServer=socket(AF_INET, SOCK_STREAM, 0);


	//4.设置套接字地址簇
	SOCKADDR_IN addrSrv;
	addrSrv.sin_family = AF_INET;//地址簇
	addrSrv.sin_addr.S_un.S_addr =htonl(INADDR_ANY);//设置网卡 htonl:主机字节顺序转换为网络字节顺序
	addrSrv.sin_port =htons(2020);//端口号范围 0 -> 65535  0:不取 1->1024 系统服务器 , 1024以上端口自己用
	
	//SOCKADDR_IN==sockaddr_in

	//5.绑定
	if (SOCKET_ERROR == bind(sockServer, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)))//绑定套接字,套接字地址簇,大小
	{
		printf("绑定失败!错误代号:%d\n", WSAGetLastError());
		return 0;
	}
	
	//6.将套接字设置为监听模式
	//第一个参数:套接字
	//第二个参数:挂起连接的队列的最大长度
	if (SOCKET_ERROR == listen(sockServer, 5))
	{
		printf("监听失败!错误代号:%d\n", WSAGetLastError());
		return 0;
	}

	//7.等待客户端连接请求
	SOCKADDR_IN addrClient;
	int length = sizeof(SOCKADDR);
	while (1)
	{
		SOCKET clientSocket=accept(sockServer, (SOCKADDR*)&addrClient, &length);
		//inet_ntoa() 是一个用于将 IPv4 地址从网络字节序转换为点分十进制字符串表示的函数
		//ntohl 网络字节顺序转换成主机字节顺序
		printf("客户端:%s:%d连接服务器\n", inet_ntoa(addrClient.sin_addr),addrClient.sin_port);

		//接收信息
		//第一个参数:套接字
		//第二个参数:发送的缓冲区
		//第三个参数:缓冲区大小
		char szRecvBuf[100] = { 0 };
		recv(clientSocket, szRecvBuf, sizeof(szRecvBuf), 0);
		printf("客户端说:%s\n", szRecvBuf);


		//发送信息
		char szSenBuf[100] = "客户端,hello";
		send(clientSocket, szSenBuf, strlen(szSenBuf) + 1, 0);


		//关闭套接字
		closesocket(clientSocket);

	}
	//8.关闭套接字
	closesocket(sockServer);

	//9.清理库
	WSACleanup();

	return 0;
}

TCP客户端

#include <stdio.h>
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib") //包含静态库

/*
.obj + .lib 文件 组合打包成 .exe
*/

int main()
{

	char szServerIPAddress[16];
	printf("请输入需要连接的服务器IP地址:\n");
	scanf("%s",szServerIPAddress);

	//1.加载套接字库
	//第一个参数:版本
	WORD wVersionRequseted = MAKEWORD(2, 2);//低位字节:主版本,高位字节:次版本
	//第二个参数:
	WSADATA wd;
	if (0 != WSAStartup(wVersionRequseted, &wd))
	{
		printf("加载套接字失败!错误代号:%d\n", GetLastError());
		return 0;
	}

	//2.判断实际加载的版本
	if (LOBYTE(wd.wVersion) != 2 || HIBYTE(wd.wVersion) != 2)
	{
		printf("加载套接字版本不一致!错误代号:%d\n", GetLastError());
		return 0;
	}

	//3.创建套接字
	//第一个参数:地址簇 IPV4
	//第二个参数:套接字类型,流式套接字( SOCK_STREAM->TCP) 数据报套接字(SOCK_DGRAM->UDP)
	//第三个参数:待定协议
	SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);


	//4.连接服务器
	SOCKADDR_IN addrSrv;
	addrSrv.sin_family = AF_INET;//地址簇
	addrSrv.sin_addr.S_un.S_addr = inet_addr(szServerIPAddress);
	addrSrv.sin_port = htons(2020);

	if (connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)))
	{
		printf("连接服务器失败.错误代号:%d\n",WSAGetLastError());
		return 0;
	}
	printf("连接服务器成功!\n");
	
	//5.发送信息
	char szSendBuf[100] = "服务器,hello";
	send(sockClient, szSendBuf, strlen(szSendBuf) + 1,0);

	//接收信息
	//第一个参数:套接字
	//第二个参数:发送的缓冲区
	//第三个参数:缓冲区大小
	char szRecvBuf[100] = { 0 };
	recv(sockClient, szRecvBuf, sizeof(szRecvBuf), 0);
	printf("服务器说:%s\n", szRecvBuf);


	//7.关闭套接字
	closesocket(sockClient);

	//8.清理库
	WSACleanup();

	return 0;
}

有错误代码可以进行查找
在这里插入图片描述
将错误代码输入
在这里插入图片描述

UDP 服务器

#include <stdio.h>
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib") //包含静态库

/*
.obj + .lib 文件 组合打包成 .exe
*/

int main()
{

	

	//1.加载套接字库
	//第一个参数:版本
	WORD wVersionRequseted = MAKEWORD(2, 2);//低位字节:主版本,高位字节:次版本
	//第二个参数:
	WSADATA wd;
	if (0 != WSAStartup(wVersionRequseted, &wd))
	{
		printf("加载套接字失败!错误代号:%d\n", GetLastError());
		return 0;
	}

	//2.判断实际加载的版本
	if (LOBYTE(wd.wVersion) != 2 || HIBYTE(wd.wVersion) != 2)
	{
		printf("加载套接字版本不一致!错误代号:%d\n", GetLastError());
		return 0;
	}

	//3.创建套接字
	//第一个参数:地址簇 IPV4
	//第二个参数:套接字类型,流式套接字( SOCK_STREAM->TCP) 数据报套接字(SOCK_DGRAM->UDP)
	//第三个参数:待定协议
	SOCKET sockServer = socket(AF_INET, SOCK_DGRAM, 0);


	//4.设置套接字地址簇
	SOCKADDR_IN addrSrv;
	addrSrv.sin_family = AF_INET;//地址簇
	addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//设置网卡 htonl:主机字节顺序转换为网络字节顺序
	addrSrv.sin_port = htons(2021);//端口号范围 0 -> 65535  0:不取 1->1024 系统服务器 , 1024以上端口自己用

	//SOCKADDR_IN==sockaddr_in

	//5.绑定
	if (SOCKET_ERROR == bind(sockServer, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)))//绑定套接字,套接字地址簇,大小
	{
		printf("绑定失败!错误代号:%d\n", WSAGetLastError());
		return 0;
	}

	//6.接收消息
	SOCKADDR_IN addrclient;
	int length = sizeof(SOCKADDR);
	char szRecvBuf[100];
	recvfrom(sockServer, szRecvBuf, sizeof(szRecvBuf), 0,(SOCKADDR*)&addrclient,&length);
	printf("客户端:%s\n", szRecvBuf);


	//发送
	char szSendBuf[100] = "客户端你好!";
	sendto(sockServer, szSendBuf,strlen(szSendBuf)+1,0, (SOCKADDR*)&addrclient,sizeof(SOCKADDR));

	//7.关闭套接字
	closesocket(sockServer);

	//8.清理库
	WSACleanup();

	return 0;
}

UDP客户端

#include <stdio.h>
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib") //包含静态库

/*
.obj + .lib 文件 组合打包成 .exe
*/

int main()
{

	char szServerIPAddress[16];
	printf("请输入需要连接的服务器IP地址:\n");
	scanf("%s", szServerIPAddress);

	//1.加载套接字库
	//第一个参数:版本
	WORD wVersionRequseted = MAKEWORD(2, 2);//低位字节:主版本,高位字节:次版本
	//第二个参数:
	WSADATA wd;
	if (0 != WSAStartup(wVersionRequseted, &wd))
	{
		printf("加载套接字失败!错误代号:%d\n", GetLastError());
		return 0;
	}

	//2.判断实际加载的版本
	if (LOBYTE(wd.wVersion) != 2 || HIBYTE(wd.wVersion) != 2)
	{
		printf("加载套接字版本不一致!错误代号:%d\n", GetLastError());
		return 0;
	}

	//3.创建套接字
	//第一个参数:地址簇 IPV4
	//第二个参数:套接字类型,流式套接字( SOCK_STREAM->TCP) 数据报套接字(SOCK_DGRAM->UDP)
	//第三个参数:待定协议
	SOCKET sockServer = socket(AF_INET, SOCK_DGRAM, 0);


	//4.发送消息
	SOCKADDR_IN addrServer;
	addrServer.sin_addr.S_un.S_addr = inet_addr(szServerIPAddress);
	addrServer.sin_family = AF_INET;
	addrServer.sin_port = htons(2021);
	int length = sizeof(SOCKADDR);

	char szSendBuf[100]="服务器你好!";
	sendto(sockServer, szSendBuf, sizeof(szSendBuf), 0, (SOCKADDR*)&addrServer,sizeof(SOCKADDR));


	//6.接收消息
	SOCKADDR_IN addrclient;
	length = sizeof(SOCKADDR);
	char szRecvBuf[100];
	recvfrom(sockServer, szRecvBuf, sizeof(szRecvBuf), 0, (SOCKADDR*)&addrclient, &length);
	printf("服务器:%s\n", szRecvBuf);

	//7.关闭套接字
	closesocket(sockServer);

	//8.清理库
	WSACleanup();

	return 0;
}

MFC TCP通信

勾选高级功能在这里插入图片描述

如果没有勾选
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

TCP服务器

ui 设置
在这里插入图片描述
添加套接字类
在这里插入图片描述
在这里插入图片描述
创建虚函数接收连接在这里插入图片描述
在服务器里面创建客户端类在这里插入图片描述
在客户端类中添加接收的响应函数在这里插入图片描述
断开连接在这里插入图片描述

// TCPChatServerDlg.h: 头文件

//

#pragma once

//类的前置声明
class ClistenSocket;

// CTCPChatServerDlg 对话框
class CTCPChatServerDlg : public CDialogEx
{
// 构造
public:
	CTCPChatServerDlg(CWnd* pParent = nullptr);	// 标准构造函数

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

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持


// 实现
protected:
	HICON m_hIcon;

	// 生成的消息映射函数
	virtual BOOL OnInitDialog();
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:
	ClistenSocket* m_plistSocket;
	afx_msg void OnBnClickedBtnStart();
	afx_msg void OnBnClickedBtnClose();
	CListCtrl m_list;
};

// TCPChatServerDlg.cpp: 实现文件

//

#include "pch.h"
#include "framework.h"
#include "TCPChatServer.h"
#include "TCPChatServerDlg.h"
#include "afxdialogex.h"
#include "ClistenSocket.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#define PORT 2020 //端口号

// CTCPChatServerDlg 对话框



CTCPChatServerDlg::CTCPChatServerDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_TCPCHATSERVER_DIALOG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	m_plistSocket = NULL;
}

void CTCPChatServerDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_LIST1, m_list);
}

BEGIN_MESSAGE_MAP(CTCPChatServerDlg, CDialogEx)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BTN_START, &CTCPChatServerDlg::OnBnClickedBtnStart)
	ON_BN_CLICKED(IDC_BTN_CLOSE, &CTCPChatServerDlg::OnBnClickedBtnClose)
END_MESSAGE_MAP()


// CTCPChatServerDlg 消息处理程序

BOOL CTCPChatServerDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	m_list.InsertColumn(0,L"IP地址",LVCFMT_LEFT,150);
	m_list.InsertColumn(1, L"端口号", LVCFMT_LEFT,80);
	m_list.SetExtendedStyle(LVS_EX_FULLROWSELECT);

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

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CTCPChatServerDlg::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 CTCPChatServerDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}



void CTCPChatServerDlg::OnBnClickedBtnStart()
{
	CString strMsg;
	m_plistSocket = new ClistenSocket;
	//创建套接字
	//第一个参数:端口号
	//第二个参数:套接字类型 TCP->SOCK_STREAM ,UDP->SOCK_DGRAM
	//后前面全是默认参数
	if (FALSE==m_plistSocket->Create(PORT, SOCK_STREAM))
	{
		strMsg.Format(L"开启服务器失败.错误代号:%d",GetLastError());
		MessageBox(strMsg, L"提示");
		return;
	}

	//将套接字设置为监听模式
	if (FALSE == m_plistSocket->Listen())
	{
		strMsg.Format(L"开启服务器失败.错误代号:%d", GetLastError());
		MessageBox(strMsg, L"提示");
		return;
	}

	//禁用按钮
	GetDlgItem(IDC_BTN_START)->EnableWindow(FALSE);
	GetDlgItem(IDC_BTN_CLOSE)->EnableWindow(TRUE);

}


void CTCPChatServerDlg::OnBnClickedBtnClose()
{
	if (m_plistSocket)
	{
		m_plistSocket->Close();

		delete m_plistSocket;
		m_plistSocket = NULL;


		//禁用按钮
		GetDlgItem(IDC_BTN_START)->EnableWindow(TRUE);
		GetDlgItem(IDC_BTN_CLOSE)->EnableWindow(FALSE);
	}
}

//ClistenSocket.h

#pragma once
#include <afxsock.h>
class ClistenSocket :public CSocket
{
public:
	ClistenSocket();
	~ClistenSocket();
	virtual void OnAccept(int nErrorCode);
};

//ClistenSocket.cpp

#include "pch.h"
#include "ClistenSocket.h"
#include "CClientSocket.h"
#include "TCPChatServerDlg.h"
#include "TCPChatServer.h"

ClistenSocket::ClistenSocket()
{
}

ClistenSocket::~ClistenSocket()
{
}

//监听到
void ClistenSocket::OnAccept(int nErrorCode)
{
	CClientSocket *pSocket = new CClientSocket;

	//第一个参数:连接的新的套接字,其他参数为默认
	Accept(*pSocket);
	CString strIPAddress;
	UINT uPort;
	//获取IP地址
	pSocket->GetPeerName(strIPAddress, uPort);

	//保存客户端套接字指针对象
	((CTCPChatServerApp*)AfxGetApp())->m_Clientlist.push_back(pSocket);

	//获取主对话框中的UI
	CTCPChatServerDlg* pMainDlg=(CTCPChatServerDlg*)AfxGetMainWnd();
	//插入到列表中
	int nCount = pMainDlg->m_list.GetItemCount();//获取插入行数
	pMainDlg->m_list.InsertItem(nCount, strIPAddress);
	CString str;
	str.Format(L"%d", uPort);
	pMainDlg->m_list.SetItemText(nCount,1,str);//插入端口号


	str.Format(L"客户端%s:%d上线了\r\n",strIPAddress,uPort);
	//转发给所有客户端
	//((CTCPChatServerApp*)AfxGetApp())->m_Clientlist.push_back(pSocket);
	std::list<CClientSocket*>::iterator it;
	for (it = ((CTCPChatServerApp*)AfxGetApp())->m_Clientlist.begin(); it != ((CTCPChatServerApp*)AfxGetApp())->m_Clientlist.end(); ++it)
	{
		CClientSocket* pSocket = *it;
		//发送
		pSocket->Send(str, str.GetLength() * 2);//长度*2 ==字节数
	}


	CSocket::OnAccept(nErrorCode);
}

//CClientSocket.h

#pragma once
#include <afxsock.h>
class CClientSocket :public CSocket
{
public:
	CClientSocket();
	~CClientSocket();
	virtual void OnReceive(int nErrorCode);
	virtual void OnClose(int nErrorCode);
};

//CClientSocket.cpp

#include "pch.h"
#include "CClientSocket.h"
#include "TCPChatServer.h"
#include "TCPChatServerDlg.h"
CClientSocket::CClientSocket()
{
}

CClientSocket::~CClientSocket()
{
}


//接收
void CClientSocket::OnReceive(int nErrorCode)
{
	wchar_t szRecvBuf[512];
	ZeroMemory(szRecvBuf, sizeof(szRecvBuf));//清空内存,防止没有字符串终止符出现乱码
	//接收数据
	//第一个参数:缓存
	//第二个参数:缓存大小
	int n=Receive(szRecvBuf, sizeof(szRecvBuf));//n为实际接收多少字节
	//AfxMessageBox(szRecvBuf);

	//获取当前时间
	CTime time = CTime::GetCurrentTime();
	CString strIPAddress;
	UINT uPort;
	GetPeerName(strIPAddress,uPort);//获取IP地址和端口号
	CString str;
	str.Format(L"%s:%d\t%s\r\n%s\r\n", strIPAddress, uPort,time.Format(L"%H:%M:%S"), szRecvBuf);

	//转发给所有客户端
	//((CTCPChatServerApp*)AfxGetApp())->m_Clientlist.push_back(pSocket);
	std::list<CClientSocket*>::iterator it;
	for (it = ((CTCPChatServerApp*)AfxGetApp())->m_Clientlist.begin(); it != ((CTCPChatServerApp*)AfxGetApp())->m_Clientlist.end(); ++it)
	{
		CClientSocket* pSocket = *it;
		//发送
		pSocket->Send(str, str.GetLength() * 2);//长度*2 ==字节数
	}


	CSocket::OnReceive(nErrorCode);
}


void CClientSocket::OnClose(int nErrorCode)
{
	CString strIPAddress;
	UINT uPort;
	GetPeerName(strIPAddress, uPort);//获取IP地址和端口号
	//删除链表中的IP地址信息
	CTCPChatServerDlg* pMainDlg = (CTCPChatServerDlg*)AfxGetMainWnd();
	int nCount = pMainDlg->m_list.GetItemCount();//获取总行数
	for (int i = 0; i < nCount; i++)
	{
		//判断IP地址和端口号是否和链表中数据一致
		if (pMainDlg->m_list.GetItemText(i, 0) == strIPAddress && _wtoi(pMainDlg->m_list.GetItemText(i, 1)) == uPort)
		{
			pMainDlg->m_list.DeleteItem(i);
			break;
		}
	}


	//从list释放内存
	std::list<CClientSocket*>::iterator it;
	for (it = ((CTCPChatServerApp*)AfxGetApp())->m_Clientlist.begin(); it != ((CTCPChatServerApp*)AfxGetApp())->m_Clientlist.end(); ++it)
	{
		CClientSocket* pSocket = *it;
		if (pSocket == this)
		{
			((CTCPChatServerApp*)AfxGetApp())->m_Clientlist.erase(it);
			delete pSocket;
			break;
		}
	}

	CSocket::OnClose(nErrorCode);
}

在这里插入图片描述

TCP 客户端

ui 设置
在这里插入图片描述
客户端类在这里插入图片描述
接受响应函数在这里插入图片描述在这里插入图片描述

// TCPChatClientDlg.h: 头文件

//

#pragma once
class CClientSocket;

// CTCPChatClientDlg 对话框
class CTCPChatClientDlg : public CDialogEx
{
// 构造
public:
	CTCPChatClientDlg(CWnd* pParent = nullptr);	// 标准构造函数
	~CTCPChatClientDlg();
// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_TCPCHATCLIENT_DIALOG };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持


// 实现
protected:
	HICON m_hIcon;

	// 生成的消息映射函数
	virtual BOOL OnInitDialog();
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:
	CString m_strSendMsg;
	CClientSocket* m_pClientSocket;
	afx_msg void OnBnClickedBtnSend();
	afx_msg void OnBnClickedBtnClose();
	CEdit m_edit;
	void ShowMessage(CString strMsg);
};

// TCPChatClientDlg.cpp: 实现文件

//

#include "pch.h"
#include "framework.h"
#include "TCPChatClient.h"
#include "TCPChatClientDlg.h"
#include "afxdialogex.h"
#include "CClientSocket.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif


#define PORT 2020
// CTCPChatClientDlg 对话框



CTCPChatClientDlg::CTCPChatClientDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_TCPCHATCLIENT_DIALOG, pParent)
	, m_strSendMsg(_T(""))
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	m_pClientSocket = NULL;
}

CTCPChatClientDlg::~CTCPChatClientDlg()
{
	if (m_pClientSocket)
	{
		delete m_pClientSocket;
		m_pClientSocket = NULL;
	}
}

void CTCPChatClientDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Text(pDX, IDC_EDIT2, m_strSendMsg);
	DDX_Control(pDX, IDC_EDIT1, m_edit);
}

BEGIN_MESSAGE_MAP(CTCPChatClientDlg, CDialogEx)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BTN_SEND, &CTCPChatClientDlg::OnBnClickedBtnSend)
	ON_BN_CLICKED(IDC_BTN_CLOSE, &CTCPChatClientDlg::OnBnClickedBtnClose)
END_MESSAGE_MAP()


// CTCPChatClientDlg 消息处理程序

BOOL CTCPChatClientDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	CString strMsg;

	m_pClientSocket = new CClientSocket;
	if (FALSE == m_pClientSocket->Create())//默认为TCP协议
	{
		strMsg.Format(L"初始化网络失败.错误代号:%d", GetLastError());
		MessageBox(strMsg, L"提示");
		//结束对话框
		EndDialog(IDOK);
	}

	//连接服务器
	if (FALSE==m_pClientSocket->Connect(L"192.168.1.109", PORT))
	{
		strMsg.Format(L"连接服务器失败.错误代号:%d", GetLastError());
		MessageBox(strMsg, L"提示");
		//结束对话框
		EndDialog(IDOK);
	}

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

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CTCPChatClientDlg::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 CTCPChatClientDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}


//发送
void CTCPChatClientDlg::OnBnClickedBtnSend()
{
	UpdateData(TRUE);
	if (m_strSendMsg.IsEmpty())
	{
		MessageBox(L"发消息为空");
		return;
	}
	if (m_strSendMsg.GetLength() > 512)
	{
		MessageBox(L"发送内容太多");
		return;
	}

	//发消息
	//第一个参数:发送的消息
	//第二个参数:发送的长度
	int n=m_pClientSocket->Send(m_strSendMsg,m_strSendMsg.GetLength()*2);

}


//关闭
void CTCPChatClientDlg::OnBnClickedBtnClose()
{
	EndDialog(IDOK);
}

//显示消息
void CTCPChatClientDlg::ShowMessage(CString strMsg)
{
	
	//获取原来字符的长度
	int nLength = m_edit.GetWindowTextLength();
	m_edit.SetSel(nLength, -1);//设置光标位置 
	//追加
	strMsg = strMsg + L"\r\n";
	m_edit.ReplaceSel(strMsg);//设置文本字符串
}

//CClientSocket.h

#pragma once
#include <afxsock.h>
class CClientSocket :public CSocket
{
public:
	CClientSocket();
	~CClientSocket();
	virtual void OnReceive(int nErrorCode);
};

//CClientSocket.cpp

#include "pch.h"
#include "CClientSocket.h"
#include "TCPChatClientDlg.h"
CClientSocket::CClientSocket()
{
}

CClientSocket::~CClientSocket()
{
}


void CClientSocket::OnReceive(int nErrorCode)
{
	
	wchar_t szRecvBuf[512];
	ZeroMemory(szRecvBuf, sizeof(szRecvBuf));//清空内存,防止没有字符串终止符出现乱码
	//接收数据
	//第一个参数:缓存
	//第二个参数:缓存大小
	int n = Receive(szRecvBuf, sizeof(szRecvBuf));//n为实际接收多少字节
	
	//显示到界面
	//获取到控件
	CTCPChatClientDlg* pMainDlg=(CTCPChatClientDlg*)AfxGetMainWnd();
	pMainDlg->ShowMessage(szRecvBuf);


	CSocket::OnReceive(nErrorCode);
}

请添加图片描述

MFC UDP通信

ui 设置
在这里插入图片描述

添加关联变量
在这里插入图片描述在这里插入图片描述在这里插入图片描述

在这里插入图片描述
在这里插入图片描述> 添加类
在这里插入图片描述
在这里插入图片描述

// UDPChatDlg.h: 头文件

//

#pragma once
#include "CClientSocket.h"

// CUDPChatDlg 对话框
class CUDPChatDlg : public CDialogEx
{
// 构造
public:
	CUDPChatDlg(CWnd* pParent = nullptr);	// 标准构造函数

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

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持


// 实现
protected:
	HICON m_hIcon;

	// 生成的消息映射函数
	virtual BOOL OnInitDialog();
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:
	CIPAddressCtrl m_IPAddressCtrl;
	int m_uPort;
	CEdit m_edit;
	CString m_strSendMsg;
	afx_msg void OnBnClickedBtnSend();
	CClientSocket m_socket;
	void ShowMessage(CString strMsg);
	int m_uMyPort;
	afx_msg void OnBnClickedBtnCreate();
};

// UDPChatDlg.cpp: 实现文件

//

#include "pch.h"
#include "framework.h"
#include "UDPChat.h"
#include "UDPChatDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif



// CUDPChatDlg 对话框



CUDPChatDlg::CUDPChatDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_UDPCHAT_DIALOG, pParent)
	, m_strSendMsg(_T(""))
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CUDPChatDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_IPADDRESS1, m_IPAddressCtrl);
	DDX_Text(pDX, IDC_EDIT1, m_uPort);
	DDX_Control(pDX, IDC_EDIT2, m_edit);
	DDX_Text(pDX, IDC_EDIT3, m_strSendMsg);
	DDX_Text(pDX, IDC_EDIT4, m_uMyPort);
}

BEGIN_MESSAGE_MAP(CUDPChatDlg, CDialogEx)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BTN_SEND, &CUDPChatDlg::OnBnClickedBtnSend)
	ON_BN_CLICKED(IDC_BTN_CREATE, &CUDPChatDlg::OnBnClickedBtnCreate)
END_MESSAGE_MAP()


// CUDPChatDlg 消息处理程序

BOOL CUDPChatDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	

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

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CUDPChatDlg::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 CUDPChatDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}


//发送
void CUDPChatDlg::OnBnClickedBtnSend()
{
	UpdateData(TRUE);
	if (m_strSendMsg.IsEmpty())
	{
		MessageBox(L"不能发送空消息");
		return;
	}
	if (m_strSendMsg.GetLength() >= 512)
	{
		MessageBox(L"发送消息过长");
		return;
	}
	CString strIPAddress;
	m_IPAddressCtrl.GetWindowText(strIPAddress);
	if (strIPAddress == L"0.0.0.0")
	{
		MessageBox(L"IP地址不能为空");
		return;
	}
	m_socket.SendTo(m_strSendMsg, m_strSendMsg.GetLength() * 2, m_uPort,strIPAddress);
}


void CUDPChatDlg::ShowMessage(CString strMsg)
{
	int nLength = m_edit.GetWindowTextLength();
	m_edit.SetSel(nLength, -1);//设置光标位置

	//追加
	strMsg = strMsg + L"\r\n";
	m_edit.ReplaceSel(strMsg);
}


void CUDPChatDlg::OnBnClickedBtnCreate()
{
	UpdateData(TRUE);
	CString str;
	if (FALSE == m_socket.Create(m_uMyPort, SOCK_DGRAM))
	{
		str.Format(L"初始化网络失败,错误代号:%d", GetLastError());
		MessageBox(str, L"提示");
		EndDialog(IDOK);
		return ;
	}
}

//CClientSocket.h

#pragma once

#include <afxsock.h>
class CClientSocket :public CSocket
{
public:
	CClientSocket();
	~CClientSocket();
	virtual void OnReceive(int nErrorCode);
};

//CClientSocket.cpp

#include "pch.h"
#include "CClientSocket.h"
#include "UDPChatDlg.h"

CClientSocket::CClientSocket()
{
}

CClientSocket::~CClientSocket()
{
}


void CClientSocket::OnReceive(int nErrorCode)
{
	wchar_t szRecvMsg[512];
	ZeroMemory(szRecvMsg,sizeof(szRecvMsg));

	//接收数据
	CString strIPaddress;
	UINT uPort;
	ReceiveFrom(szRecvMsg,sizeof(szRecvMsg),strIPaddress,uPort);

	//显示到界面
	CUDPChatDlg* pMainDlg=(CUDPChatDlg*)AfxGetMainWnd();
	pMainDlg->ShowMessage(szRecvMsg);

	CSocket::OnReceive(nErrorCode);
}

请添加图片描述

  • 0
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值