VS 2019 MFC Socket 通讯例程客户端Connect连接一对多同步通信TCP/IP通信客户端[二]

发布于:2022-11-09 ⋅ 阅读:(16) ⋅ 点赞:(0) ⋅ 评论:(0)

 技术要点:

SOCKET socket(  int af,  int type,  int protocol);
int connect( SOCKET s, const struct sockaddr FAR* name, int namelen);BOOL AfxSocketInit(WSADATA* lpwsaData = NULL );
Visual C++ 
if (!AfxSocketInit())
{
   AfxMessageBox(_T("Failed to Initialize Sockets"), MB_OK | MB_ICONSTOP);
   return FALSE;
}

注意事项:

         Socket通信客户端的初始化可以分为两种方法,一种是通过上一节中提到的初始化封装类进行Socket的初始化。第二种是通过AfxSocketInit()Socket进行初始化。AfxSocketInit()初始化需要注意的是需要添加头文件#include<afxsock.h>,并在应用程序InitInstance()进行初始化。如下所示:

 

BOOL CMFCApplicationSocketClientDemoApp::InitInstance()
{

	INITCOMMONCONTROLSEX InitCtrls;
	InitCtrls.dwSize = sizeof(InitCtrls);
	InitCtrls.dwICC = ICC_WIN95_CLASSES;
	InitCommonControlsEx(&InitCtrls);
	
	CWinApp::InitInstance();

	if (!AfxSocketInit())
	{
		AfxMessageBox(_T("Windows套接字初始化失败!"));
		return FALSE;
	}

	AfxEnableControlContainer();

	CShellManager *pShellManager = new CShellManager;

	CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));

	SetRegistryKey(_T("应用程序向导生成的本地应用程序"));

	CMFCApplicationSocketClientDemoDlg dlg;
	m_pMainWnd = &dlg;
	INT_PTR nResponse = dlg.DoModal();
	if (nResponse == IDOK)
	{
	
	}
	else if (nResponse == IDCANCEL)
	{

	}
	else if (nResponse == -1)
	{
		TRACE(traceAppMsg, 0, "警告: 对话框创建失败,应用程序将意外终止。\n");
		TRACE(traceAppMsg, 0, "警告: 如果您在对话框上使用 MFC 控件,则无法 #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS。\n");
	}

	if (pShellManager != nullptr)
	{
		delete pShellManager;
	}

#if !defined(_AFXDLL) && !defined(_AFX_NO_MFC_CONTROLS_IN_DIALOGS)
	ControlBarCleanUp();
#endif
	return FALSE;
}

        通过自定义类对Socket进行初始化。必须包含自定义类头文件#include"CSoceketInitConfig.h",在应用程序中通过如下代码进行初始化。

CSoceketInitConfig ClientSockInit(2,2);

        应用程序头文件源代码:

#include"CSoceketInitConfig.h"
#include "afxwin.h"
#include<iostream>
#include<winsock.h>
#pragma comment(lib,"ws2_32.lib")
#include "afxdialogex.h"

using namespace std;
#pragma once
#pragma warning(disable:4996)
#pragma warning(disable:6263)
#pragma warning(disable:6255)
#pragma warning(disable:6387)
#pragma warning(disable:26454)

const int      PORTSET             = 8000;
#define        MaxBufSize           2048

class CMFCApplicationSocketClientDemoDlg : public CDialogEx
{

public:
	CMFCApplicationSocketClientDemoDlg(CWnd* pParent = nullptr);	


#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_MFCAPPLICATIONSOCKETCLIENTDEMO_DIALOG };
#endif

