C++套接字实现TCP通讯,客户端以及服务端

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

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
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大块头爱编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值