socket学习02(发送结构化消息)

发送结构化消息
网络数据报文的格式定义:
报文有两部分:包头和包体,是网络消息的基本单元
包头:描述本次消息的大小,描述数据的作用
包体:数据

server

// Sock01.cpp : 定义控制台应用程序的入口点。
//
//#define _WINSOCK_DEPRECATED_NO_WARNINGS   //属性 预处理 添加
#include "stdafx.h"
#include<WinSock2.h>
#include<Windows.h>
//#pragma comment(lib,"ws2_32.lib")

enum CMD
{
	CMD_LOGIN,
	CMD_LOGIN_RESULT,
	CMD_LOGOUT,
	CMD_LOGOUTRESULT,
	CMD_ERROR
};
struct DataHeader
{
	short dataLength;
	short cmd;
};
struct Login:public DataHeader
{
	Login()
	{
		dataLength = sizeof(Login);
		cmd = CMD_LOGIN;
	}
	char userName[32];
	char passWord[32];
};
struct LoginResult:public DataHeader
{

	LoginResult()
	{
		dataLength = sizeof(LoginResult);
		cmd = CMD_LOGIN_RESULT;
		result = 0;
	}
	int result;
};
struct Logout :public DataHeader
{
	Logout()
	{
		dataLength = sizeof(Logout);
		cmd = CMD_LOGOUT;
	}
	char userName[32];
};
struct LogoutResult :public DataHeader
{
	LogoutResult()
	{
		dataLength = sizeof(LogoutResult);
		cmd = CMD_LOGOUTRESULT;
		result = 0;
	}
	int result;
};
int main()
{
	//cc209 加入接受缓冲区

	WORD ver = MAKEWORD(2, 2);
	WSADATA dat;
	WSAStartup(ver, &dat);  //启动windows socket 2环境
							//建立简易的tcp服务端

	SOCKET _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);     //socket编程有三种:流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM),原始套接字(SOCK_RAW) TCP基于流式
//2.BIND 绑定用于接受客户端连接的网络端口
	sockaddr_in _sin = {};
	_sin.sin_family = AF_INET;
	_sin.sin_port = htons(4567);// host to net unsigned short
	_sin.sin_addr.S_un.S_addr = INADDR_ANY;
	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 nDddrLen = sizeof(sockaddr_in);
	SOCKET _cSock = INVALID_SOCKET;

	_cSock = accept(_sock, (sockaddr*)&clientAddr, &nDddrLen);
	if (_cSock == INVALID_SOCKET)
	{
		printf("错误,接受到无效客户端socke..\n");
	}
	printf("新客户端加入:socket = %d, IP = %s\n", _cSock, inet_ntoa(clientAddr.sin_addr));

	//char _recvBuf[256] = {}; //接收数据
	while (true)
	{
		char szRecv[1024] = {};//缓冲区
		//DataHeader header = {};
		//5.接收客户端请求数据
		int nLen = recv(_cSock, szRecv, sizeof(DataHeader), 0);  //读取header
		DataHeader *header = (DataHeader*)szRecv;
		if (nLen <= 0)
		{
			printf("客户端已退出,任务结束\n");
			break;
		}
		//printf("收到命令:%d  数据长度:%d\n", header.cmd,header.dataLength);

		switch (header->cmd)
		{
		case CMD_LOGIN:
		{
			recv(_cSock, szRecv +sizeof(DataHeader), header->dataLength - sizeof(DataHeader), 0); //header重复,长度要减去header,数据指针要加上header长度,指到login
			Login *login = (Login*)szRecv;
			printf("收到命令:CMD_LOGIN  数据长度:%d ,userName:%s , passWord = %s\n", login->dataLength,login->userName,login->passWord);

			LoginResult ret;
			send(_cSock, (char*)&ret, sizeof(LoginResult), 0);

		}
		break;
		case CMD_LOGOUT:
		{
			recv(_cSock, szRecv + sizeof(DataHeader), header->dataLength - sizeof(DataHeader), 0);
			Logout *logout= (Logout*)szRecv;
			printf("收到命令:CMD_LOGIN  数据长度:%d ,userName:%s\n", logout->dataLength, logout->userName);

			LogoutResult ret;
			send(_cSock, (char*)&ret, sizeof(LogoutResult), 0);
		}
		break;
		default:
			header->cmd = CMD_ERROR;
			header->dataLength = 0;
			send(_cSock, (char*)&header, sizeof(DataHeader), 0);
			break;
		}
	}

	//6.关闭套接字socket
	closesocket(_cSock);
	WSACleanup();
	printf("已退出,任务结束\n");
	getchar();
	return 0;
}