	protected:
	virtual			void DoDataExchange(CDataExchange* pDX);	


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:
	CEdit			m_ClientRecvMsg;
	CButton			m_ConnectServer;
	CButton			m_CutDownConnect;
	SOCKET          m_pClientSock;
	BOOL            m_ServerConnectSucced;
	afx_msg			void OnBnClickedButtonsendmsg();
	afx_msg         char* CstringToWideCharArry(CString CstrText);
	afx_msg         CString CharArryToCstring(char* CharText);
	afx_msg			void OnBnClickedButtonconnectserver();
	afx_msg         BOOL ConnectServerSocket(CMFCApplicationSocketClientDemoDlg*);
	afx_msg		    CString GetSystemTime();
	afx_msg		    void SetRevTextMsg(CString nText);
	afx_msg			void OnEnChangeEditsend();
	CButton			m_SendMsgToServer;
	afx_msg void    OnBnClickedButtonconnectcunt();
};
DWORD               WINAPI ConnectServerThread(LPCVOID lParam);
BOOL                socket_Select(SOCKET hSocket, DWORD nTimeOut, BOOL bRead);

      应用程序CPP文件源代码:最近很忙,程序写的较为匆忙,能正常运行,后期根据自己需要进行更改完善,文件发送的功能后期会陆续补上。


#include "pch.h"
#include "framework.h"
#include "MFCApplicationSocketClientDemo.h"
#include "MFCApplicationSocketClientDemoDlg.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#endif


class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();


#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_ABOUTBOX };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);   

protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


CMFCApplicationSocketClientDemoDlg::CMFCApplicationSocketClientDemoDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_MFCAPPLICATIONSOCKETCLIENTDEMO_DIALOG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	m_pClientSock = NULL;
	m_ServerConnectSucced = FALSE;
}

void CMFCApplicationSocketClientDemoDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_EDITRECEV, m_ClientRecvMsg);
	//  DDX_Control(pDX, IDC_EDITSEND, m_ClientSendMsg);
	//  DDX_Control(pDX, IDC_IPADDRESS_SERVER, m_ServerIPaddr);
	//  DDX_Control(pDX, IDC_EDITSERVERPORT, m_ServerPort);
	DDX_Control(pDX, IDC_BUTTONCONNECTSERVER, m_ConnectServer);
	DDX_Control(pDX, IDC_BUTTONCONNECTCUNT, m_CutDownConnect);
	DDX_Control(pDX, IDC_BUTTONSENDMSG, m_SendMsgToServer);
}

BEGIN_MESSAGE_MAP(CMFCApplicationSocketClientDemoDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTONSENDMSG, &CMFCApplicationSocketClientDemoDlg::OnBnClickedButtonsendmsg)
	ON_BN_CLICKED(IDC_BUTTONCONNECTSERVER, &CMFCApplicationSocketClientDemoDlg::OnBnClickedButtonconnectserver)
	ON_EN_CHANGE(IDC_EDITSEND, &CMFCApplicationSocketClientDemoDlg::OnEnChangeEditsend)
	ON_BN_CLICKED(IDC_BUTTONCONNECTCUNT, &CMFCApplicationSocketClientDemoDlg::OnBnClickedButtonconnectcunt)
END_MESSAGE_MAP()


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

	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != nullptr)
	{
		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);		
	//ShowWindow(SW_MAXIMIZE);
	//ShowWindow(SW_MINIMIZE);
	UpdateData(TRUE);
    SetDlgItemText(IDC_IPADDRESS_SERVER,_T("127.0.0.1"));
	::HideCaret(GetDlgItem(IDC_EDITSEND)->GetSafeHwnd());
	SetDlgItemInt(IDC_EDITSERVERPORT, PORTSET);
	SetDlgItemText(IDC_EDITSERVERPORT, _T("8000"));
	m_CutDownConnect.EnableWindow(FALSE);
	m_ConnectServer.EnableWindow(TRUE);
	UpdateData(FALSE);
	return TRUE;  
}

void CMFCApplicationSocketClientDemoDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else if ((nID & 0xFFF0) == SC_SIZE)
	{
		return;
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}


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


