[MFC] Learn MFC day5 vs2019 dialog-based MFC application & TCP socket application developed using CAsyncSocket class

[MFC] Learn MFC day5 vs2019 dialog-based MFC application & TCP socket application developed using CAsyncSocket class

Previous

Today’s goal:

1. Make a server and client application.
2. Realize sending information from the client to the server and display it on the server list box (List Control) control

Start:

Today’s code file Github link will also be placed at the bottom of the blog.
Everyday I’m lazy and use the project of the previous blog as the server, and make some modifications.
Create a new dialog-based MFC project as the client. The
following table is the steps for the server and the client to interact

Server Client
AfxSocketIint() AfxSocketIint()
CSocket sockSrvr; CSocket sockClient;
sockSrvr.Create(nPort);1,2 sockClient.Create( );2
sockSrvr.Listen( );
sockClient.Connect(strAddr, nPort);3,4
CSocket sockRecv; sockSrvr.Accept (sockRecv); 5

Server interface (class name CMFCDialogDlg):

Insert picture description here

1. Create a new TcpSever class and inherit from the CAsyncSocket class

CAsyncSocket class constructor:
CAsyncSocket constructs a CAsyncSocket object
Create creates a socket

CAsyncSocket class member functions:
Attach attaches a socket handle to the CAsyncSocket object
Detach removes the socket handle from the CAsyncSocket object
FromHandle returns a pointer to the CAsyncSocket object, gives the socket handle
GetLastError to obtain the status of the previous run failure
GetPeerName obtains the socket The address of the connected peer socket
GetSockName Gets the local name
of the socket GetSockOpt Gets the socket option
SetSockOpt Sets the socket option
Accept Accepts the connection
on the socket AsyncSelect Requests the event notification
of the socket Bind and the socket The local address related to the word
Close Close the socket
Connect to establish a connection to the peer socket
IOCtl Control the socket mode
Listen to establish a socket, listen to the upcoming connection request
Receive Receive data from the socket
ReceiveFrom Resume the datagram and Storage resource address
Send Send data to the connected socket
SendTo Send data to a specific destination
ShutDown invalidates Send and/or Receive calls on the socket

The CAsyncSocket class overrides the notification function:
OnAccept notifies the listening socket, it can accept the pending connection request by calling Accept,
OnClose notifies the socket, closes its socket connection,
OnConnect notifies the connected socket, the connection attempt has been completed , Regardless of success or failure,
OnOutOfBandData notifies the receiving socket, and there is out-of-band data read on the socket, usually a busy message.
OnReceive notifies the listening socket, and restores the data by calling Receive.
OnSend notifies the socket by calling Send , It can send data

2. Reference the afxsock.h header file in the TcpSever class

TcpSever.h code:
where typedef struct MyMsg is the structure of the message sent from the client to the server.

#pragma once
#include<afxsock.h>
#include "pch.h"
#include "resource.h"
typedef struct MyMsg
{
    
    
	char name[20]="";
	char position[10]="";
	char Style[128]="";
};
class TcpSever:public CAsyncSocket
{
    
    
public:
	CListCtrl *mList1=new CListCtrl();
	void UpdataListCtrl(MyMsg* Msg);
	void setListCtrl(CListCtrl* mList);
	TcpSever();
	virtual void OnAccept(int nErrorCode);
	virtual void OnReceive(int nErrorCode);
	//
};

The code of TcpSever.cpp:

#include "pch.h"
#include "TcpSever.h"

void TcpSever::UpdataListCtrl(MyMsg* Msg)
{
    
    
	int count = -1;
	/*转换格数*/
	CString name;
	CString position;
	CString Style;
	name.Format(_T("%s"), Msg->name);
	position.Format(_T("%s"), Msg->position);
	Style.Format(_T("%s"), Msg->Style);
	//把数据写到List 控件
	count = mList1->GetItemCount();
	mList1->InsertItem(count, name);
	mList1->SetItemText(count, 1, position);
	mList1->SetItemText(count, 2, Style);
	
}

void TcpSever::setListCtrl(CListCtrl* mList)
{
    
    
	this->mList1 = mList;
}

TcpSever::TcpSever()
{
    
    

}

/*OnAccept(int nErrorCode)由框架调用,通知监听套接字现在可以调用Accept成员函数
来接收悬挂的(pending)连接请求。
*/
void TcpSever::OnAccept(int nErrorCode)
{
    
    
	//newTcp = new TcpSever();
	TcpSever* newTcp = new TcpSever();
	if (this->Accept(*newTcp)) {
    
    
		newTcp->setListCtrl(this->mList1);//将this->mList1传给newTcp
		CString str;
		UINT port;
		newTcp->GetPeerName(str, port);//获得与套接字连接的对等套接字的地址 
		newTcp->GetSockName(str, port);//获得套接字的本地名 
	}
	CAsyncSocket::OnAccept(nErrorCode);

}

/*本函数由框架调用,通知套接字缓冲中有数据,
可以调用Receive成员函数取出。*/
void TcpSever::OnReceive(int nErrorCode)
{
    
    

	MyMsg Msg = {
    
    "","",""};
	this->Receive(&Msg,sizeof(Msg));
	UpdataListCtrl(&Msg);
	//this->Close();
}

