结构化数据传输
server
// ctrl + k + c
// Ctrl + K+ U
#define WIN32_LEAN_AND_MEAN
#include <iostream>
#include <Windows.h>
#include <WinSock2.h>
using namespace std;
//加入静态连接库
#pragma comment(lib,"ws2_32.lib")
//输出目录 $(SolutionDir)..bin/$(Platform)/$(Configuration)\
//中间目录 $(SolutionDir)../temp/$(Platform)/$(Configuration)/$(ProjectName)\
struct DataPackage {
int age;
char name[32];
//在客户端声明时也要保持该格式,字节对齐
};
int main()
{
//启动windows socket 2.x环境
WORD ver = MAKEWORD(2, 2);
WSADATA dat;
WSAStartup(ver, &dat);
//---------------------------
//TCP 服务端
//启动windows scoket编程环境
//1.建立一个socket
SOCKET _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//ipv4 数据流 TCP
//2.绑定接受客户端连接的端口号bind
sockaddr_in _sin = {};//
_sin.sin_family = AF_INET;//网络类型 ipv4
_sin.sin_port = htons(4567);// host to net unsigned short 端口号 主机数据转换到网络数据,无符号数据类型
_sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");// 服务器的ip地址
//当不知道自己的本机ip地址时可以写为 INADDR_ANY
if (bind(_sock, (sockaddr*)&_sin, sizeof(_sin)) == SOCKET_ERROR)
{
cout << "绑定用于接收客户端连接的网络端口失败" << endl;
}
else {
cout << "绑定网络端口成功..." << endl;
}//网络端口是否被占用
//3.监听网络端口listen
if (listen(_sock, 5) == SOCKET_ERROR)//等待连接的队列的长度
{
cout << "监听网络端口失败..." << endl;
}
else {
cout << "监听网络端口成功..." << endl;
}
//4.等待接受客户端连接accept
sockaddr_in clientAddr = {};//客户端的地址和端口
int nAddrLen = sizeof(sockaddr_in);
SOCKET _cSock = INVALID_SOCKET;
_cSock = accept(_sock, (sockaddr *)&clientAddr, &nAddrLen);
if (_cSock == INVALID_SOCKET)
{
cout << "错误,接收到无效客户端SOCKET..." << endl;
}
else
{
cout << "接收数据客户端有效..." << endl;
}
cout << "新客户端加入:socket = " << _cSock << ", IP = " << inet_ntoa(clientAddr.sin_addr) /*转换为 字符串 刻度的字符串数字*/ << endl;
char _recvBuf[128] = {};//接收缓存区
while (true)
{
//5.接收客户端的请求数据
int nLen = recv(_cSock, _recvBuf, 128, 0);
if (nLen <= 0)
{
cout << "客户端已退出,任务结束" << endl;
break;
}
cout << "收到命令:" << _recvBuf << endl;
//6.处理请求
if (strcmp(_recvBuf, "getInfo") == 0) {
//7.向客户端发送一条数据send
DataPackage dp = {80,"张国荣"};
send(_cSock, (const char*)&dp, sizeof(DataPackage), 0);//strlen(msgBuf) + 1 将结尾符一并发送过去
}
//if (strcmp(_recvBuf, "getName") == 0) {
// char msgBuf[] = "Xiao Qiang!";
// //7.向客户端发送一条数据send
// send(_cSock, msgBuf, strlen(msgBuf) + 1, 0);//strlen(msgBuf) + 1 将结尾符一并发送过去
//}
//else if (strcmp(_recvBuf, "getAge") == 0) {
// char msgBuf[] = "18";
// send(_cSock, msgBuf, strlen(msgBuf) + 1, 0);//strlen(msgBuf) + 1 将结尾符一并发送过去
//}
else {
char msgBuf[] = "hello ,I'm server!";
send(_cSock, msgBuf, strlen(msgBuf) + 1, 0);//strlen(msgBuf) + 1 将结尾符一并发送过去
}
}
//8.关闭socket closesocket
closesocket(_sock);
//----------------------------
//清除windows socket环境
WSACleanup();
getchar();
return 0;
}
client
#define WIN32_LEAN_AND_MEAN
#include <iostream>
#include <Windows.h>
#include <WinSock2.h>
using namespace std;
//加入静态连接库
#pragma comment(lib,"ws2_32.lib")
//输出目录 $(SolutionDir)..bin/$(Platform)/$(Configuration)\
//中间目录 $(SolutionDir)../temp/$(Platform)/$(Configuration)/$(ProjectName)\
struct DataPackage {
int age;
char name[32];
//在客户端声明时也要保持该格式,字节对齐
};
int main()
{
//启动windows socket 2.x环境
WORD ver = MAKEWORD(2, 2);
WSADATA dat;
WSAStartup(ver, &dat);
//-----------------------------
//TCP客户端
//1.建立一个socket
SOCKET _sock = socket(AF_INET, SOCK_STREAM, 0);
if (_sock == INVALID_SOCKET)
{
cout << "连接服务器失败..." << endl;
}
else {
cout << "连接服务器成功.." << endl;
}
//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)
{
cout << "连接服务器失败" << endl;
}
else {
cout << "连接服务器成功" << endl;
}
while (true)
{
//3.输入请求命令
char cmdBuf[128] = {};
//cin >> cmdBuf;
scanf("%s", cmdBuf);
//4.处理请求
if (strcmp(cmdBuf, "exit") == 0) {
cout << "已退出客户端,任务结束!" << endl;
break;
}
else {
//5.把命令发送给服务端
send(_sock, cmdBuf, strlen(cmdBuf) + 1, 0);
}
//6.接受服务器信息recv
char recBuf[256] = {};//创建数据缓冲区
int nlen = recv(_sock, recBuf, 256, 0);
if (nlen > 0) {
DataPackage *dp = (DataPackage *)recBuf;
cout << "接受的数据为:age: " << dp->age << ", name: "<< dp->name << endl;
}
else {
cout << "接受数据失败" << endl;
}
}
//7.关闭socket closesocket
closesocket(_sock);
//----------------------------
//清除windows socket环境
WSACleanup();
getchar();
return 0;
}
以上命名格式输入错误的时,强制类型转换带来的不安全;
2. 网络数据报文
* 报文有两个部分,包头和包体,是网络消息的基本单元;
* 包头:描述本次消息包的大小,描述数据的作用;
*包体:数据;
2.1 server
// ctrl + k + c
// Ctrl + K+ U
#define WIN32_LEAN_AND_MEAN
#include <iostream>
#include <Windows.h>
#include <WinSock2.h>
using namespace std;
//加入静态连接库
#pragma comment(lib,"ws2_32.lib")
//输出目录 $(SolutionDir)..bin/$(Platform)/$(Configuration)\
//中间目录 $(SolutionDir)../temp/$(Platform)/$(Configuration)/$(ProjectName)\
enum CMD{
CMD_LOGIN,
CMD_LOGOUT,
LOG_ERROR
};
//消息头
struct DataHeader{
short dataLength;//数据长度
short cmd;//
};
//DataPackage
struct Login{
char userName[32];
char PassWord[32];
};
struct LoginResult {
int result;
};
struct LogOut
{
char userName[32];
};
struct LogOutResult {
int result;
};
int main()
{
//启动windows socket 2.x环境
WORD ver = MAKEWORD(2, 2);
WSADATA dat;
WSAStartup(ver, &dat);
//---------------------------
//TCP 服务端
//启动windows scoket编程环境
//1.建立一个socket
SOCKET _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//ipv4 数据流 TCP
//2.绑定接受客户端连接的端口号bind
sockaddr_in _sin = {};//
_sin.sin_family = AF_INET;//网络类型 ipv4
_sin.sin_port = htons(4567);// host to net unsigned short 端口号 主机数据转换到网络数据,无符号数据类型
_sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");// 服务器的ip地址
//当不知道自己的本机ip地址时可以写为 INADDR_ANY
if (bind(_sock, (sockaddr*)&_sin, sizeof(_sin)) == SOCKET_ERROR)
{
cout << "绑定用于接收客户端连接的网络端口失败" << endl;
}
else {
cout << "绑定网络端口成功..." << endl;
}//网络端口是否被占用
//3.监听网络端口listen
if (listen(_sock, 5) == SOCKET_ERROR)//等待连接的队列的长度
{
cout << "监听网络端口失败..." << endl;
}
else {
cout << "监听网络端口成功..." << endl;
}
//4.等待接受客户端连接accept
sockaddr_in clientAddr = {};//客户端的地址和端口
int nAddrLen = sizeof(sockaddr_in);
SOCKET _cSock = INVALID_SOCKET;
_cSock = accept(_sock, (sockaddr *)&clientAddr, &nAddrLen);
if (_cSock == INVALID_SOCKET)
{
cout << "错误,接收到无效客户端SOCKET..." << endl;
}
else
{
cout << "接收数据客户端有效..." << endl;
}
cout << "新客户端加入: socket = " << _cSock << ", IP = " << inet_ntoa(clientAddr.sin_addr) /*转换为 字符串 刻度的字符串数字*/ << endl;
while (true)
{
DataHeader header = {};
//5.接收客户端的请求数据
int nLen = recv(_cSock,(char*)&header, sizeof(DataHeader), 0);
if (nLen <= 0)
{
cout << "客户端已退出,任务结束" << endl;
break;
}
cout << "收到命令:数据命令:" << header.cmd<< ",数据长度:"<< header.dataLength << endl;
//6.处理请求
switch (header.cmd) {
case CMD_LOGIN:
{
Login login = {};
recv(_cSock, (char*)&login, sizeof(Login), 0);
LoginResult ret = {1};
//忽略判断用户名和密码是否正确
send(_cSock, (char*)&header, sizeof(DataHeader), 0);
send(_cSock, (char*)&ret, sizeof(LoginResult), 0);
}
break;
case CMD_LOGOUT:
{
LogOut logOut = {};
recv(_cSock, (char*)&logOut, sizeof(LogOut), 0);
LogOutResult ret = { 1 };
//忽略判断用户名和密码是否正确
send(_cSock, (char*)&header, sizeof(DataHeader), 0);
send(_cSock, (char*)&ret, sizeof(LogOutResult), 0);
}
break;
default:
{
header.cmd = LOG_ERROR;
header.dataLength = 0;
send(_cSock, (char *)&header, sizeof(header), 0);//strlen(msgBuf) + 1 将结尾符一并发送过去
break;
}
}
}
//8.关闭socket closesocket
closesocket(_sock);
//----------------------------
//清除windows socket环境
WSACleanup();
getchar();
return 0;
}
2.2 client
#define WIN32_LEAN_AND_MEAN
#include <iostream>
#include <Windows.h>
#include <WinSock2.h>
using namespace std;
//加入静态连接库
#pragma comment(lib,"ws2_32.lib")
//输出目录 $(SolutionDir)..bin/$(Platform)/$(Configuration)\
//中间目录 $(SolutionDir)../temp/$(Platform)/$(Configuration)/$(ProjectName)\
enum CMD {
CMD_LOGIN,
CMD_LOGOUT,
LOG_ERROR
};
//消息头
struct DataHeader {
short dataLength;//数据长度
short cmd;//
};
//DataPackage
struct Login {
char userName[32];
char PassWord[32];
};
struct LoginResult {
int result;
};
struct LogOut
{
char userName[32];
};
struct LogOutResult {
int result;
};
int main()
{
//启动windows socket 2.x环境
WORD ver = MAKEWORD(2, 2);
WSADATA dat;
WSAStartup(ver, &dat);
//-----------------------------
//TCP客户端
//1.建立一个socket
SOCKET _sock = socket(AF_INET, SOCK_STREAM, 0);
if (_sock == INVALID_SOCKET)
{
cout << "连接服务器失败..." << endl;
}
else {
cout << "连接服务器成功.." << endl;
}
//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)
{
cout << "连接服务器失败" << endl;
}
else {
cout << "连接服务器成功" << endl;
}
while (true)
{
//3.输入请求命令
char cmdBuf[128] = {};
//cin >> cmdBuf;
scanf("%s", cmdBuf);
//4.处理请求
//5.把命令发送给服务端
if (strcmp(cmdBuf, "exit") == 0) {
cout << "已退出客户端,任务结束!" << endl;
break;
}
else if (strcmp(cmdBuf, "login") == 0) {
Login login = { "jmm","lovely" };
DataHeader dh = {sizeof(login),CMD_LOGIN };
//5.把命令发送给服务端
send(_sock, (char*)&dh, sizeof(dh), 0);
send(_sock, (char *)&login, sizeof(login), 0);
// 接受服务器返回的数据
DataHeader retHeader = {};
LoginResult loginRet = {};
recv(_sock, (char*)&retHeader, sizeof(retHeader), 0);
recv(_sock, (char*)&loginRet, sizeof(loginRet), 0);
cout << "LoginResult: " << loginRet.result << endl;
}
else if (strcmp(cmdBuf, "logout") == 0) {
LogOut logout = {};
DataHeader dh = {sizeof(logout),CMD_LOGOUT };
//5.把命令发送给服务端
send(_sock, (char *)&dh, sizeof(dh), 0);
send(_sock, (char *)&logout, sizeof(logout), 0);
// 接受服务器返回的数据
DataHeader retHeader = {};
LoginResult logoutRet = {};
recv(_sock, (char*)&retHeader, sizeof(retHeader), 0);
recv(_sock, (char*)&logoutRet, sizeof(logoutRet), 0);
cout << "LogOutResult: " << logoutRet.result << endl;
}
else {
cout << "不支持该命令,请重新输入!" << endl;
}
}
//7.关闭socket closesocket
closesocket(_sock);
//----------------------------
//清除windows socket环境
WSACleanup();
getchar();
return 0;
}