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