在MFC中的socket编程

新建两个基于对话框的工程,分别为sFile、cFile。
在s端添加两个Edit:一个显示窗口IDC_EDIT1(点击右键选择Properties->Styles,选中Multiline,Vertical scroll、Read-only三项),一个输入窗口IDC_EDIT2。然后增加一个发送按钮:IDC_BtnSend。
在c端添加三个Edit:一个显示窗口IDC_EDIT1(点击右键选择Properties->Styles,选中Multiline,Vertical scroll、Read-only三项),一个输入窗口IDC_EDIT2,一个IP地址输入窗口IDC_EDIT3。再增加两个按钮:一个发送按钮IDC_SEND,一个连接服务器按钮IDC_btnConnect。
客户端
在这里插入图片描述
服务器端具体步骤如下
1、在StdAfx.h中添加 #include <afxsock.h>
在Resource.h中添加#define IDP_SOCKETS_INIT_FAILED 103
在sFileDlg.h中添加public:void update(CString s);
在sFileDlg.h中添加private:
CEdit* show_edit;
CEdit* send_edit;

public:
	void update(CString s);

private:
	CEdit* send_edit;
	CEdit* show_edit;
public:
	afx_msg void OnBnClickedBtnsend();
	virtual BOOL PreTranslateMessage(MSG* pMsg);

2、在sFileDlg.cpp中添加#include <winsock2.h>(加在#include "stdafx.h"之后)
#pragma comment(lib, “WS2_32.lib”)
新建两个socket:SOCKET listen_sock;
SOCKET sock;
声明线程函数 UINT server_thd(LPVOID p);
在项目属性-C/C++预处理器中添加
_WINSOCK_DEPRECATED_NO_WARNINGS

#include "stdafx.h"
#include <winsock2.h>
#include "sFile.h"
#include "sFileDlg.h"
#include "afxdialogex.h"
#pragma comment(lib, "WS2_32.lib")

SOCKET listen_sock;
SOCKET sock;
UINT server_thd(LPVOID p);

3、在OnInitDialog()函数中添加:

	show_edit = (CEdit *)GetDlgItem(IDC_EDIT1);
	send_edit = (CEdit *)GetDlgItem(IDC_EDIT2);
	send_edit->SetFocus();

	char name[128];
	CString IP;
	hostent* pHost;
	gethostname(name, 128);		//获得主机名
	pHost = gethostbyname(name);		//获得主机结构
	IP = inet_ntoa(*(in_addr*)pHost->h_addr);		//获得主机IP
	update(_T("本机服务器IP地址:") + IP);

4、 添加函数update():

void CSFileDlg::update(CString s)
{
	show_edit->ReplaceSel(s + "\r\n");
}

5、添加线程函数server_thd():

