datetime:2022/12/29 15:46
author:nzb
多线程网络服务端
server.cpp
#include "_freecplus.h"
void *pthmain(void *arg); // 线程主函数。
vector<long> vpthid; // 存放线程id的容器。
void mainexit(int sig); // 信号2和15的处理函数。
void pthmainexit(void *arg); // 线程清理函数。
CLogFile logfile; // 服务程序的运行日志。
CTcpServer TcpServer; // 创建服务端对象。
// 处理业务的主函数。
bool _main(const char *strrecvbuffer, char *strsendbuffer);
// 心跳报文。
bool biz000(const char *strrecvbuffer, char *strsendbuffer);
// 身份验证业务处理函数。
bool biz001(const char *strrecvbuffer, char *strsendbuffer);
// 查询余客业务处理函数。
bool biz002(const char *strrecvbuffer, char *strsendbuffer);
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("Using:./mtserver_biz port logfile\nExample:./mtserver_biz 5005 /tmp/mtserver_biz.log\n\n");
return -1;
}
// 关闭全部的信号
for (int ii = 0; ii < 100; ii++) signal(ii, SIG_IGN);
// 打开日志文件。
if (logfile.Open(argv[2], "a+") == false) {
printf("logfile.Open(%s) failed.\n", argv[2]);
return -1;
}
// 设置信号,在shell状态下可用 "kill + 进程号" 正常终止些进程
// 但请不要用 "kill -9 +进程号" 强行终止
signal(SIGINT, mainexit);
signal(SIGTERM, mainexit);
if (TcpServer.InitServer(atoi(argv[1])) == false) // 初始化TcpServer的通信端口。
{
logfile.Write("TcpServer.InitServer(%s) failed.\n", argv[1]);
return -1;
}
while (true) {
if (TcpServer.Accept() == false) // 等待客户端连接。
{
logfile.Write("TcpServer.Accept() failed.\n");
continue;
}
logfile.Write("客户端(%s)已连接。\n", TcpServer.GetIP());
pthread_t pthid;
if (pthread_create(&pthid, NULL, pthmain, (void *) (long) TcpServer.m_connfd) != 0) {
logfile.Write("pthread_create failed.\n");
return -1;
}
vpthid.push_back(pthid); // 把线程id保存到vpthid容器中。
}
return 0;
}
void *pthmain(void *arg) {
pthread_cleanup_push(pthmainexit, arg); // 设置线程清理函数。
pthread_detach(pthread_self()); // 分离线程。
pthread_setcanceltype(PTHREAD_CANCEL_DISABLE, NULL); // 设置取消方式为立即取消。
int sockfd = (int) (long) arg; // 与客户端的socket连接。
int ibuflen = 0;
char strrecvbuffer[1024], strsendbuffer[1024]; // 存放数据的缓冲区。
while (true) {
memset(strrecvbuffer, 0, sizeof(strrecvbuffer));
memset(strsendbuffer, 0, sizeof(strsendbuffer));
if (TcpRead(sockfd, strrecvbuffer, &ibuflen, 50) == false) break; // 接收客户端发过来的请求报文。
logfile.Write("接收:%s\n", strrecvbuffer);
// 处理业务的主函数。
if (_main(strrecvbuffer, strsendbuffer) == false) break;
logfile.Write("发送:%s\n", strsendbuffer);
if (TcpWrite(sockfd, strsendbuffer) == false) break; // 向客户端回应报文。
}
pthread_cleanup_pop(1);
pthread_exit(0);
}
// 信号2和15的处理函数。
void mainexit(int sig) {
logfile.Write("mainexit begin.\n");
// 关闭监听的socket。
TcpServer.CloseListen();
// 取消全部的线程。
for (int ii = 0; ii < vpthid.size(); ii++) {
logfile.Write("cancel %ld\n", vpthid[ii]);
pthread_cancel(vpthid[ii]);
}
logfile.Write("mainexit end.\n");
exit(0);
}
// 线程清理函数。
void pthmainexit(void *arg) {
logfile.Write("pthmainexit begin.\n");
// 关闭与客户端的socket。
close((int) (long) arg);
// 从vpthid中删除本线程的id。
for (int ii = 0; ii < vpthid.size(); ii++) {
if (vpthid[ii] == pthread_self()) {
vpthid.erase(vpthid.begin() + ii);
}
}
logfile.Write("pthmainexit end.\n");
}
bool _main(const char *strrecvbuffer, char *strsendbuffer) // 处理业务的主函数。
{
int ibizcode = -1;
GetXMLBuffer(strrecvbuffer, "bizcode", &ibizcode);
switch (ibizcode) {
case 0: // 心跳
biz000(strrecvbuffer, strsendbuffer);
break;
case 1: // 身份验证。
biz001(strrecvbuffer, strsendbuffer);
break;
case 2: // 查询余额。
biz002(strrecvbuffer, strsendbuffer);
break;
default:
logfile.Write("非法报文:%s\n", strrecvbuffer);
return false;
}
return true;
}
// 身份验证业务处理函数。
bool biz001(const char *strrecvbuffer, char *strsendbuffer) {
char username[51], password[51];
memset(username, 0, sizeof(username));
memset(password, 0, sizeof(password));
GetXMLBuffer(strrecvbuffer, "username", username, 50);
GetXMLBuffer(strrecvbuffer, "password", password, 50);
if ((strcmp(username, "wucz") == 0) && (strcmp(password, "p@ssw0rd") == 0))
sprintf(strsendbuffer, "<retcode>0</retcode><message>成功。</message>");
else
sprintf(strsendbuffer, "<retcode>-1</retcode><message>用户名或密码不正确。</message>");
return true;
}
// 查询余额业务处理函数。
bool biz002(const char *strrecvbuffer, char *strsendbuffer) {
char cardid[51];
memset(cardid, 0, sizeof(cardid));
GetXMLBuffer(strrecvbuffer, "cardid", cardid, 50);
if (strcmp(cardid, "62620000000001") == 0)
sprintf(strsendbuffer, "<retcode>0</retcode><message>成功。</message><ye>100.50</ye>");
else
sprintf(strsendbuffer, "<retcode>-1</retcode><message>卡号不存在。</message>");
return true;
}
// 心跳报文
bool biz000(const char *strrecvbuffer, char *strsendbuffer) {
sprintf(strsendbuffer, "<retcode>0</retcode><message>成功。</message>");
return true;
}
client.cpp
#include "_freecplus.h"
CTcpClient TcpClient; // 创建客户端的对象。
bool biz000(); // 发送心跳报文。
bool biz001(); // 身份验证
bool biz002(); // 余额查询
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("Using:./demo47_biz ip port\nExample:./demo47_biz 172.21.0.3 5005\n\n");
return -1;
}
if (TcpClient.ConnectToServer(argv[1], atoi(argv[2])) == false) // 向服务端发起连接请求。
{
printf("TcpClient.ConnectToServer(\"%s\",%s) failed.\n", argv[1], argv[2]);
return -1;
}
/*
// 身份验证
if (biz001()==false)
{
printf("biz001() failed.\n"); return -1;
}
sleep(10);
biz002(); // 余额查询
sleep(5);
biz002(); // 余额查询
*/
for (int ii = 0; ii < 10; ii++) {
if (biz000() == false) break;
sleep(10);
}
// 程序直接退出,析构函数会释放资源。
}
// 身份验证。
bool biz001() {
char strbuffer[1024]; // 存放数据的缓冲区。
memset(strbuffer, 0, sizeof(strbuffer));
snprintf(strbuffer, 1000, "<bizcode>1</bizcode><username>wucz</username><password>p@ssw0rd</password>");
printf("发送:%s\n", strbuffer);
if (TcpClient.Write(strbuffer) == false) return false; // 向服务端发送请求报文。
memset(strbuffer, 0, sizeof(strbuffer));
if (TcpClient.Read(strbuffer, 20) == false) return false; // 接收服务端的回应报文。
printf("接收:%s\n", strbuffer);
int iretcode = -1;
GetXMLBuffer(strbuffer, "retcode", &iretcode);
if (iretcode == 0) {
printf("身份验证成功。\n");
return true;
}
printf("身份验证失败。\n");
return false;
}
// 余额查询
bool biz002() {
char strbuffer[1024]; // 存放数据的缓冲区。
memset(strbuffer, 0, sizeof(strbuffer));
snprintf(strbuffer, 1000, "<bizcode>2</bizcode><cardid>62620000000001</cardid>");
printf("发送:%s\n", strbuffer);
if (TcpClient.Write(strbuffer) == false) return false; // 向服务端发送请求报文。
memset(strbuffer, 0, sizeof(strbuffer));
if (TcpClient.Read(strbuffer, 20) == false) return false; // 接收服务端的回应报文。
printf("接收:%s\n", strbuffer);
int iretcode = -1;
GetXMLBuffer(strbuffer, "retcode", &iretcode);
if (iretcode == 0) {
printf("查询余额成功。\n");
return true;
}
printf("查询余额失败。\n");
return false;
}
bool biz000() // 发送心跳报文。
{
char strbuffer[1024]; // 存放数据的缓冲区。
memset(strbuffer, 0, sizeof(strbuffer));
snprintf(strbuffer, 1000, "<bizcode>0</bizcode>");
//printf("发送:%s\n",strbuffer);
if (TcpClient.Write(strbuffer) == false) return false; // 向服务端发送请求报文。
memset(strbuffer, 0, sizeof(strbuffer));
if (TcpClient.Read(strbuffer, 20) == false) return false; // 接收服务端的回应报文。
//printf("接收:%s\n",strbuffer);
return true;
}