3. CMFCDialogDlg class

Refer to TcpSever.h in the
CMFCDialogDlg class and add the public TcpSever server member variables in the CMFCDialogDlg class and instantiate them *

TcpSever* server = new TcpSever();
BOOL CMFCDialogDlg::OnInitDialog()
{
    
    
	。。。。。。//代表省略其他代码
	// TODO: 在此添加额外的初始化代码
}

Add in OnInitDialog() (initialization function) above

AfxSocketInit();//初始套接字//这是自带的不需要定义,直接调用

4. The click event code of the button titled "Enable remote submission":

void CMFCDialogDlg::OnBnClickedButton3()
{
    
    
	// TODO: 在此添加控件通知处理程序代码
	server = new TcpSever();
	if (server->Create(8967, 1, 63L, NULL)) {
    
    //端口为8967
		server->setListCtrl(&(this->mList1));//传入List控件的指针
		server->Listen();
	}
}

BOOL CAsyncSocket::Create(
UINT nSocketPort = 0,
int nSocketType = SOCK_STREAM,
long lEvent = FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT|FD_CLOSE,
LPCTSTR lpszSocketAddress = NULL
);

The known port used by the nSocketPort socket. If you want the Windows socket to select the port, this value is 0.
nSocketType SOCK_STREAM or SOCK_DGRAM.
lEvent bit mask, which specifies the combination of network events that the application is interested in. · FD_READ wants to receive a read notification for reading.
· FD_WRITE I want to receive notification when data reading is valid.
· FD_OOB wants to restore the notification of out-of-band data arrival.
· FD_ACCEPT wants to receive notifications about the connection.
· FD_CONNECT wants to receive notification of the connection result.
· FD_CLOSE Want to receive notification when the socket is closed under test.
lpszSockAddress Pointer to a string. This string contains the network address of the socket to be connected, such as a number separated by a period: "128.56.22.8". If it is NULL, the network address is not specified.

Client interface (class name CClienttcpDlg):Insert picture description here

1. Create a new TcpClient class and inherit from the CAsyncSocket class

In fact, you don’t need to build this class, just use the CAsyncSocket class directly

2. Reference the afxsock.h header file in the TcpSever class

The code of TcpClient.h:

#pragma once
#include <afxsock.h>
class TcpClient :
    public CAsyncSocket
{
    
    
public:
    virtual void OnConnect(int nErrorCode);
    virtual void OnReceive(int nErrorCode);

};

The code of TcpClient.cpp:

#include "pch.h"
#include "TcpClient.h"
void TcpClient::OnConnect(int nErrorCode)
{
    
    
	CAsyncSocket::OnConnect(nErrorCode);
}
void TcpClient::OnReceive(int nErrorCode)
{
    
    
	CAsyncSocket::OnReceive(nErrorCode);
}

3. CClienttcpDlg class

Reference TcpClient.h in the CClienttcpDlg class
* Add the public TcpClient Client member variable in the CClienttcpDlg class and instantiate it

TcpClient *Client=new TcpClient();
BOOL CMFCDialogDlg::OnInitDialog()
{
    
    
	。。。。。。//代表省略其他代码
	// TODO: 在此添加额外的初始化代码
}

Add in OnInitDialog() (initialization function) above

AfxSocketInit();//初始套接字//这是自带的不需要定义,直接调用
Client->Create();//创建套接字

Control and control variable binding (see my previous blog in this series for specific operations)

	// 名字
	CEdit NameEdit;
	// 职务
	CComboBox PositionBox;
	// 自我介绍
	CEdit StyleEdit;

4. The click event code of the button titled "Connect and Send":

void CClienttcpDlg::OnBnClickedButton1()
{
    
    
	// TODO: 在此添加控件通知处理程序代码
	CString test=CString("");
	if (Client->Connect(CString("192.168.3.15"), 8967)) {
    
    
	}
	else
	{
    
    
		//GetLastError() 获取错误代码
		if (Client->GetLastError() == WSAEWOULDBLOCK) {
    
    
		/*如果确定了WSAEWOULDBLOCK的错误代码,
		并且应用正在使用函数覆盖的调用,
		则当连接操作完成时,应用将接收OnConnect消息。*/
			CString name;
			CString position;
			CString Style;
			NameEdit.GetWindowTextW(name);
			StyleEdit.GetWindowTextW(Style);
			PositionBox.GetLBText(PositionBox.GetCurSel(), position);
			MyMsg msg = {
    
    "","",""};
			memcpy(msg.name, name, name.GetLength()*2);
			memcpy(msg.position, position, position.GetLength() * 2);
			memcpy(msg.Style, Style, Style.GetLength() * 2);
			Client->Send(&msg, sizeof(msg));
			return;
		}
	}
}

Final renderings:

Insert picture description here

At last

Thank you for reading, please correct me if there are any errors

Additional:

The GitHub address of the project source code file of this blog

Guess you like

Origin blog.csdn.net/m0_46202128/article/details/107849913