更新时间:2017-08-13 13:35:09浏览次数:1+次
当你接受到这样一个需求,你如何来实现:
1、tcp服务端,响应和保持300+个tcp客户端连接,维护这些连接的状态;
2、当客户端有数据时,及时收下来;
3、定时向客户端发报文;
4、当有控制命令时,向指定客户端发报文;
我们来整理一下需求,整理如下:
1.实现一个TCP服务端,要保存所有TCP客户端连接,不让其断线。实现方法就可以是定时向客户端发送报文,俗称心跳报文。
2.如果收到客户端发过来的数据,要接受保存下来。
3.心跳报文的实现,就使用定时器来实现。
4.TCP服务端不仅要接受数据,还要对数据进行解析,如果发过来的是控制命令,我们需要执行命令,并返回执行结果。
这样细化之后,我们也就更好的使用编程的思路来转化。
下面是实现的效果图:
TCP服务端相必你应该知道如何实现。但是如果从最基本的socket去写,相必也是有点费劲的。所以我们这里就推荐用libuv来实现了。libuv是跨平台的网络通信库,使用很简单,核心机制就是处处回调。明白这个核心机制,后续的使用学习会有很大的帮助。
这里我早已提供了libuv的封装类,见:《libuv服务器端包装类源代码分享》。
然后我们只需要写一个使用这个类的代码就行了。我们就用控制台程序来实现。
先将这个包装类的两个文件创建好,分别是tcpServer.h和tcpServer.cpp。然后再创建一个main函数所在的文件,如m.cpp。然后在m.cpp文件里这样写:
#include <map>
#include <stdlib.h>
#include <stdio.h>
#include "tcpServer.h"
#include <vector>
using namespace std;
//服务器对象
CTcpServer srv;
typedef struct
{
char * pdata;
int data_size;
}DATA;
vector<int> g_client_list;
vector<DATA> g_data_list;
bool is_stop=false;
void recv_cb(int client_id, const char* buf, int buf_size)
{
//处理接受消息
if (buf[0]==0)//当数据最开头是0,显示所有接受的数据
{
printf("客户端%d:执行查看所有客户端发过来的消息。\n",client_id);
vector<DATA>::iterator it=g_data_list.begin();
for (int i=0;it!=g_data_list.end();++it,i++)
{
char* pdata= new char[it->data_size+2];
memset(pdata,0,it->data_size+2);
memcpy(pdata,it->pdata,it->data_size);
pdata[it->data_size+1]='\n';
pdata[it->data_size]='\r';
srv.send(client_id, (const char*)pdata, it->data_size+2);
}
return;
}
if (buf[0]==1)//当数据最开头是1,清空所有接受的数据
{
printf("客户端%d:执行清空所有客户端发过来的消息。\n",client_id);
vector<DATA>::iterator it=g_data_list.begin();
for (int i=0;it!=g_data_list.end();++it,i++)
{
delete [] it->pdata;
}
g_data_list.clear();
srv.send(client_id, (const char*)"clear finished\r\n", sizeof("clear finished\r\n"));
return;
}
if (buf[0]==2)//当数据最开头是2,要求服务器停止定期向客户端发送消息
{
printf("客户端%d:执行停止服务器定期向所有客户端发送消息。\n",client_id);
is_stop=true;
srv.send(client_id, (const char*)"stop finished\r\n", sizeof("stop finished\r\n"));
return;
}
if (buf[0]==3)//当数据最开头是3,要求服务器开始定期向客户端发送消息
{
printf("客户端%d:执行开启服务器定期向所有客户端发送消息。\n",client_id);
is_stop=false;
srv.send(client_id, (const char*)"start finished\r\n", sizeof("start finished\r\n"));
return;
}
char* pdata = new char[buf_size];
memset(pdata,0,buf_size);
memcpy(pdata,buf,buf_size);
DATA data;
data.pdata = pdata;
data.data_size = buf_size;
g_data_list.push_back(data);
return;
}
void new_conn_cb(int client_id)
{
srv.setrecvcb(client_id, recv_cb);
vector<int>::iterator it=g_client_list.begin();
bool is_exsit=false;
for (;it!=g_client_list.end();++it)
{
if(*it==client_id)
{
is_exsit=true;
break;
}
}
if (!is_exsit)
{
g_client_list.push_back(client_id);
}
}
void callback_timer(uv_timer_t *handle)
{
//定时发送消息
if (is_stop)return;
vector<int>::iterator it=g_client_list.begin();
for (;it!=g_client_list.end();++it)
{
//向所有客户端定期发送消息,维持客户端连接
int ret = srv.send(*it, (const char*)"is_alive\r\n", sizeof("is_alive\r\n"));
if (ret)
{
//发送失败,移除旧连接,客户端重新链接后会自动加入到客户端队列
g_client_list.erase(it);
it=g_client_list.begin();
}
}
}
int main(int argc, char **argv)
{
//设置连接客户端时处理的回调函数
srv.setnewconnectcb(new_conn_cb);
uv_loop_t *loop = uv_default_loop();
uv_timer_t timer_req;
uv_timer_init(loop, &timer_req);
uv_timer_start(&timer_req, callback_timer, 1000, 1000);
//启动服务器
if(!srv.Start("0.0.0.0", 6000))
{
printf("Start Server error:%s\n",srv.GetLastErrMsg());
}
printf("server return on main.\n");
}
代码里有几个主要的函数:
相关资讯