UINT server_thd(LPVOID p)
{
	WSADATA wsaData;
	WORD wVersion;
	wVersion = MAKEWORD(2, 2);		//将两个参数转换成八位二进制,然后将第一个数放在低位,第二个参数放在高位,最后转换为十进制。其实意思就是调用2.2版本
	WSAStartup(wVersion, &wsaData);			//根据版本搜索相应的Socket库,执行成功返回0
	SOCKADDR_IN local_addr;
	SOCKADDR_IN client_addr;
	int iaddrSize = sizeof(SOCKADDR_IN);
	int res;
	char msg[1024];
	CsFileDlg* dlg = (CsFileDlg*)AfxGetApp()->GetMainWnd();
	local_addr.sin_family = AF_INET;			//表示协议簇 AF_INET表示TCP/IP协议并使用ipv4
	local_addr.sin_port = htons(5150);
	local_addr.sin_addr.s_addr = htons(INADDR_ANY);

	if ((listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)		//根据指定的地址族、数据类型和协议来分配一个socket的描述字及其所用的资源
	{
		dlg->update(_T("创建监听失败"));
	}
	if (bind(listen_sock, (struct sockaddr*)&local_addr, sizeof(SOCKADDR_IN)))		//绑定套接字,也就是把一个地址族中的特定地址付给socket
	{
		dlg->update(_T("绑定错误"));
	}
	listen(listen_sock, 1);		//监听socket,参数1:要监听的socket描述字  参数2:socket可以排队的最大连接个数
	if ((sock = accept(listen_sock, (struct sockaddr *)&client_addr, &iaddrSize)) == INVALID_SOCKET)		//接收套接字,第一个服务器端描述字,第二个客户端socket地址,第三个socket地址长度
	{
		dlg->update(_T("accept失败"));
	}
	else
	{
		CString port;
		port.Format(_T("%d"), int(ntohs(client_addr.sin_port)));
		dlg->update(_T("已连接客户端:") + CString(inet_ntoa(client_addr.sin_addr)) + "端口:" + port);
	}
	//接收数据
	while (1)
	{
		if ((res = recv(sock, msg, 1024, 0)) == 0)
		{
			dlg->update(_T("失去客户端的连接"));
			break;
		}
		else
		{
			msg[res] = '\0';
			dlg->update(_T("client:") + CString(msg));
		}
	}

	return 0;
}

6、添加按钮实现函数

void CsFileDlg::OnBnClickedBtnsend()
{
	// TODO: 在此添加控件通知处理程序代码
	CString s;
	char *msg;
	send_edit->GetWindowTextW(s);
	CString Cmsg = s.GetBuffer(s.GetLength());
	USES_CONVERSION;
	msg = T2A(Cmsg);
	if (send(sock, msg, strlen(msg), 0) == SOCKET_ERROR)
	{
		show_edit->ReplaceSel(_T("发送失败"));
	}
	else if (s == "")
	{
		MessageBox(_T("请输入信息"));
	}
	else
	{
		show_edit->ReplaceSel("sever:" + s + "\r\n");			//消息上屏,清空输入,并重获焦点
		send_edit->SetWindowText(_T(""));
		send_edit->SetFocus();
	}
}

7、在sFile.cpp的InitInstance()函数中添加:

 if (!AfxSocketInit())
 {
 	 AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
 	 return FALSE;
 }

客户端具体步骤如下:
1、在StdAfx.h中添加 #include <afxsock.h>
在Resource.h中添加#define IDP_SOCKETS_INIT_FAILED 103
在cFileDlg.h中添加public:void update(CString s);
在cFileDlg.h中添加private:
CEdit* edit1;
CButton* btnconn;
CEdit* send_edit;
CEdit* ip_edit;

public:
	void update(CString s);

private:
	CEdit* edit1;
	CButton* btnconn;
	CEdit* send_edit;
	CEdit* ip_edit;
public:
	afx_msg void OnBnClickedSend();
	afx_msg void OnBnClickedbtnconnect();
	virtual BOOL PreTranslateMessage(MSG* pMsg);

2、在cFileDlg.cpp中添加#include <winsock2.h>(加在#include "stdafx.h"之后)
#pragma comment(lib, “WS2_32.lib”)
新建一个socket:SOCKET sock;
声明线程函数 UINT recv_thd(LPVOID p);

#include "stdafx.h"
#include <winsock2.h>
#include "sFile.h"
#include "sFileDlg.h"
#include "afxdialogex.h"
#pragma comment(lib, "WS2_32.lib")

SOCKET sock;
UINT recv_thd(LPVOID p);

3、在OnInitDialog()函数中添加:

	edit1 = (CEdit *)GetDlgItem(IDC_EDIT1);
	send_edit = (CEdit *)GetDlgItem(IDC_EDIT2);
	btnconn = (CButton *)GetDlgItem(IDC_btnConnect);
	ip_edit = (CEdit*)GetDlgItem(IDC_EDIT3);

	ip_edit->SetWindowText(_T("127.0.0.1"));

4、添加函数update():

void CcFileDlg::update(CString s)
{
	show_edit->ReplaceSel(s + "\r\n");
}

5、添加线程函数recv_thd():

UINT recv_thd(LPVOID p)
{
	int res;
	char msg[1024];
	CString s;
	CcFileDlg * dlg = (CcFileDlg *)AfxGetApp()->GetMainWnd();
	//dlg->update(_T("in thd"));
	while (1)
	{
		res = recv(sock, msg, 1024, 0);
		if (res == 0)
		{
			dlg->update(_T("失去服务器的连接"));
			break;
		}
		else
		{
			msg[res] = '\0';
			dlg->update(_T("sever:") + CString(msg));
		}
	}
	return 0;
}c

6、添加按钮实现函数void CcFileDlg::OnBnClickedBtnsend():

void CcFileDlg::OnBnClickedSend()
{
	// TODO: 在此添加控件通知处理程序代码
	CString s;
	char* msg;
	send_edit->GetWindowText(s);
	CString Cmsg = s.GetBuffer(s.GetLength());
	USES_CONVERSION;
	msg = T2A(Cmsg);
	if (send(sock, msg, strlen(msg), 0) == SOCKET_ERROR)
	{
		update(_T("发送失败"));
	}
	else if (s == "")
	{
		MessageBox(_T("请输入信息"));
	}
	else
	{
		update(_T("client:") + s);
		send_edit->SetWindowText(_T(""));
		send_edit->SetFocus();
	}
}

7、添加连接按钮实现函数OnConnect():

void CcFileDlg::OnBnClickedbtnconnect()
{
	// TODO: 在此添加控件通知处理程序代码
	WSADATA wsaData;
	SOCKADDR_IN server_addr;
	WORD wVersion;
	wVersion = MAKEWORD(2, 2);
	WSAStartup(wVersion, &wsaData);
	CString ip;
	ip_edit->GetWindowText(ip);		//取得服务器中的ip地址
	USES_CONVERSION;
	char* cip = T2A(ip);
	server_addr.sin_addr.s_addr = inet_addr(cip);
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(5150);

	if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
	{
		edit1->ReplaceSel(_T("create socket error\r\n"));
	}

	if (connect(sock, (struct sockaddr*) &server_addr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)		//连接某个socket
	{
		edit1->ReplaceSel(_T("连接失败\r\n"));
	}
	else
	{
		edit1->ReplaceSel(_T("连接成功\r\n"));
		AfxBeginThread(&recv_thd, 0);
		btnconn->EnableWindow(FALSE);			//按钮变灰
	}
}

如果需要回车键发送的话可以添加:

BOOL CcFileDlg::PreTranslateMessage(MSG* pMsg)		//添加类向导,之后选择虚函数,添加PreTranslateMessage函数
{
	// TODO: 在此添加专用代码和/或调用基类
	if (pMsg->message ==  WM_KEYDOWN)		//如果一个按钮被触发
	{
		int nVirtKey = (int)pMsg->wParam;
		if (nVirtKey == VK_RETURN)
		{
			//如果是回车在这里做想做的事
			OnBnClickedSend();
			pMsg->wParam = VK_TAB;
		}
	}

	return CDialogEx::PreTranslateMessage(pMsg);
}

以上便是简单的通过socket在MFC中的简单通信Demo。

  • 6
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值