void CMFCApplicationSocketClientDemoDlg::OnBnClickedButtonsendmsg()
{
	char* Pmsg;
	CString strGetMsg;
	int iWrite;
	GetDlgItemText(IDC_EDITSEND, strGetMsg);
	Pmsg = CstringToWideCharArry(strGetMsg);
	iWrite = send(m_pClientSock, Pmsg, _tcslen(strGetMsg)*sizeof(Pmsg), 0);
	if (SOCKET_ERROR == iWrite) 
	{
		SetRevTextMsg(_T("本机发送消息:") +strGetMsg +_T("失败!"));	
	}
	else
	{
		SetRevTextMsg(_T("本机发送消息: >>") + strGetMsg+_T("成功!"));
	}	
	SetDlgItemText(IDC_EDITSEND, _T(""));	
}

BOOL socket_Select(SOCKET hSocket, DWORD nTimeOut, BOOL bRead)
{
	{
		FD_SET fdset;
		timeval tv;
		FD_ZERO(&fdset);
		FD_SET(hSocket, &fdset);
		nTimeOut = nTimeOut > 1000 ? 1000 : nTimeOut;
		tv.tv_sec = 0;
		tv.tv_usec = nTimeOut;
		int iRet = 0;
		if (bRead)
		{
			iRet = select(0, &fdset, NULL, NULL, &tv);
		}
		else
		{
			iRet = select(0, NULL, &fdset, NULL, &tv);
		}
		if (iRet <= 0)
		{
			return FALSE;
		}
		else if (FD_ISSET(hSocket, &fdset))
		{
			return TRUE;
		}
		return FALSE;
	}
}

char* CMFCApplicationSocketClientDemoDlg::CstringToWideCharArry(CString CstrText)
{
	int lth = WideCharToMultiByte(CP_ACP, 0, CstrText, CstrText.GetLength(), NULL, 0, NULL, NULL);
	char* pStr = (char*)malloc((lth + 1) * sizeof(char));
	ASSERT(pStr!=NULL);
	memset(pStr, 0, (lth + 1) * sizeof(char));
	WideCharToMultiByte(CP_ACP, 0, CstrText.GetBuffer(), CstrText.GetLength(), (LPSTR)pStr, lth, NULL, NULL);
	*(pStr + lth + 1) = '\0';
	printf("lth=%d", lth);
	printf("lth+1=%d", (lth + 1) * sizeof(char));
	printf("LthStr=%d", sizeof(CString));
	printf("CharLen=%d", sizeof(char*));
	return  pStr;
}

CString CMFCApplicationSocketClientDemoDlg::CharArryToCstring(char* CharText)
{
	int charLth = strlen(CharText);
	int len = MultiByteToWideChar(CP_ACP, 0, CharText, charLth, NULL, 0);
	TCHAR* buf = new TCHAR[len + 1];
	MultiByteToWideChar(CP_ACP, 0, CharText, charLth, buf, len);
	buf[len] = '\0';
	CString pWideChar;
	pWideChar.Append(buf);
	return pWideChar;
}


void CMFCApplicationSocketClientDemoDlg::OnBnClickedButtonconnectserver()
{
	CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ConnectServerThread, this, 0, NULL);
}

