在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。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)