TCP客户端与服务器MFC

一、首先为界面设置:


屏蔽一些控件,所以在你初始化时,添加代码如下:

BOOL CTCP客户程序Dlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// TODO: 在此添加额外的初始化代码

	GetDlgItem(IDC_TEXT)->EnableWindow(FALSE);         //将消息显示框,发送消息编辑框,发送按键禁用
	GetDlgItem(IDC_SENDTEXT)->EnableWindow(FALSE);
	GetDlgItem(IDC_SEND)->EnableWindow(FALSE);
	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}


除了界面初始化,还应该对套接字进行初始化,如下:

在CTCP客户端程序Dlg::OnInitDialog()中包含:

s = ::socket(AF_INET, SOCK_STREAM, 0); 


在class CTCP客户程序Dlg : public CDialogEx()中包含

SOCKET s;             //定义套接字对象
	sockaddr_in addr;     //定义套接字地址结构变量


初始化如图所示:



二、为按钮添加处理函数

1.connect按键:

void CTCP客户程序Dlg::OnBnClickedConnect()
{
	// TODO: 在此添加控件通知处理程序代码
	CString str, str1;
	int port;

	GetDlgItem(IDC_ADDR)->GetWindowText(str);
	GetDlgItem(IDC_PORT)->GetWindowText(str1);

	if ( str == "" || str1 == "" )
	{
		MessageBox("服务器地址或者端口不能为NULL");
	}
	else
	{
		port = atoi(str1.GetBuffer(1));//将端口字符串转换为数字
		addr.sin_family = AF_INET;
		addr.sin_addr.S_un.S_addr = inet_addr(str.GetBuffer(1));
		addr.sin_port = ntohs(port);

		GetDlgItem(IDC_TEXT)->SetWindowText("正在连接服务器....\r\n");
	}

	if ( ::connect(s, (sockaddr*)&addr, sizeof(addr)) != SOCKET_ERROR )
	{
		GetDlgItem(IDC_TEXT)->GetWindowText(str);
		str += "连接服务器成功!\r\n";

		GetDlgItem(IDC_TEXT)->SetWindowText(str);
		GetDlgItem(IDC_SENDTEXT)->EnableWindow(true);
		GetDlgItem(IDC_SEND)->EnableWindow(true);
		GetDlgItem(IDC_ADDR)->EnableWindow(false);
		GetDlgItem(IDC_PORT)->EnableWindow(false);
	}
	else
	{
		GetDlgItem(IDC_TEXT)->GetWindowText(str);
		str += "连接服务器失败! 请重试\r\n";
		GetDlgItem(IDC_TEXT)->SetWindowText(str);
	}

}
注:在vs2012中如果是unicode编码的话,在atoi(str1.GetBuffer(1))这会提示无法从LPCTSTR转化为const char*,最省事的办法是将编码方式选择为多字节


2.send按键

void CTCP客户程序Dlg::OnBnClickedSend()
{
	// TODO: 在此添加控件通知处理程序代码
	CString str, str1;
	GetDlgItem(IDC_SENDTEXT)->GetWindowText(str);
	if (str == "")
	{
		GetDlgItem(IDC_TEXT)->GetWindowTextA(str1);
		str1 += "\r\n";
		str1 += "消息不能为空\r\n";

		GetDlgItem(IDC_TEXT)->SetWindowText(str1);
	}
	else
	{
		::send(s, str.GetBuffer(1), sizeof(str), 0);
		GetDlgItem(IDC_TEXT)->GetWindowTextA(str1);
		str1 += "\r\n";
		str1 += str;
		GetDlgItem(IDC_TEXT)->SetWindowText(str1);
	}
}

LRESULT CTCP客户程序Dlg::OnSocket(WPARAM wParam, LPARAM lParam)
{
	char cs[100] = {0};
	if (lParam == FD_READ)
	{
		CString num = "";
		recv(s, cs, 100, NULL);
		GetDlgItem(IDC_TEXT)->GetWindowText(num);
		num += "\r\n服务器说: ";
		num += (LPTSTR)cs;
		GetDlgItem(IDC_TEXT)->SetWindowText(num);
	}
	return true;
}

3.接收与显示服务端信息

这里采用异步套接字模式。

在BOOL CTCP客户程序Dlg::OnInitDialog()中初始化异步套接字模式

::WSAAsyncSelect(s, this->m_hWnd, WM_SOCKET, FD_READ);

将异步套接字处理的时间指定为读取时间,并将事件处理消息指定为WM_SOCKET,代码如下:


#define WM_SOCKET WM_USER + 100
class CTCP客户程序Dlg : public CDialogEx
{
  afx_msg LRESULT OnSocket(WPARAM wParam, LPARAM lParam);
}

