2021-07-08定义网络数据报文

该博客展示了如何使用C++和Windows Socket API实现一个简单的TCP服务端和客户端。服务端监听特定端口,接收并处理客户端的登录和登出请求,客户端则发送登录和登出命令,接收并显示服务端的响应。
摘要由CSDN通过智能技术生成

服务端

#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<windows.h>
#include<WinSock2.h>
#include<stdio.h>
#include<iostream>
using namespace std;

//指令
enum CMD
{	
	CMD_LOGIN,
	CMD_LOGINOUT,
	CMD_ERROR
};
//消息头
struct DataHeader
{
	short dataLength;
	short cmd;
};
//登录
struct Login
{
	char userName[32];
	char PassWord[32];
};
//登录结果
struct LoginResult
{
	int result;

};
//登出
struct Loginout
{
	char userName[32]; 
};
//登出结果
struct LoginoutResult
{
	int result;
};

//#pragma comment(lib,"ws2_32.lib")			//声明静态链接库
int main()
{
	WORD ver = MAKEWORD(2, 2);				//创建WINDOWS版本号
	WSADATA dat;
	WSAStartup(ver, &dat);					//启动网络环境,此函数调用了一个WINDOWS的静态链接库,因此需要加入静态链接库文件
	//-----------------

	//-- 用socket API建立简易TCP服务端
	// 1 建立一个socket
	SOCKET _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	// 2 bind 绑定用于接收客户端连接的网络端口
	sockaddr_in _sin = { };
	_sin.sin_family = AF_INET;
	_sin.sin_port = htons(4567);
	_sin.sin_addr.S_un.S_addr = INADDR_ANY;		//inet_addr("127.0.0.1");
	if (SOCKET_ERROR == bind(_sock, (sockaddr*)&_sin, sizeof(_sin)))
	{
		printf("错误,绑定网络端口失败...\n");
	}
	else {
		printf("绑定端口成功...\n");
	}

	// 3 listen 监听网络端口
	if (SOCKET_ERROR == listen(_sock, 5))
	{
		printf("错误,监听网络端口失败...\n");
	}
	else {
		printf("监听网络端口成功...\n");
	}
	// 4 accept 等待接收客户端连接
	sockaddr_in _clientAddr = { };
	int nAddrLen = sizeof(_clientAddr);
	SOCKET _cSock = INVALID_SOCKET;
	char msgBuf[] = "HELLO, I'm Server";
	char _recvBuf[128] = { };
	
	_cSock = accept(_sock, (sockaddr*)&_clientAddr, &nAddrLen);
	
	if (INVALID_SOCKET == _cSock)
	{
		printf("错误,接收到无效客户端SOCKET...\n");
	}
	printf("新客户加入:IP = %s ,socket = %d \n", inet_ntoa(_clientAddr.sin_addr), (int)_cSock);
	
	while (true)
	{
		// 5 接收客户端数据
		DataHeader header = { };
		int nLen = recv(_cSock, (char*)&header, sizeof(DataHeader), 0);
		if (nLen <= 0)
		{
			printf("客户端已退出,任务结束。");
			break;
		}
		printf("收到命令:%d 数据长度: %d\n", header.cmd, header.dataLength);
		// 6 处理请求
		switch (header.cmd)
		{
			// 7 向客户端发送数据
		case CMD_LOGIN:
		{
			Login login = { };
			recv(_cSock, (char*)&login, sizeof(Login), 0);
			//忽略判断用户密码是否正确的过程
			LoginResult ret = { 0 };
			//首先发送消息头
			send(_cSock, (char*)&header, sizeof(DataHeader), 0);
			//然后发送消息结果
			send(_cSock, (char*)&ret, sizeof(LoginResult), 0);
		}
		break;
		case CMD_LOGINOUT:
		{
			Loginout loginout = { };
			recv(_cSock, (char*)&loginout, sizeof(Loginout), 0);
			//忽略判断用户密码是否正确的过程
			LoginoutResult ret = { 0 };
			//首先发送消息头
			send(_cSock, (char*)&header, sizeof(DataHeader), 0);
			//然后发送消息结果
			send(_cSock, (char*)&ret, sizeof(LoginoutResult), 0);
		}
		break;
		default:
			header.cmd = CMD_ERROR;
			header.dataLength = 0;
			send(_cSock, (char*)&header, sizeof(DataHeader), 0);
			break;
		}

	}
		// 8 关闭套接字closesocket
		closesocket(_sock);
	
	//-----------------
	//清除Windows socket环境

	WSACleanup();							//关闭Socket网络环境
	getchar();
	return 0;
}