BOOL CMFCApplicationSocketClientDemoDlg::ConnectServerSocket(CMFCApplicationSocketClientDemoDlg* pClient)
{
	CSoceketInitConfig ClientSockInit(2,2);

	m_pClientSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (m_pClientSock==NULL)
	{
		MessageBox(_T("ClientSocket创建失败!"),_T("信息提示:"),MB_OKCANCEL|MB_ICONERROR);
		return FALSE;
	}
	sockaddr_in ServerAddr_in;
	ServerAddr_in.sin_family = AF_INET;

	int m_SerPort = GetDlgItemInt(IDC_EDITSERVERPORT);
	CString StrSerIp;
	GetDlgItemText(IDC_IPADDRESS_SERVER,StrSerIp);
	
	if (StrSerIp==_T("0.0.0.0")||m_SerPort > 65535 || m_SerPort < 1024|| m_SerPort==0)
	{
		MessageBox(_T("请输入正确端口IP地址,重新连接!"), _T("信息提示:"), MB_OK | MB_ICONINFORMATION);
		SetRevTextMsg(_T("请输入正确端口IP地址,重新连接"));
		return FALSE;
	}
	char* pStrIP = CstringToWideCharArry(StrSerIp);

	ServerAddr_in.sin_port = htons(m_SerPort);
	ServerAddr_in.sin_addr.S_un.S_addr = inet_addr(pStrIP);
	if (SOCKET_ERROR==connect(m_pClientSock, (sockaddr*)&ServerAddr_in, sizeof(ServerAddr_in)))
	{
		MessageBox(_T("服务器连接失败,请检查你填写的IP和端口是否错误!"), _T("信息提示:"), MB_OK | MB_ICONWARNING);
		SetRevTextMsg(_T("服务器连接失败,请检查你填写的IP和端口是否错误!"));
		return FALSE;
	}
	pClient->SetRevTextMsg(_T("连接服务器成功"));
	pClient->m_CutDownConnect.EnableWindow( TRUE);
	pClient->m_ConnectServer.EnableWindow(FALSE);
	m_ServerConnectSucced = TRUE;

	CString RevMsg;
	while (true)
	{
		if (socket_Select(m_pClientSock,100,TRUE))
		{
			char recvBuff[MaxBufSize] = { 0 };
			int iRead = recv(m_pClientSock, recvBuff, sizeof(recvBuff), 0);
			if (iRead > 0)
			{
				RevMsg = CharArryToCstring(recvBuff);
				pClient->SetRevTextMsg(StrSerIp + _T(">>") + RevMsg);
			}
			else
			{
				pClient->SetRevTextMsg(_T("已断线,请重新连接"));
				m_ServerConnectSucced = FALSE;
				return TRUE;
			}
		}
		
	}
	return TRUE;
}

CString CMFCApplicationSocketClientDemoDlg::GetSystemTime()
{
	CString m_CurrentTime;
	CTime m_GetTime = CTime::GetTickCount();
	m_CurrentTime = m_GetTime.Format(_T("%Y/%m/%d:%H:%M:%S"));
	return m_CurrentTime;
}

void CMFCApplicationSocketClientDemoDlg::SetRevTextMsg(CString nText)
{
	m_ClientRecvMsg.SetSel(-1, -1);
	m_ClientRecvMsg.ReplaceSel(GetSystemTime() + _T("\r\n") + nText + _T("\r\n"));
}

DWORD WINAPI ConnectServerThread(LPCVOID lParam)
{
	CMFCApplicationSocketClientDemoDlg* pClient = (CMFCApplicationSocketClientDemoDlg*)lParam;
	if (pClient->ConnectServerSocket(pClient))
	{

	}
	return 0;
}


void CMFCApplicationSocketClientDemoDlg::OnEnChangeEditsend()
{
	CString m_Msg_Enter;
	GetDlgItemText(IDC_EDITSEND, m_Msg_Enter);
	if (m_Msg_Enter == _T("") || !m_ServerConnectSucced)
	{
		m_SendMsgToServer.EnableWindow(FALSE);
	}
	else
	{
		m_SendMsgToServer.EnableWindow(TRUE);
	}
}


void CMFCApplicationSocketClientDemoDlg::OnBnClickedButtonconnectcunt()
{
	closesocket(m_pClientSock);
	m_ServerConnectSucced = FALSE;
	m_CutDownConnect.EnableWindow(FALSE);
    m_ConnectServer.EnableWindow(TRUE);
}

 

 

 

 参考文献:

        VS 2019 MFC Socket 通讯例程服务器端Select一对多同步通信TCP/IP通信服务器端[一]_lzc881012的博客-CSDN博客TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的。3>原始套接字(SOCK_RAW):它提供一种能力,让我们直接跨越传输层,直接对IP层进行数据封装,通过该套接字,我们可以直接将数据封装成IP层能够认识的协议格式。1>流方套接字(SOCK_STREAM):它对应TCP协议,它提供面向连接的、可靠的数据传输服务,数据无差错、无重复的发送,且按发送顺序接收。https://blog.csdn.net/lzc881012/article/details/127737864?spm=1001.2014.3001.5501