BEGIN_MESSAGE_MAP(CTCP客户程序Dlg, CDialogEx)
	ON_MESSAGE(WM_SOCKET,OnSocket)
END_MESSAGE_MAP()
LRESULT CTCP客户程序Dlg::OnSocket(WPARAM wParam, LPARAM lParam)
{
	char cs[100] = {0};
	if (lParam == FD_READ)
	{
		CString num = "";
		recv(s, cs, 100, NULL);
		GetDlgItem(IDC_TEXT)->GetWindowText(num);
		num += "\r\n服务器说: ";
		num += (LPTSTR)cs;
		GetDlgItem(IDC_TEXT)->SetWindowText(num);
	}
	return true;
}


---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
TCP服务器端:
界面初始化:

在class CTCP服务器程序Dlg : public CDialogEx中定义套接字相关变量

SOCKET s, s1;
	sockaddr_in addr, addr1;
	int n;

在对话框初始函数中创建套接字并且将套接字绑定到本地地址
BOOL CTCP服务器程序Dlg::OnInitDialog()
{
  addr.sin_family = AF_INET;
	addr.sin_port = htons(75);
	addr.sin_addr.S_un.S_addr = INADDR_ANY;

	s = ::socket(AF_INET, SOCK_STREAM, 0);
	::bind(s, (sockaddr*)&addr, sizeof(addr));
	::listen(s, 5);
	::WSAAsyncSelect(s, this->m_hWnd, WM_SOCKET, FD_ACCEPT|FD_READ);

	GetDlgItem(IDC_TEXT)->EnableWindow(false);
	GetDlgItem(IDC_ADDR)->SetWindowText("服务器监听已经启动!");
}

TCP服务器具有监听、发送和接收数据的功能。因为服务器必须等待客户端的连接请求之后,才能实现接收和发送数据。将服务器创建的套接字设置为异步模式,并将套接字事件设置为连接和读取事件。

#define  WM_SOCKET WM_USER+10
class CTCP服务器程序Dlg : public CDialogEx
{
   virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	afx_msg LRESULT OnSocket(WPARAM wParam, LPARAM lParam);
	DECLARE_MESSAGE_MAP()
}

::WSAAsyncSelect(s, this->m_hWnd, WM_SOCKET, FD_ACCEPT|FD_READ);
ON_MESSAGE(WM_SOCKET, OnSocket)

响应套接字上的相关事件:
LRESULT CTCP服务器程序Dlg::OnSocket(WPARAM wParam, LPARAM lParam)
{
	CString str13;
	char cs[100] = {0};
	switch (lParam)
	{
	case FD_ACCEPT:
		{
			int lenth = sizeof(addr1);
			s1 = ::accept(s, (sockaddr*)&addr1, &lenth);

			n = n + 1;
			
			str13.Format("有%d客户已经连接上了", n);
			GetDlgItem(IDC_TEXT)->SetWindowText(str13);

			str13 += ::inet_ntoa(addr1.sin_addr);
			str13 += "登录\r\n";

			GetDlgItem(IDC_TEXT)->SetWindowText(str13);
		}
		break;

	case FD_READ:
		{
			CString num ="";
			::recv(s1, cs, 100, 0);
			GetDlgItem(IDC_TEXT)->GetWindowText(num);
			num += "\r\n";

			num += (LPCTSTR)::inet_ntoa(addr1.sin_addr);
			num += "对您说: ";
			num += (LPCTSTR)cs;

			GetDlgItem(IDC_TEXT)->SetWindowText(num);
		}
		break;
	
	}

	return true;
}

添加发送功能:
void CTCP服务器程序Dlg::OnBnClickedSend()
{
	// TODO: 在此添加控件通知处理程序代码
	CString str = "";
	GetDlgItem(IDC_SENDTEXT)->GetWindowText(str);

	if (str == "")
	{
		MessageBox("消息不能为空!");
	}
	else
	{
		if (::send(s1, str.GetBuffer(1), sizeof(str), 0) != SOCKET_ERROR)
		{
			GetDlgItem(IDC_TEXT)->SetWindowText("消息已经发送到客户端!\r\n");

			GetDlgItem(IDC_TEXT)->GetWindowText(str);
			str += "\r\n";

			GetDlgItem(IDC_TEXT)->SetWindowText(str);;
		}
		else
		{
			GetDlgItem(IDC_TEXT)->SetWindowText("发送消息失败!\r\n");
		}
	}

}


--------------------------------------------------------------------------------------------------------
以下是客户端与服务器连接图:


  • 8
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值