客户端

#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS				//忽略scanf报错

#include<windows.h>
#include<WinSock2.h>
#include<stdio.h>
#include<iostream>
using namespace std;
//指令
enum CMD
{	
	CMD_LOGIN,
	CMD_LOGINOUT,
	CMD_ERROR
};
//消息头
struct DataHeader
{
	short dataLength;
	short cmd;
};
//登录
struct Login
{
	char userName[32];
	char PassWord[32];
};
//登录结果
struct LoginResult
{
	int result;

};
//登出
struct Loginout
{
	char userName[32]; 
};
//登出结果
struct LoginoutResult
{
	int result;
};

struct DataPackage
{
	int age;
	char name[32];
};

int main()
{
	WORD ver = MAKEWORD(2, 2);				//创建WINDOWS版本号
	WSADATA dat;
	WSAStartup(ver, &dat);					//启动网络环境,此函数调用了一个WINDOWS的静态链接库,因此需要加入静态链接库文件
	//-----------------

	//-- 用socket API建立简易TCP客户端
	// 1 建立一个socket
	SOCKET _sock = socket(AF_INET, SOCK_STREAM, 0);
	if (INVALID_SOCKET == _sock)
	{
		printf("错误,建立Socket失败...\n");
	}
	else {
		printf("建立Socket成功...\n");
	}
	// 2 连接服务器 connect 
	sockaddr_in _sin = { };
	_sin.sin_family = AF_INET;
	_sin.sin_port = htons(4567);
	_sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	int ret = connect(_sock, (sockaddr*)&_sin, sizeof(sockaddr_in));
	if (ret == SOCKET_ERROR)
	{
		printf("错误,连接失败...\n");
	}
	else {
		printf("连接成功...\n");
	}
	// 3 用户输入请求
	while (true)
	{
		char cmdBuf[128] = { };
		scanf("%s", cmdBuf);

		// 4 处理请求
		if (0 == strcmp(cmdBuf, "exit"))
		{
			break;
		}
		else if (0 == strcmp(cmdBuf, "login"))
		{
			Login login = { "yql","yqlyyds" };
			DataHeader header = { sizeof(login),CMD_LOGIN };
			// 5 向服务器发送请求命令
			send(_sock, (const char*)&header, sizeof(header), 0);
			send(_sock, (const char*)&login, sizeof(login), 0);
			// 6 接收服务器返回的数据
			DataHeader retHeader = { };
			LoginResult loginRet = { };
			recv(_sock, (char*)&retHeader, sizeof(DataHeader), 0);
			recv(_sock, (char*)&loginRet, sizeof(LoginResult), 0);
			printf("LoginResult: %d \n", loginRet.result);
		}
		else if (0 == strcmp(cmdBuf, "loginout"))
		{
			Loginout loginout = { };
			DataHeader header = { sizeof(loginout),CMD_LOGINOUT };
			// 5 向服务器发送请求命令
			send(_sock, (const char*)&header, sizeof(header), 0);
			send(_sock, (const char*)&loginout, sizeof(loginout), 0);
			// 6 接收服务器返回的数据
			DataHeader retHeader = { };
			LoginResult loginoutRet = { };
			recv(_sock, (char*)&retHeader, sizeof(DataHeader), 0);
			recv(_sock, (char*)&loginoutRet, sizeof(LoginoutResult), 0);
			printf("LoginoutResult: %d \n", loginoutRet.result);
		}
		else {
			printf("不支持的命令,请重新输入。\n");
		}
	}
		// 7 关闭套接字 closesocket
		closesocket(_sock);
		//-----------------
		//清除Windows socket环境

		WSACleanup();							//关闭Socket网络环境
		printf("客户端已退出,任务结束...\n");
		getchar();
		return 0;
	
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值