Server - select网络模型优化(后续,客户端封装)

一、服务器端代码 -使用前一篇博客中的代码-上一篇


新建空的控制台项目 新建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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

莫忘输赢

莫忘输赢 - 收钱袋

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值