一、服务端
在之前的解决方案下,新建控制台空项目,命名为EasyTcpSever,配置项目属性<在前一篇博客中有介绍 配置方法类似>
新建server.cpp,黏贴以下代码:
#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include <Windows.h>
#include <WinSock2.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib")
enum CMD
{
CMD_NEW_USER,
CMD_LOGIN,
CMD_LOGIN_RST,
CMD_LOGOUT,
CMD_LOGOUT_RST,
};
struct DataHeader
{
short dataLth;
CMD cmd;
};
struct NewUsr : public DataHeader
{
NewUsr()
{
dataLth = sizeof(NewUsr);
cmd = CMD_NEW_USER;
}
};
struct Login : public DataHeader
{
Login()
{
dataLth = sizeof(Login);
cmd = CMD_LOGIN;
strcpy(usrName, "小明");
strcpy(passWord, "小明密码");
}
char usrName[32];
char passWord[32];
};
struct LoginRst : public DataHeader
{
LoginRst()
{
dataLth = sizeof(LoginRst);
cmd = CMD_LOGIN_RST;
rst = 1;
}
int rst;
};
struct Logout : public DataHeader
{
Logout()
{
dataLth = sizeof(Logout);
cmd = CMD_LOGOUT;
strcpy(usrName, "小明");
}
char usrName[32];
};
struct LogoutRst : public DataHeader
{
int rst;
LogoutRst()
{
dataLth = sizeof(LogoutRst);
cmd = CMD_LOGOUT_RST;
rst = -1;
}
};
int main()
{
WORD ver = MAKEWORD(2, 2);
WSADATA dat;
WSAStartup(ver, &dat);
//1建立套接字
SOCKET _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//2绑定用于接受客户端链接的网络端口
sockaddr_in _sin = {};
_sin.sin_family = AF_INET;
_sin.sin_port = htons(4567);//主机转网络字节地址
_sin.sin_addr.S_un.S_addr = INADDR_ANY; //接收
if (bind(_sock, (sockaddr*)&_sin, sizeof(_sin)) == SOCKET_ERROR)
{
printf("绑定网络端口失败!");
}
else{
printf("绑定网络端口成功!");
}
//3 监听端口
if (SOCKET_ERROR == listen(_sock, 5))
{
printf("监听失败!");
}
else
{
printf("监听成功!");
}
//4 accept 等待客户端链接
sockaddr_in _clientAddr = {};
int nAddrLen = sizeof(sockaddr_in);
SOCKET _cSock = INVALID_SOCKET;
_cSock = accept(_sock, (sockaddr*)&_clientAddr, &nAddrLen);
if (_cSock == INVALID_SOCKET)
{
printf("当前是无效客户端套接字!!!\n");
}
//printf("接收到新客户端加入:IP = %s!!!\n", inet_ntoa(_clientAddr.sin_addr));
while (true)
{
//接收报头
DataHeader recvDH;
int nLen = recv(_cSock, (char*)&recvDH, sizeof(recvDH), 0);
if (nLen <= 0)
{
printf("客户端已退出!!!\n");
break;
}
//处理请求
switch(recvDH.cmd)
{
case CMD_NEW_USER:
{
printf("命令CMD_NEW_USER,加入新的客户端!!!\n");
}
break;
case CMD_LOGIN:
{
printf("命令 CMD_LOGIN,客户端!!登录!\n");
Login login;
int ret = recv(_cSock, (char*)(&login + sizeof(DataHeader)), sizeof(Login)-sizeof(DataHeader),0);
printf("用户姓名:%s 用户密码:%s\n", login.usrName, login.passWord);
}
break;
case CMD_LOGOUT:
{
printf("命令 CMD_LOGOUT,客户端登出!!!\n");
Logout logout;
int ret = recv(_cSock, (char*)(&logout + sizeof(DataHeader)), sizeof(Logout) - sizeof(DataHeader), 0);
printf("用户姓名:%s", logout.usrName);
}
break;
case CMD_LOGIN_RST:
{
printf("命令 CMD_LOGIN_RST,客户端登录结果!!!\n");
LoginRst loginrst;
int ret = recv(_cSock, (char*)(&loginrst + sizeof(DataHeader)), sizeof(loginrst) - sizeof(DataHeader), 0);
printf("登录结果:%d\n", loginrst.rst);
}
break;
case CMD_LOGOUT_RST:
{
printf("命令CMD_LOGOUT_RST,客户端登出结果!!!\n");
LoginRst logoutrst;
int ret = recv(_cSock, (char*)(&logoutrst + sizeof(DataHeader)), sizeof(logoutrst) - sizeof(DataHeader), 0);
printf("登出结果:%d\n", logoutrst.rst);
}
break;
}
}
//6 关闭套接字
closesocket(_sock);
WSACleanup();
getchar();
return 0;
}
二、客户端
在之前的解决方案下,新建控制台空项目,命名为EasyTcpSever,配置项目属性<在前一篇博客中有介绍 配置方法类似>
新建client.cpp,黏贴以下代码:
#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include <Windows.h>
#include <WinSock2.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib")
enum CMD
{
CMD_NEW_USER,
CMD_LOGIN,
CMD_LOGIN_RST,
CMD_LOGOUT,
CMD_LOGOUT_RST,
};
struct DataHeader
{
short dataLth;
CMD cmd;
};
struct NewUsr : public DataHeader
{
NewUsr()
{
dataLth = sizeof(NewUsr);
cmd = CMD_NEW_USER;
}
};
struct Login : public DataHeader
{
Login()
{
dataLth = sizeof(Login);
cmd = CMD_LOGIN;
strcpy(usrName, "小明");
strcpy(passWord, "小明密码");
}
char usrName[32];
char passWord[32];
};
struct LoginRst : public DataHeader
{
LoginRst()
{
dataLth = sizeof(LoginRst);
cmd = CMD_LOGIN_RST;
rst = 1;
}
int rst;
};
struct Logout : public DataHeader
{
Logout()
{
dataLth = sizeof(Logout);
cmd = CMD_LOGOUT;
strcpy(usrName, "小明");
}
char usrName[32];
};
struct LogoutRst : public DataHeader
{
int rst;
LogoutRst()
{
dataLth = sizeof(LogoutRst);
cmd = CMD_LOGOUT_RST;
rst = 1;
}
};
int main()
{
WORD ver = MAKEWORD(2, 2);
WSADATA dat;
WSAStartup(ver, &dat);
//1 建立套接字
SOCKET _sock = socket(AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET == _sock)
{
printf("客户端创建套接字失败!!!\n");
}
else
{
printf("客户端创建套接字成功!!!\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("服务器连接失败!!!\n");
}
else
{
printf("服务器连接成功!!!\n");
}
while (true)
{
char scanfBuf[256] = {};
scanf("%s", scanfBuf);
if (0 == strcmp(scanfBuf, "exit"))
{
printf("退出客户端!!!\n");
break;
}
else if (0 == strcmp(scanfBuf, "login"))
{
Login login;
send(_sock, (char*)&login, sizeof(login), 0);
}
else if (0 == strcmp(scanfBuf, "logout"))
{
Logout logout;
send(_sock, (char*)&logout, sizeof(logout), 0);
}
else if (0 == strcmp(scanfBuf, "loginrst"))
{
LoginRst loginrst;
send(_sock, (char*)&loginrst, sizeof(loginrst), 0);
}
else if (0 == strcmp(scanfBuf, "logoutrst"))
{
LogoutRst logoutrst;
send(_sock, (char*)&logoutrst, sizeof(logoutrst), 0);
}
else
{
printf("输入的请求不合法!!!\n");
}
}
//7关闭套接字
closesocket(_sock);
WSACleanup();
getchar();
return 0;
}