写在前面:前面几篇文字已经把服务器端相关的叙述了,这里再把客户端的给加上
一.client.cpp函数的实现,如下:
1.构造函数的实现,如下:
Client::Client():writable(true){
if((epfd = epoll_create(MAXEVENTS)) == -1){
exit(-1);
}
if((connfd = epoll_create(MAXEVENTS)) == -1){
exit(-1);
}
tcpfd = ::socket(AF_INET, SOCK_STREAM, 0);
udpfd = ::socket(AF_INET, SOCK_DGRAM, 0);
epevent.events = EPOLLET | EPOLLIN | EPOLLOUT;
}
2.连接函数的实现,如下:
void Client::connect(std::string host, int port){
int rc = 1;
int flags = 0;
struct sockaddr_in tcpAddr;
tcpAddr.sin_family = AF_INET;
tcpAddr.sin_port = htons(port);
tcpAddr.sin_addr.s_addr = ::inet_addr(host.c_str());
if((rc = ::connect(tcpfd, (struct sockaddr*)&tcpAddr, sizeof(struct sockaddr_in))) < 0){
printf("[Client::connect] tcp connect failed.\n");
writable = false;
rc = 1;
return;
}
if(epoll_ctl(epfd, EPOLL_CTL_ADD, tcpfd, &epevent) == -1){
printf("[Client::connect] epAdd tcp failed:%s", strerror(errno));
return;
}else{
printf("[Client::connect] epAdd tcp successfully.\n");
}
}
3.epoll事件的监听,如下:
void Client::epHandle(){
int n = -1;
n = epoll_wait(epfd, events, MAXEVENTS, 0);
for(int i=0;i if(events[i].events & (EPOLLERR | EPOLLHUP)){
printf("[Client::connHandle] epoll err.\n");
continue;
}
if(events[i].events & EPOLLOUT){
#ifdef OPEN_LOG
printf("[Client::epHandle] EPOLLOUT event happen.\n");
#endif
}
if(events[i].events & EPOLLIN){
#ifdef OPEN_LOG
printf("[Client::epHandle] EPOLLIN event happen.\n");
#endif
recvData();
}
}
}
4.登录消息的发送,如下:
int Client::sendLoginReq(){
int rc = 1;
char buf[50] = {0};
int offset = 0;
Json::Value jv;
Json::FastWriter writer;
int uri = 3;
std::string msg = "ustc";
jv["uri"] = Json::Value(uri);
jv["msg"] = Json::Value(msg);
std::string loginReq = writer.write(jv);
offset += sprintf(buf, "%04d", loginReq.size());
offset += sprintf(buf+offset, "%s", loginReq.c_str());
#ifdef OPEN_LOG
printf("[Client::sendLoginReq] loginReq size is %d\n", loginReq.size());
printf("[Client::sendLoginReq] offset is %d\n", offset);
#endif
if(writable && (rc = ::send(tcpfd, buf, offset, MSG_DONTWAIT))
!= offset && errno == EAGAIN){
printf("[Client::sendLoginReq] send EAGAIN, modify writable status.\n");
writable = false;
rc = 1;
}else{
printf("[Client::sendLoginReq] send loginReq successfully.\n");
}
return rc;
}
5.响应消息的实现,如下:
void Client::receiveLoginRes(){
printf("[Client::receiveLoginRes] handle login res.\n");
}
void Client::receivePingRes(){
printf("[Client::receivePingRes] handle ping res.\n");
}
void Client::handle(const char* pack, int length){
Json::Value v;
Json::Reader reader;
if(reader.parse(pack, v)){
int uri = v["uri"].asUInt();
std::string msg = v["msg"].asString();
switch(uri){
case PLoginRes:
receiveLoginRes();
break;
case PPingRes:
receivePingRes();
break;
default:
printf("[Client::handle] unknown uri:%d\n", uri);
break;
}
}
}
void Client::recvData(){
int lenExpected = 0;
int lenRead = 0;
int rc = 0;
char buf[BUFFERSIZE] = {0};
if(tcpfd == -1){
return;
}
if((lenRead =::recv(tcpfd, buf, 4, MSG_DONTWAIT)) != 4){
printf("[Client::receiveLoginRes] recv bytes is not equal to 4\n");
}
lenExpected = getLength(buf);
if((lenRead = ::recv(tcpfd, buf, lenExpected, MSG_DONTWAIT)) < lenExpected){
printf("[Client::receiveLoginRes] recv bytes less than expected.\n");
}
#ifdef OPEN_LOG
printf("[Client::receiveLoginRes] recv data is %s\n", buf);
#endif
handle(buf, lenExpected);
}
6.ping心跳信息的发送,如下:
void Client::sendPingReq(){
int rc = 1;
char buf[50] = {0};
int offset = 0;
Json::Value jv;
Json::FastWriter writer;
int uri = 5;
std::string msg = "linyanwen";
jv["uri"] = Json::Value(uri);
jv["msg"] = Json::Value(msg);
std::string pingReq = writer.write(jv);
#ifdef OPEN_LOG
printf("[Client::sendPingReq] pingReq size:%d\n", pingReq.size());
printf("[Client::sendPingReq] json message is %s", pingReq.c_str());
#endif
offset += sprintf(buf, "%04d", pingReq.size());
offset += sprintf(buf+offset, "%s", pingReq.c_str());
#ifdef OPEN_LOG
printf("[Client::sendPingReq] offset size:%d\n", offset);
#endif
if(writable && (rc = ::send(tcpfd, buf, offset, MSG_DONTWAIT))
!= pingReq.size() && errno == EAGAIN){
printf("[Client::sendLoginReq] send EAGAIN, modify writable status.\n");
writable = false;
rc = 1;
}else{
#ifdef OPEN_LOG
printf("[Client::sendPingReq] send pingReq successfully.\n");
#endif
}
}
说明:代码简洁明了,不再赘述
二.main.cpp函数的实现,如下:
#include
#include
#include
#include "Timer.h"
#include "client.h"
using Poco::Mutex;
Mutex mutex;
Client cli;
void ping(int){
Mutex::ScopedLock lock(mutex);
cli.sendPingReq();
}
void loop(int){
Mutex::ScopedLock lock(mutex);
cli.epHandle();
}
class loopThread:public Poco::Runnable{
virtual void run(){
printf("[loopThread:run] ~~~~~~ invoke ~~~~~\n");
while(1){
loop(1);
}
}
};
class pingThread:public Poco::Runnable{
virtual void run(){
printf("[pingThread:run] ~~~~~~ invoke ~~~~~\n");
while(1){
ping(1);
sleep(5);
}
}
};
int main(int argc, char** argv){
std::string host = "your server ip address";
int port = 9999;
//connect
cli.connect(host, port);
//ep listen
loopThread looper;
Poco::Thread listenThread("listen");
listenThread.start(looper);
//send login req
cli.sendLoginReq();
//ping
pingThread pinger;
Poco::Thread pingThread("ping");//开辟另外一个线程实现ping信息的发送
pingThread.start(pinger);
listenThread.join();
pingThread.join();
return 0;
}
三.运行结果,如下:
1.客户端运行结果:
2.服务器端运行结果:
说明:服务器端运行结果是3个客户端同时发送ping信息的结果,而客户端这里只给出其中一个的运行结果
转载请注明出处:山水间博客,http://blog.csdn.net/linyanwen99/article/details/8315899