client

// Client.cpp : 定义控制台应用程序的入口点。
//
/*
发送结构化消息
*/
#include "stdafx.h"
#include<WinSock2.h>
#include<Windows.h>
//#pragma comment(lib,"ws2_32.lib")
#include<iostream>
using namespace std;
enum CMD
{
	CMD_LOGIN,
	CMD_LOGIN_RESULT,
	CMD_LOGOUT,
	CMD_LOGOUTRESULT,
	CMD_ERROR
};
struct DataHeader
{
	short dataLength;
	short cmd;
};
struct Login :public DataHeader
{
	Login()
	{
		dataLength = sizeof(Login);
		cmd = CMD_LOGIN;
	}
	char userName[32];
	char passWord[32];
};
struct LoginResult :public DataHeader
{

	LoginResult()
	{
		dataLength = sizeof(LoginResult);
		cmd = CMD_LOGIN_RESULT;
		result = 0;
	}
	int result;
};
struct Logout :public DataHeader
{
	Logout()
	{
		dataLength = sizeof(Logout);
		cmd = CMD_LOGOUT;
	}
	char userName[32];
};
struct LogoutResult :public DataHeader
{
	LogoutResult()
	{
		dataLength = sizeof(LogoutResult);
		cmd = CMD_LOGOUTRESULT;
		result = 0;
	}
	int result;
};

int main()
{
	WORD ver = MAKEWORD(2, 2);
	WSADATA dat;
	WSAStartup(ver, &dat);  //启动windows socket 2环境
							//建立简易的tcp服务端
							//1.建立一个socket
	SOCKET _sock = socket(AF_INET, SOCK_STREAM, 0);
	if (INVALID_SOCKET == _sock)
	{
		printf("错误,建立client socket失败。。\n");
	}
	else
	{
		printf("建立client socket成功\n");
	}
	//2.连接服务器
	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 (SOCKET_ERROR == ret)
	{
		printf("错误,连接socket失败。。\n");
	}
	else
	{
		printf("连接socket成功\n");
	}

	while (true)
	{
		//3.输入请求命令
		char cmdBuf[256] = {};
		scanf("%s", cmdBuf);
		//4.处理数据请求
		if (0 == strcmp(cmdBuf, "exit"))
		{
			printf("收到退出命令,任务结束\n");
			break;
		}
		else if(0 == strcmp(cmdBuf, "login"))
		{
			//5.向服务器发送请求命令
			Login login;
			strcpy(login.userName,"gk1314");
			strcpy(login.passWord,"10203453");
			send(_sock, (const char*)&login, sizeof(login), 0);

			//接受服务器数据
			LoginResult loginRet = {};
			recv(_sock, (char*)&loginRet, sizeof(loginRet), 0);
			printf("LoginResult = %d\n", loginRet.result);
		}
		else if (0 == strcmp(cmdBuf, "logout"))
		{
			//5.向服务器发送请求命令
			Logout logout;
			strcpy(logout.userName, "gk1314");
			send(_sock, (const char*)&logout, sizeof(logout), 0);

			//6.接受服务器数据
			LogoutResult logoutRet = {};
			recv(_sock, (char*)&logoutRet, sizeof(logoutRet), 0);
			printf("LoginResult = %d\n", logoutRet.result);
		}
		else
		{
			printf("收到不支持命令,重新输入\n");
		
		}
	}


	//7.结束套接字
	closesocket(_sock);

	WSACleanup();
	printf("退出命令,任务结束\n");
	getchar();
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值