MFC套接字实现TCP通讯,客户端以及服务端
因为最近有项目需要用到TCP通讯,我这边作为服务端,为了测试顺便也写了个客户端,方便自己测试,经过我的初步测试,服务端与客户端之间通讯正常,有兴趣的伙伴可以自行下载demo。
一、服务端
服务端类头文件 TCPServer.h
#pragma once
#include <WinSock2.h>
#include <WS2tcpip.h>
#ifndef WM_COMM_MSG_BASE
#define WM_COMM_MSG_BASE WM_USER + 617 //!< 消息编号的基点
#endif
#ifndef WM_COMM_RXCHAR
#define WM_COMM_RXCHAR WM_COMM_MSG_BASE + 10 // A character was received and placed in the input buffer.
#define WM_COMM_CLIENTOK WM_COMM_MSG_BASE + 20
#define WM_COMM_CLIENTNG WM_COMM_MSG_BASE + 30
#endif
class TCPServer
{
public:
TCPServer();
~TCPServer();
public:
static UINT AFX_CDECL RecvRequestThread(LPVOID param);
static UINT AFX_CDECL StartSrv(LPVOID param);
private:
HWND m_pOwner;
CString m_strClientAddress;
SOCKET m_sockSrv;//服务端套接字
SOCKET m_sockConn;//保存客户端套接字
CWinThread *m_thread;//该线程一直接收字符
CWinThread *m_threadStart;//该线程用来启动客户端
BOOL m_bTread = FALSE;
BOOL m_InitWsaOK=FALSE;
BOOL listenClient();
BOOL RecieveData();
public:
BOOL InitWsa(HWND pOwner, int port);
BOOL SendData(CString strSend);
void ClsoeSocket();
};
服务端类CPP文件 TCPServer.cpp
#include "stdafx.h"
#include "TCPServer.h"
TCPServer::TCPServer()
{
}
TCPServer::~TCPServer()
{
}
BOOL TCPServer::InitWsa(HWND pOwner, int port)
{
if (!m_InitWsaOK)
{
m_pOwner = pOwner;
//加载套接字
WORD wVersionRquested;
WSADATA wsaData;
int err;
wVersionRquested = MAKEWORD(1, 1);
err = WSAStartup(wVersionRquested, &wsaData);
if (err != 0)
return 0;
//创建用于监听的套接字
m_sockSrv = socket(AF_INET, SOCK_STREAM, 0);
m_InitWsaOK = TRUE;
}
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(port);
//绑定套接字
int ret = bind(m_sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
m_threadStart = AfxBeginThread(StartSrv, this);//创建一个线程用来启动服务器
return 1;
}
UINT TCPServer::StartSrv(LPVOID param)
{
TCPServer *self;
self = (TCPServer *)param;
self->listenClient();
return 0;
}
BOOL TCPServer::listenClient()
{
if (m_bTread)//如果接收数据线程已经开启,不再监听(该项目只需连接一个客户)
return 0;
//将套接字设为监听模式,准备接收客户端请求
listen(m_sockSrv, 5);
SOCKADDR_IN addrClient;
int len = sizeof(SOCKADDR);
//等待客户请求
m_sockConn = accept(m_sockSrv, (SOCKADDR*)&addrClient, &len);
char sendBuf[100];
char str[INET_ADDRSTRLEN];
sprintf_s(sendBuf, 100, "Welcome %s", inet_ntop(AF_INET, &addrClient.sin_addr, str, sizeof(str)));
m_strClientAddress = str;
//发送数据
send(m_sockConn, sendBuf, strlen(sendBuf) + 1, 0);
::SendMessage(m_pOwner, WM_COMM_CLIENTOK, (WPARAM)str, NULL);
//开启线程
m_bTread = TRUE;
m_thread = AfxBeginThread(RecvRequestThread, this);//创建一个线程用来处理请求
return 1;
}
UINT TCPServer::RecvRequestThread(LPVOID param)
{
TCPServer *self;
self = (TCPServer *)param;
self->RecieveData();
return 0;
}
BOOL TCPServer::RecieveData()
{
int ret = 0;
while (m_bTread)
{
char recvBuf[100];
//接收字符
ret = recv(m_sockConn, recvBuf, 100, 0);
if (ret == -1)//断开连接
{
CString str;
str.Format("与%s连接已断开!!!", m_strClientAddress);
//AfxMessageBox(str);
m_bTread = 0;
::SendMessage(m_pOwner, WM_COMM_CLIENTNG, (WPARAM)m_strClientAddress.GetBuffer(), NULL);
return 0;
}
::SendMessage(m_pOwner, WM_COMM_RXCHAR, (WPARAM)recvBuf, (LPARAM)&ret);
}
return 1;
}
BOOL TCPServer::SendData(CString strSend)
{
if (!m_bTread)
return 0;
send(m_sockConn, strSend.GetBuffer(), strlen(strSend) + 1, 0);
return 1;
}
void TCPServer::ClsoeSocket()
{
//关闭套接字
m_bTread = FALSE;
closesocket(m_sockConn);
}
二、客户端
客户端类头文件 TCPCLient.h
#pragma once
#include <WinSock2.h>
#include <WS2tcpip.h>
#include "afxcmn.h"
#include "afxwin.h"
#pragma comment(lib,"Ws2_32.lib")
#ifndef WM_COMM_MSG_BASE
#define WM_COMM_MSG_BASE WM_USER + 620 //!< 消息编号的基点
#endif
#ifndef WM_COMM_RXCHAR
#define WM_COMM_RXCHAR WM_COMM_MSG_BASE + 10 // A character was received and placed in the input buffer.
#define WM_COMM_CLIENTOK WM_COMM_MSG_BASE + 20
#define WM_COMM_CLIENTNG WM_COMM_MSG_BASE + 30
#endif
class TCPCLient
{
public:
TCPCLient();
~TCPCLient();
public:
static UINT AFX_CDECL RecvRequestThread(LPVOID param);//接收字符串线程函数
private:
HWND m_pOwner;
BOOL m_bTread = FALSE;
BOOL m_InitWsaOK = FALSE;
SOCKET m_sockClient;
CWinThread *m_thread;
BOOL RecieveData(); //接收字符串
CString m_strServerAddress;
public:
BOOL InitWsa(HWND pOwner, CString strServerAddress, int port);//初始化套接字,连接服务器
BOOL SendData(CString strSend);
void ClsoeSocket();
};
客户端类CPP文件 TCPCLient.cpp
#include "stdafx.h"
#include "TCPCLient.h"
TCPCLient::TCPCLient()
{
}
TCPCLient::~TCPCLient()
{
WSACleanup();
}
BOOL TCPCLient::InitWsa(HWND pOwner,CString strServerAddress, int port)
{
if (!m_InitWsaOK)
{
m_pOwner = pOwner;
//加载套接字
WORD wVersionRquested;
WSADATA wsaData;
int err;
wVersionRquested = MAKEWORD(1, 1);
err = WSAStartup(wVersionRquested, &wsaData);
if (err != 0)
return 0;
m_InitWsaOK = TRUE;
}
if (m_bTread)//如果接收数据线程已经开启,说明已经连接服务器
return 0;
//创建套接字
m_sockClient = socket(AF_INET, SOCK_STREAM, 0);
SOCKADDR_IN addrSrv;
inet_pton(AF_INET, strServerAddress, &addrSrv.sin_addr);
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(port);
//向服务器发出连接请求
BOOL ret = connect(m_sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
if (ret == 0)
{
m_strServerAddress = strServerAddress;
::SendMessage(m_pOwner, WM_COMM_CLIENTOK, (WPARAM)strServerAddress.GetBuffer(), NULL);
//开启线程
m_bTread = TRUE;
m_thread = AfxBeginThread(RecvRequestThread, this);//创建一个线程用来处理请求
}
else
{
AfxMessageBox("连接服务器失败");
::SendMessage(m_pOwner, WM_COMM_CLIENTNG, (WPARAM)strServerAddress.GetBuffer(), NULL);
return 0;
}
return 1;
}
UINT TCPCLient::RecvRequestThread(LPVOID param)
{
TCPCLient *self;
self = (TCPCLient *)param;
self->RecieveData();
return 0;
}
BOOL TCPCLient::RecieveData()
{
int ret = 0;
while (m_bTread)
{
char recvBuf[100];
//接收字符
ret = recv(m_sockClient, recvBuf, 100, 0);//该函数会一直等待,会阻滞程序,所以要开线程跑
if (ret == -1)//断开连接
{
CString str;
str.Format("与%s服务器连接已断开!!!", m_strServerAddress);
AfxMessageBox(str);
m_bTread = 0;
::SendMessage(m_pOwner, WM_COMM_CLIENTNG, (WPARAM)m_strServerAddress.GetBuffer(), NULL);
return 0;
}
::SendMessage(m_pOwner, WM_COMM_RXCHAR, (WPARAM)recvBuf, (LPARAM)&ret);
}
return 1;
}
BOOL TCPCLient::SendData(CString strSend)
{
send(m_sockClient, strSend.GetBuffer(), strlen(strSend) + 1, 0);
return 1;
}
void TCPCLient::ClsoeSocket()
{
m_bTread = FALSE;
//关闭套接字
closesocket(m_sockClient);
}
三、DEMO程序下载
demo程序运行界面如下图,有需要的同学可以自行下载:
demo链接地址:https://download.youkuaiyun.com/download/bin1995/75369790


本文介绍了如何使用C++实现TCP通信,包括服务端和客户端的详细步骤。提供了服务端(TCPServer)和客户端(TCPClient)的头文件及源代码,并附带DEMO程序下载,便于读者测试与学习。
534

被折叠的 条评论
为什么被折叠?



