一、服务器端代码 -使用前一篇博客中的代码-上一篇
新建空的控制台项目 新建server.cpp,将上一篇博文中的服务端黏贴进去
二、客户端代码 - 使用前一篇博客中的代码-上一篇
客户端的旧代码是上一篇博客中的client.cpp代码,现在对它进行封装
新建空的控制台项目 添加新建头文件,MessageHeader.hpp,代码如下:
#ifndef _MESSAGEHEADER_HPP
#define _MESSAGEHEADER_HPP
enum CMD
{
CMD_NEW_USER_JOIN,
CMD_LOGIN,
CMD_LOGIN_RST,
CMD_LOGOUT,
CMD_LOGOUT_RST,
};
struct DataHeader
{
short dataLth;
CMD cmd;
};
struct Login : public DataHeader
{
Login()
{
dataLth = sizeof(Login);
cmd = CMD_LOGIN;
}
char usrName[32];
char passWord[32];
};
struct LoginRst : public DataHeader
{
LoginRst()
{
dataLth = sizeof(LoginRst);
cmd = CMD_LOGIN_RST;
}
int rst;
};
struct Logout : public DataHeader
{
Logout()
{
dataLth = sizeof(Logout);
cmd = CMD_LOGOUT;
}
char usrName[32];
};
struct LogoutRst : public DataHeader
{
LogoutRst()
{
dataLth = sizeof(LogoutRst);
cmd = CMD_LOGOUT_RST;
}
int rst;
};
struct NewUserJoin : public DataHeader
{
NewUserJoin()
{
dataLth = sizeof(NewUserJoin);
cmd = CMD_NEW_USER_JOIN;
}
int sock;
};
#endif//END _MESSAGEHEADER_HPP
添加新建头文件,EasyTcpClient.hpp,代码如下
#ifndef _EASYTCPCLIENT_HPP_
#define _EASYTCPCLIENT_HPP_
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include<windows.h>
#include<WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
#else
#include<unistd.h> //uni std
#include<arpa/inet.h>
#include<string.h>
#define SOCKET int
#define INVALID_SOCKET (SOCKET)(~0)
#define SOCKET_ERROR (-1)
#endif //end define _win32
#include <stdio.h>
#include "MessageHeader.hpp"
class EasyTcpClient
{
SOCKET _sock;
public:
EasyTcpClient()
{
_sock = INVALID_SOCKET;
}
virtual ~EasyTcpClient()
{
Close();
}
//初始化socket
void InitSocket()
{
#ifdef _WIN32
//启动Windows socket 2.x环境
WORD ver = MAKEWORD(2, 2);
WSADATA dat;
WSAStartup(ver, &dat);
#endif
//初始化_sock 如果含有旧链接,关闭旧链接 之后再建立socket
if (INVALID_SOCKET != _sock)
{
printf("<socket=%d>关闭旧连接...\n", _sock);
Close();
}
_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == _sock)
{
printf("错误,建立Socket失败...\n");
}
else {
printf("建立Socket成功...\n");
}
}
//连接服务器
int Connect(char* ip, unsigned short port)
{
//如果socket没有被创建,初始化socket
if (INVALID_SOCKET == _sock)
{
InitSocket();
}
// 2 连接服务器 connect
sockaddr_in _sin = {};
_sin.sin_family = AF_INET;
_sin.sin_port = htons(port);
#ifdef _WIN32
_sin.sin_addr.S_un.S_addr = inet_addr(ip);
#else
_sin.sin_addr.s_addr = inet_addr(ip);
#endif
int ret = connect(_sock, (sockaddr*)&_sin, sizeof(sockaddr_in));
if (SOCKET_ERROR == ret)
{
printf("错误,连接服务器失败...\n");
}
else {
printf("连接服务器成功...\n");
}
return ret;
}
//关闭套节字closesocket
void Close()
{
//如果是有效的_sock
if (_sock != INVALID_SOCKET)
{
#ifdef _WIN32
closesocket(_sock);
//清除Windows socket环境
WSACleanup();
#else
close(_sock);
#endif
_sock = INVALID_SOCKET;
}
}
int processor(SOCKET _cSock)
{
printf("当前<客户端>套接字%d,processor start.... \n", (int)_cSock);
char szRecv[4096] = {};
// 5 接收客户端数据
int nLen = (int)recv(_cSock, szRecv, sizeof(DataHeader), 0);
DataHeader* header = (DataHeader*)szRecv;
if (nLen <= 0)
{
printf("客户端退出!\n 当前<客户端>套接字%d,processor end....\n ", (int)_cSock);
return -1;
}
//处理请求
switch (header->cmd)
{
case CMD_LOGIN_RST:
{
printf("命令 CMD_LOGIN_RST,服务器发送登入消息!\n");
recv(_cSock, szRecv + sizeof(DataHeader), header->dataLth - sizeof(DataHeader), 0);
LoginRst* loginrst = (LoginRst*)szRecv;
printf("服务器发送来的登入消息:%d\n", loginrst->rst);
}
break;
case CMD_LOGOUT_RST:
{
printf("命令 CMD_LOGOUT_RST,服务端发来登出消息!\n");
recv(_cSock, szRecv + sizeof(DataHeader), sizeof(Logout) - sizeof(DataHeader), 0);
LogoutRst *logoutrst = (LogoutRst*)szRecv;
printf("服务器发送来的登出消息是:%d\n", logoutrst->rst);
}
break;
case CMD_NEW_USER_JOIN:
{
printf("命令 CMD_NEW_USER_JION,服务器进行群发消息-新用户进入\n");
recv(_cSock, szRecv + sizeof(DataHeader), sizeof(NewUserJoin) - sizeof(DataHeader), 0);
NewUserJoin *newuserjoin = (NewUserJoin*)szRecv;
printf("新用户的id是:%d", newuserjoin->sock);
}
break;
}
printf("当前<客户端>套接字%d,processor end.... \n", (int)_cSock);
return 0;
}
//处理网络消息
bool OnRun()
{
if (isRun())
{
fd_set fdReads;//建立可读集合
FD_ZERO(&fdReads);//清空可读集合
FD_SET(_sock, &fdReads);//将_sock放入可读集合中
timeval t = { 1,0 };//设置延迟
int ret = select(_sock + 1, &fdReads, 0, 0, &t);//选择模型启动
if (ret < 0)
{
printf("<socket=%d>select任务结束,选择模型启动未成功\n", _sock);
return false;
}
if (FD_ISSET(_sock, &fdReads))//
{
FD_CLR(_sock, &fdReads);//清空_sock
if (-1 == processor(_sock))
{
printf("<socket=%d>select任务结束,\n", _sock);
return false;
}
}
return true;
}
return false;
}
//是否工作中
bool isRun()
{
return _sock != INVALID_SOCKET;
}
//发送logout
int SendData(Logout logout)
{
if (isRun())
{
return send(_sock, (const char*)&logout, logout.dataLth, 0);
}
return SOCKET_ERROR;
}
//发送login
int SendData(Login login)
{
if (isRun())
{
return send(_sock, (const char*)&login, login.dataLth, 0);
}
return SOCKET_ERROR;
}
private:
};
#endif // _EASYTCPCLIENT_HPP_
添加新建client.cpp文件,代码如下:
#include "EasyTcpClient.hpp"
int main()
{
EasyTcpClient client;
//client init
client.InitSocket();
//client connect
char szConnet[] = "127.0.0.1";
client.Connect(szConnet,4567);
//
while (true)
{
//运行程序接收
if (false == client.OnRun())
{
break;
}
Sleep(10000);
Login login;
strcpy(login.usrName, "<kehu-login>");
strcpy(login.passWord, "<kehu-login-password>");
Logout logout;
strcpy(logout.usrName, "<kehu-logout>");
client.SendData(login);
client.SendData(logout);
}
//关闭client
client.Close();
getchar();
return 0;
}