目录
一、代码重构是软件开发者最重要的软技能
我的前辈们不止一个,亦不止一次告诫我,好代码、好软件都是不断迭代优化出来的。的确,从业这些年接触或了解的所有软件项目,初始的版本都是不堪入目,但那些软件只要是有商业价值不中途夭折,一般都会持续地在重构优化中螺旋前进,最终成为不错的,看着较赏心悦目的软件工具。
不管对于何种语言的软件开发,重构都是软件其不可或缺的一部分,只是不同的团队、不同的人员对于重构都有其决策及方法,何时重构、那些要重构、如何重构、如何衡量、有那些得力工具,是否可以捕获到适合团队及个人的过程方法及规律,如何进行重构跟踪及版本兼容与管理等等。这方面大家都是见人见异,没有对错,只有是否适合自己,因此代码重构属于软技能,虽然有一定的方法论、重构建议规则,但相比语言特性、代码规范等,它更在于个人不断自我训练及自我领悟。要想提高自己的代码重构能力,最好的方法就是拿出自己曾经撰写的代码,最好是那些能运转起来的程序代码,大胆的开启您的迭代优化训练吧。
在本文中,将基于本专栏前文TCP/Socket通信开发案例源码,
c/c++开发,c++无可避免的TCP/Socket通信开发实战案例_py_free的博客-CSDN博客
来分享一些我的代码重构思路。本人在代码重构上,遵循重构是服务于项目的,因此总体来说,重构开展工作主要就是两点:
1)由大及小,模块->类->函数
2)由简及繁,基础性的、非业务的、性能指标->业务逻辑、业务展现
二、源码回顾及分析
TCP/Socket通信开发案例源码目录结构中:
1)client_IO模块和srv_IO模块其实当时设想是客户端及服务端的socket IO模块分开,但是在实际编码过程中发现重复性挺高的,需要优化;
2)关于线程类,由于windows和linux调用标准库的API不一样,因此创建了win32Thread.h/cpp和myThread.h/cpp来表述,但对于站在使用的角度来看,仅需要一个线程类,内部自行匹配操作系统才行,使用者尽量不要触碰这个层级;
3)前文也提到,在DataDef.h中,用于缓存从socket 读取数据的结构体和数据传输缓存使用的结构体大体上是一致的,前者比起后者仅缓存区域大些,多了一个add函数,其余几乎一样。
4)common目录下的主要是通用性模块,用于支撑 socket通信业务模块,从服务于项目的角度,其内部的不少功能函数是没有使用到的,其存在反而造成困惑,尤其是不是原作者的话。
5)其他等等。
#
TCP_StructData
bin #编译输出结果
client_test
client_test.exe
server_test
server_test.exe
client_IO #客户端Socket的API功能源码
MySocket.h
MySocket.cpp
MySocketClient.h
MySocketClient.cpp
MySocketRD.h
MySocketRD.cpp
MySocketWD.h
MySocketWD.cpp
client_test #客户端业务功能源码
build_win #客户端windows编辑中间文件输出目录
build_linux #客户端linux编辑中间文件输出目录
main.cpp
CMakeLists.txt #cmake配置文件
common #共同功能模块或数据结构源码
DataDef.h #结构化数据
hashmap.h #结构化数据作为容器Key实现
hashmap.cpp
Log.h #日志模块
Log.cpp
Mutex.h #互斥锁
Mutex.cpp
myThread.h #linux系统下线程类实现
myThread.cpp
queuedata.h
win32Thread.h #windows系统下线程类实现
win32Thread.cpp
srv_IO #服务端Socket的API功能源码
MySocket.h
MySocket.cpp
MySocketPrivate.h
MySocketPrivate.cpp
MySocketRD.h
MySocketRD.cpp
MySocketSrv.h
MySocketSrv.cpp
MySocketWD.h
MySocketWD.cpp
svr_test #服务端业务功能源码
build_win #客户端windows编辑中间文件输出目录
build_linux #客户端linux编辑中间文件输出目录
main.cpp #
CMakeLists.txt #cmake配置文件
三、代码重构实践
3.1 相似结构体或类的归并
在DataDef.h文件内,有RDClient结构体和TCP_Data结构体,前者应用于/client_IO/MySocketClient.h/cpp和/srv_IO/MySocketPrivate.h/cpp中,用来缓存从socket句柄读取到的数据,后者应用于/client_io/[MySocketWD.h/cpp,MySocketRD.h/cpp]和/srv_io/[MySocketWD.h/cpp,MySocketRD.h/cpp]文件中,用于缓存将写入socket句柄的数据或缓存从socket句柄读取到并解码后的数据。RDClient结构体和TCP_Data结构体最大的不同就是缓存区域大小不同,主要是因为在业务设计时,RDClient结构体会存储多帧数据情况,而TCP_Data结构体存储是单帧数据。
//common/DataDef.h
#define RDCSIZE 1024
struct RDClient
{
RDClient()
: len(0)
{
memset(Buf,0,RDCSIZE);
};
RDClient(unsigned char *buf,int nlen)
{
memset(Buf,0,RDCSIZE);
memcpy(Buf,buf,nlen);
len = nlen;
};
~RDClient()
{
};
RDClient& operator=(const RDClient &rval)
{
if (this!=&rval)
{
memset(Buf,0,RDCSIZE);
memcpy(Buf,rval.Buf,rval.len);
len = rval.len;
}
return *this;
};
int add(unsigned char *buf,int nlen)
{
try{
memset(Buf+len,0,RDCSIZE-len);
memcpy(Buf+len,buf,nlen);
len += nlen;
}catch(...)
{
printf("RDClient::add error \r\n");
}
return len;
};
unsigned char Buf[RDCSIZE];
int len;
};
struct TCP_Data
{
TCP_Data() : len(0)
{
memset(Buf, 0, 512);
};
TCP_Data(unsigned char *buf, int nlen)
{
memset(Buf, 0, 512);
memcpy(Buf, buf, nlen);
len = nlen;
};
TCP_Data& operator=(const TCP_Data &rval)
{
if (this != &rval) {
memset(Buf, 0, 512);
if (rval.len < 512) {
memcpy(Buf, rval.Buf, rval.len);
len = rval.len;
}
else {
memcpy(Buf, rval.Buf, 512);
len = 512;
}
}
return *this;
};
unsigned char Buf[512];
int len;
};
因此最大变因是缓存区域长度依据应用不同值不同,这容易联想到模板参数上,因此采用模板来解决,如下文:
//common/DataDef.h
/
#define RDC_SIZE 1024 //服务端从socket读取数据时的缓存大小
#define DATA_SIZE 512 //服务及客户端的数据传输(读取及写入)的缓存大小
template<int SIZE = DATA_SIZE>
struct TCP_Data
{
TCP_Data()
: len(0)
{
memset(Buf,0,SIZE);
};
TCP_Data(unsigned char *buf,int nlen)
{
memset(Buf,0,SIZE);
memcpy(Buf,buf,nlen);
len = nlen;
};
~TCP_Data()
{
};
TCP_Data& operator=(const TCP_Data &rval)
{
if (this!=&rval)
{
memset(Buf,0,SIZE);
memcpy(Buf,rval.Buf,rval.len);
len = rval.len;
}
return *this;
};
int add(unsigned char *buf,int nlen)
{
try{
memset(Buf+len,0,SIZE-len);
memcpy(Buf+len,buf,nlen);
len += nlen;
}catch(...)
{
printf("RDClient::add error \r\n");
}
return len;
};
unsigned char Buf[SIZE];
int len;
};
如上,通过一个模板参数来解决不同应用场景上缓存区域长度不同的情况,那么原来的RDClient结构体和TCP_Data结构体就调整为TCP_Data<RDC_SIZE>和TCP_Data<>或TCP_Data<DATA_SIZE>,因此只要对应地在其他业务模块调用到RDClient结构体和TCP_Data结构体进行相应调整就好,例如:
//common/DataDef.h
//服务端读取从socket读取到的数据缓存结构(已解码)
struct RDS
{
RDS() : data(),flag("")
{
};
//RDS(TCP_Data _data,std::string _f = "") //old
RDS(TCP_Data<DATA_SIZE> _data,std::string _f = "")
: data(_data),flag(_f)
{
};
RDS& operator=(const RDS &rval)
{
if (this == &rval) {
return *this;
}
data = rval.data;
flag = rval.flag;
return *this;
};
//TCP_Data data;//old
TCP_Data<DATA_SIZE> data;
std::string flag;
};
/*------------------------------------------------------*/
//srv_IO/MySocketPrivate.h
//int Read(std::map<KeyObj_Client,RDClient &bufs);//old
int Read(std::map<KeyObj_Client,TCP_Data<RDC_SIZE> > &bufs);
3.2 平台特性隐匿
在线程类中,是在/common/win32Thread.h/cpp中实现windows线程服务,在/common/myThread.h/cpp中实现linux线程服务,现在需要将其合而为一,首选将win32Thread.h/cpp内容分别拷贝到/common/myThread.h/cpp上,并采用条件判定区分开来,例如:
//common/myThread.h
#ifndef _MYTHREAD_H
#define _MYTHREAD_H
#ifdef WIN32
//myThread.h原来的全部内容
#else
//来自win32Thread.h的全部内容
#endif
#endif //_MYTHREAD_H
//common/myThread.cpp
#ifdef WIN32
//myThread.cpp原来的全部内容
#else
//来自win32Thread.cpp的全部内容
#endif
然后,去调整/srv_test/CMakeLists.txt和/client_test/CMakeLists.txt,去除对win32Thread.h/cpp的依赖,并将/common/myThread.h/cpp的依赖从linux专属转换为通用。例如:
旧的/srv_test/CMakeLists.txt
# CMake 最低版本号要求
cmake_minimum_required (VERSION 3.2)
# 项目信息
project (server_test)
#
if(WIN32)
message(STATUS "windows compiling...")
add_definitions(-D_PLATFORM_IS_WINDOWS_)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
set(WIN_OS true)
else(WIN32)
message(STATUS "linux compiling...")
add_definitions( -D_PLATFORM_IS_LINUX_)
set(UNIX_OS true)
set(_DEBUG true)
endif(WIN32)
#
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../bin)
# 指定源文件的目录,并将名称保存到变量
SET(source_h
#
${PROJECT_SOURCE_DIR}/../common/queuedata.h
${PROJECT_SOURCE_DIR}/../common/Mutex.h
${PROJECT_SOURCE_DIR}/../common/hashmap.h
${PROJECT_SOURCE_DIR}/../common/myFunc.h
${PROJECT_SOURCE_DIR}/../common/Log.h
${PROJECT_SOURCE_DIR}/../srv_IO/MySocket.h
${PROJECT_SOURCE_DIR}/../srv_IO/MySocketRD.h
${PROJECT_SOURCE_DIR}/../srv_IO/MySocketWD.h
${PROJECT_SOURCE_DIR}/../srv_IO/MySocketPrivate.h
${PROJECT_SOURCE_DIR}/../srv_IO/MySocketSrv.h
)
SET(source_cpp
#
${PROJECT_SOURCE_DIR}/../common/Mutex.cpp
${PROJECT_SOURCE_DIR}/../common/hashmap.cpp
${PROJECT_SOURCE_DIR}/../common/myFunc.cpp
${PROJECT_SOURCE_DIR}/../common/Log.cpp
${PROJECT_SOURCE_DIR}/../srv_IO/MySocket.cpp
${PROJECT_SOURCE_DIR}/../srv_IO/MySocketRD.cpp
${PROJECT_SOURCE_DIR}/../srv_IO/MySocketWD.cpp
${PROJECT_SOURCE_DIR}/../srv_IO/MySocketPrivate.cpp
${PROJECT_SOURCE_DIR}/../srv_IO/MySocketSrv.cpp
${PROJECT_SOURCE_DIR}/main.cpp
)
#头文件目录
include_directories(
${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/../common
${PROJECT_SOURCE_DIR}/../srv_IO
)
if (${UNIX_OS})
SET(source_h_linux
${PROJECT_SOURCE_DIR}/../common/myThread.h
)
SET(source_cpp_linux
${PROJECT_SOURCE_DIR}/../common/myThread.cpp
)
add_definitions(
"-W"
"-fPIC"
"-Wall"
"-Werror"
"-Wshadow"
"-Wformat"
"-Wpointer-arith"
"-D_REENTRANT"
"-D_USE_FAST_MACRO"
"-Wno-long-long"
"-Wuninitialized"
"-D_POSIX_PTHREAD_SEMANTICS"
"-DACL_PREPARE_COMPILE"
"-Wno-unused-parameter"
"-fexceptions"
)
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0")
link_directories()
# 指定生成目标
add_executable(server_test ${source_h} ${source_cpp} ${source_h_linux} ${source_cpp_linux})
#link
target_link_libraries(server_test
-lpthread -pthread -lz -lrt -ldl
)
endif(${UNIX_OS})
if (${WIN_OS})
SET(source_h_win
${PROJECT_SOURCE_DIR}/../common/win32Thread.h
)
SET(source_cpp_win
${PROJECT_SOURCE_DIR}/../common/win32Thread.cpp
)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4819")
add_definitions(
"-D_CRT_SECURE_NO_WARNINGS"
"-D_WINSOCK_DEPRECATED_NO_WARNINGS"
"-DNO_WARN_MBCS_MFC_DEPRECATION"
"-DWIN32_LEAN_AND_MEAN"
)
link_directories()
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_SOURCE_DIR}/../bin)
# 指定生成目标
add_executable(server_testd ${source_h} ${source_cpp} ${source_h_win} ${source_cpp_win})
else(CMAKE_BUILD_TYPE)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/../bin)
# 指定生成目标
add_executable(server_test ${source_h} ${source_cpp} ${source_h_win} ${source_cpp_win})
endif (CMAKE_BUILD_TYPE)
endif(${WIN_OS})
新的/srv_test/CMakeLists.txt,一下子内容简介清爽不少。
# CMake 最低版本号要求
cmake_minimum_required (VERSION 3.2)
# 项目信息
project (server_test)
#
if(WIN32)
message(STATUS "windows compiling...")
add_definitions(-D_PLATFORM_IS_WINDOWS_)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
set(WIN_OS true)
else(WIN32)
message(STATUS "linux compiling...")
add_definitions( -D_PLATFORM_IS_LINUX_)
set(UNIX_OS true)
set(_DEBUG true)
endif(WIN32)
#
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../bin)
# 指定源文件的目录,并将名称保存到变量
SET(source_h
#
${PROJECT_SOURCE_DIR}/../common/queuedata.h
${PROJECT_SOURCE_DIR}/../common/Mutex.h
${PROJECT_SOURCE_DIR}/../common/hashmap.h
${PROJECT_SOURCE_DIR}/../common/myFunc.h
${PROJECT_SOURCE_DIR}/../common/myThread.h
${PROJECT_SOURCE_DIR}/../common/Log.h
${PROJECT_SOURCE_DIR}/../srv_IO/MySocket.h
${PROJECT_SOURCE_DIR}/../srv_IO/MySocketRD.h
${PROJECT_SOURCE_DIR}/../srv_IO/MySocketWD.h
${PROJECT_SOURCE_DIR}/../srv_IO/MySocketPrivate.h
${PROJECT_SOURCE_DIR}/../srv_IO/MySocketSrv.h
)
SET(source_cpp
#
${PROJECT_SOURCE_DIR}/../common/Mutex.cpp
${PROJECT_SOURCE_DIR}/../common/hashmap.cpp
${PROJECT_SOURCE_DIR}/../common/myFunc.cpp
${PROJECT_SOURCE_DIR}/../common/myThread.cpp
${PROJECT_SOURCE_DIR}/../common/Log.cpp
${PROJECT_SOURCE_DIR}/../srv_IO/MySocket.cpp
${PROJECT_SOURCE_DIR}/../srv_IO/MySocketRD.cpp
${PROJECT_SOURCE_DIR}/../srv_IO/MySocketWD.cpp
${PROJECT_SOURCE_DIR}/../srv_IO/MySocketPrivate.cpp
${PROJECT_SOURCE_DIR}/../srv_IO/MySocketSrv.cpp
${PROJECT_SOURCE_DIR}/main.cpp
)
#头文件目录
include_directories(
${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/../common
${PROJECT_SOURCE_DIR}/../srv_IO
)
if (${UNIX_OS})
add_definitions(
"-W"
"-fPIC"
"-Wall"
"-Werror"
"-Wshadow"
"-Wformat"
"-Wpointer-arith"
"-D_REENTRANT"
"-D_USE_FAST_MACRO"
"-Wno-long-long"
"-Wuninitialized"
"-D_POSIX_PTHREAD_SEMANTICS"
"-DACL_PREPARE_COMPILE"
"-Wno-unused-parameter"
"-fexceptions"
)
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0")
link_directories()
# 指定生成目标
add_executable(server_test ${source_h} ${source_cpp} )
#link
target_link_libraries(server_test
-lpthread -pthread -lz -lrt -ldl
)
endif(${UNIX_OS})
if (${WIN_OS})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4819")
add_definitions(
"-D_CRT_SECURE_NO_WARNINGS"
"-D_WINSOCK_DEPRECATED_NO_WARNINGS"
"-DNO_WARN_MBCS_MFC_DEPRECATION"
"-DWIN32_LEAN_AND_MEAN"
)
link_directories()
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_SOURCE_DIR}/../bin)
# 指定生成目标
add_executable(server_testd ${source_h} ${source_cpp} )
else(CMAKE_BUILD_TYPE)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/../bin)
# 指定生成目标
add_executable(server_test ${source_h} ${source_cpp} )
endif (CMAKE_BUILD_TYPE)
endif(${WIN_OS})
在回到/common/myThread.h/cpp上,我的做法是,逐步将一些共性部分移出编译条件外进行合并,每移动及合并后,编译测试一下,直到将win及linux可以共性的部分迁移出来,然后再分析哪些不共性的部分,是否可以通过重命名、重映射等进行合并,最终得到的线程类如下:
myThread.h
#ifndef _MYTHREAD_H
#define _MYTHREAD_H
/***********************************************************************
*Copyright 2023-02-06, pyfree
*
*File Name : myThread.h
*File Mark :
*Summary :
*支持windows和linux的线程类,提供基本的线程功能(循环、启动、退出)
*
*Current Version : 1.00
*Author : pyfree
*FinishDate :
*
*Replace Version :
*Author :
*FinishDate :
************************************************************************/
#ifdef WIN32
#include <process.h>
#include <iostream>
typedef void* HANDLE_THREAD;
#else
#include <pthread.h>
#include <unistd.h>
typedef pthread_t HANDLE_THREAD;
#endif
class MyThread
{
public://func
MyThread(); // constructed function
~MyThread();
/**
* the entity for thread running
* @param null {void } 无参数
* @return {int} 运行返回结果
*/
virtual int Run()=0;
/**
* start thread
* @param null {void } 无参数
* @return {bool} 是否启动成功
*/
bool start();
/**
* get thread ID
* @param null {void } 无参数
* @return {HANDLE_THREAD} 线程句柄
*/
HANDLE_THREAD getThreadID();
#ifdef __linux__
//get thread status
int getState();
//wait for thread end
void join();
//wait for thread end in limit time
void join(unsigned long millisTime);
#endif
public://val
#ifdef __linux__
//threadStatus-new create
static const int THREAD_STATUS_NEW = 0;
//threadStatus-running
static const int THREAD_STATUS_RUNNING = 1;
//threadStatus-end
static const int THREAD_STATUS_EXIT = -1;
#endif
private://func
#ifdef WIN32
static void agent(void *p);
#else
//get manner pointer of execution
static void* run0(void* pVoid);
//manner of execution inside
void* run1();
#endif
private://val
HANDLE_THREAD hThread;
#ifdef __linux__
//thread status
int threadStatus;
#endif
};
#endif /* _MYTHREAD_H */
myThread.cpp
#include "myThread.h"
#ifdef WIN32
#include <windows.h>
#else
#include <stdio.h>
#endif
MyThread::MyThread()
{
#ifdef __linux__
hThread = 0;
threadStatus = THREAD_STATUS_NEW;
#endif
}
MyThread::~MyThread()
{
#ifdef WIN32
WaitForSingleObject(hThread, INFINITE);
#else
join(10);
#endif
}
int MyThread::Run()
{
#ifdef WIN32
printf("Base Thread\n");
#else
while(true){
printf("thread is running!\n");
sleep(100);
}
#endif
return 0;
}
bool MyThread::start()
{
#ifdef WIN32
return NULL!=(hThread =(HANDLE_THREAD)_beginthread(agent, 0, (void *)this));
#else
return pthread_create(&hThread, NULL, run0, this) == 0;
#endif
}
HANDLE_THREAD MyThread::getThreadID()
{
return hThread;
}
#ifdef WIN32
void MyThread::agent(void *p)
{
MyThread *agt = (MyThread *)p;
agt->Run();
}
#else
void* MyThread::run0(void* pVoid)
{
MyThread* p = (MyThread*) pVoid;
p->run1();
return p;
}
void* MyThread::run1()
{
threadStatus = THREAD_STATUS_RUNNING;
hThread = pthread_self();
Run();
threadStatus = THREAD_STATUS_EXIT;
hThread = 0;
pthread_exit(NULL);
}
int MyThread::getState()
{
return threadStatus;
}
void MyThread::join()
{
if (hThread > 0)
{
pthread_join(hThread, NULL);
}
}
void MyThread::join(unsigned long millisTime)
{
if (hThread == 0)
{
return;
}
if (millisTime == 0)
{
join();
}else
{
unsigned long k = 0;
while (threadStatus != THREAD_STATUS_EXIT && k <= millisTime)
{
usleep(100);
k++;
}
}
}
#endif
这样调整后,开发使用是只调用提供的API就好,win/linux下的线程具体实现不再是关注重点了。并在后续如果再遇到跨win/linux平台支持的线程类时,就可以直接调用,再根据项目实际需要做部分调整,实现了快速复用。
3.3 业务模块归并
在初始版本中,将tcp/socket服务接口分为client_IO客户端部分和srv_IO服务端部分,编译客户端程序就使用client_IO部分,编译服务端程序就使用srv_IO部分。若将这两部分合并在一起时,那么就在编译时,添加一个宏定义来明确什么时候调用srv_IO部分或client_IO部分即可。例如在/srv_test/CMakeLists.txt中追加宏定义add_definitions("-D_SERVERIO_")(如下图),而/client_test/CMakeLists.txt中不添加。
类似前面线程类合并操作那样,将/client_IO/[MySocketWD.h/cpp,MySocketRD.h/cpp,MySocket.h/cpp]分别拷贝到/srv_IO/[MySocketWD.h/cpp,MySocketRD.h/cpp,MySocket.h/cpp]文件内,采用#ifdef _SERVERIO_来区分,例如
//srv_IO/MySocketWD.h
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef _MySocketWD_H_
#define _MySocketWD_H_
#ifdef _SERVERIO_
//来自srv_IO/MySocketWD.h的全部内容
#else
//来自client_IO/MySocketWD.h的全部内容
#endif //_SERVERIO_
#endif //_MySocketWD_H_
而/client_IO/MySocketClient.h/cpp和/srv_IO/MySocketPrivate.h/cpp是类似的,虽然当初两个文件起名不一致,但还是可以合并,类似地将/client_IO/MySocketClient.h/cpp分别拷贝到/srv_IO/MySocketPrivate.h/cpp文件中,也采用#ifdef _SERVERIO_来区分。
然后去调整客户端的编译配置/client_test/CMakeLists.txt,将原来依赖client_IO的调整为srv_IO,client_IO文件夹内容将退出本版本的舞台。
然后再去各个模块中将原来依赖引用MySocketClient.h文件的调整为依赖引用MySocketPrivate.h即可,由于里面的类名还没调整,值修改引用头文件即可再次编译通过。OK,没做过多工作就干掉了client_IO文件夹及其内容,项目目录简化了许多。
接下来才是client_IO模块和srv_IO模块真正合并的工作开始,将和并过来的内容,如前面修改MyThread类那样,逐步将一些共同的内容移出到_SERVERIO_编译条件外,随后将一些类似的移出,后面再通过重映、重命名、共性点提炼及差异点隐藏等逐步尽可能将内容移出到_SERVERIO_编译条件外。每移动一部分最好就编译一下及运行测试一下,确保每部调整的正确性,而非等到所有调整后再编译确定,那样出现一堆异常将无法很好确定遗漏点。另外注意的是,在归并过程中,不要引入新功能,反而必要时,可以剔除旧功能,使得代码更加凝练。
简要调整过程如下:
1)在/srv_IO/MySocketPrivate.h/cpp文件中,将客户端部分的MySocketClient类名调整为->MySocketPrivate类名,使得其与服务端的一致。
2)将各个原来调用MySocketClient类的地方(MySocket.h/cpp,MySocketWD.h/cpp,MySocketRD.h/cpp)调整为MySocketPrivate。
3)先易后难,依次将/srv_IO/[MySocket.h/cpp,MySocketWD.h/cpp,MySocketRD.h/cpp,MySocketPrivate.h/cpp]的内容进行合并。
例如,公有依赖及引用移出宏编译条件外。
不同的依赖及引用通过宏编译条件_SERVERIO_区分
有些函数微调就能达成一致,例如MySocket的构造函数,是可以达成一致的,将构造参数都采用NetArg结构体,只是对于服务端,多了一个无用的IP信息而已。有些暂时无法达成一致的还是采用宏编译条件来区分,例如服务端需要侦听线程而客户端是不需要的。
MySocket(int _tranid, NetArg _netarg);//客户端的构造函数
MySocket(unsigned int port,int netType_=1);//服务端的构造函数
//统一调整为
MySocket(NetArg _netarg);
头文件调整完成后,响应的定义部分及调用部分作出调整,在MySocket.cpp几乎不动情况下,就能编译通过。
对于源文件MySocket.cpp来说,由于函数大致相同,调整时将服务端及客户端部分的对于函数一个个函数拷贝出宏编译条件外,进行合并,这个是很容易就能实现的。
遇到有些不一致的地方,需要分析其原因,去其他模块作出相应调整,遵循以当前模块为主,遇到依赖其他模块的再去其他模块调整,仅调整需要的(最小化原则),当然其他模块调整会引出连锁反应,追踪下去逐一调整即可。
最终MySocket.h/cpp经过调整后,和原来仅服务端或客户端程序代码量还是结构都没多少区别,但却同时实现了服务端或客户端socket服务接口。
MySocket.h
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef _MySocket_H_
#define _MySocket_H_
#include "DataDef.h"
class MySocketPrivate;
class MySocketRD;
class MySocketWD;
#ifdef _SERVERIO_
/*
*建立socket服务端
*/
class MySocketSrv;
#else
/*
*建立socket客户端
*/
#include <string>
#endif
class MySocket
{
public:
MySocket(NetArg _netarg);
virtual ~MySocket(void);
public:
virtual int Read(){ return -1; };
virtual int Write(){ return -1; };
//
//int Read(char* buf, int size);
int Write(const char* buf, int size);
private:
#ifdef _SERVERIO_
MySocketSrv *my_SocketSrv;
#else
NetArg netarg;
#endif
MySocketPrivate *my_PrivateData;
MySocketRD *m_MySocketRD;
MySocketWD *m_MySocketWD;
};
#endif //_MYSOCKET_H_
MySocket.cpp
#include "MySocket.h"
#include "MySocketPrivate.h"
#include "MySocketWD.h"
#include "MySocketRD.h"
#include "Log.h"
#ifdef _SERVERIO_
#include "MySocketSrv.h"
#endif
*MySocket*///
MySocket::MySocket(NetArg _netarg)
{
try {//防止构造时异常出现内存泄漏
#ifdef _SERVERIO_
my_PrivateData = new MySocketPrivate(_netarg.port);
#else
netarg = _netarg;
//TCP/IP客户端,连接监控服务或其他平台
my_PrivateData = new MySocketPrivate(netarg.ipStr, netarg.port);
#endif
if (my_PrivateData->onConnect() <= 0)
{
#ifdef _SERVERIO_
my_SocketSrv = NULL;
m_MySocketRD = NULL;
m_MySocketWD = NULL;
CLogger::createInstance()->Log(eSoftError,
"listen port(%u) error, [%s %s %d]"
, _netarg.port
, __FILE__, __FUNCTION__, __LINE__);
#else
CLogger::createInstance()->Log(eSoftError,
"connect server[%s,%d] error,please check it,[%s %s %d]!"
, netarg.ipStr.c_str(), netarg.port
, __FILE__, __FUNCTION__, __LINE__);
#endif
}
else
{
#ifdef _SERVERIO_
my_SocketSrv = new MySocketSrv();
my_SocketSrv->setPDataPtr(my_PrivateData);
my_SocketSrv->start();
#endif
//数据接收线程
m_MySocketRD = new MySocketRD(my_PrivateData, _netarg.type);
m_MySocketRD->start();
//数据发送线程
m_MySocketWD = new MySocketWD(my_PrivateData, _netarg.type);
m_MySocketWD->start();
}
}
catch (...) {
#ifdef _SERVERIO_
delete my_SocketSrv;
my_SocketSrv = NULL;
#endif
delete m_MySocketRD;
m_MySocketRD = NULL;
delete m_MySocketWD;
m_MySocketWD = NULL;
delete my_PrivateData;
my_PrivateData = NULL;
CLogger::createInstance()->Log(eSoftError,
"MySocket init error, [%s %s %d]"
, __FILE__, __FUNCTION__, __LINE__);
}
};
MySocket::~MySocket(void)
{
#ifdef _SERVERIO_
if (NULL != my_SocketSrv)
{
delete my_SocketSrv;
my_SocketSrv = NULL;
}
#endif
if (NULL != m_MySocketRD)
{
delete m_MySocketRD;
m_MySocketRD = NULL;
}
if (NULL != m_MySocketWD)
{
delete m_MySocketWD;
m_MySocketWD = NULL;
}
if(NULL!=my_PrivateData)
{
delete my_PrivateData;
my_PrivateData = NULL;
}
};
int MySocket::Write(const char* buf, int size)
{
if (size <= 0|| NULL == buf ||NULL == m_MySocketWD)
{
return -1;
}
return m_MySocketWD->add_data(buf, size);
};
类似地,完成/srv_IO/[,MySocketWD.h/cpp,MySocketRD.h/cpp,MySocketPrivate.h/cpp]文件内容的合并归整。
服务端及客户端的socket服务接口归并整合后,模块目录再叫srv_IO就不妥了,给该目录重命名一下,例如socket_io。修改CMakeLists.txt,将对变量srv_IO的依赖地方调整为socket_io。
3.4 函数、变量、引用、注释等细节方面调整
在整体业务归并并编译测试通过后,就可以在细节方面进行调整了。例如,在MySocketRD.cpp中,win/linux在数据帧解析上,存在四处,那就对其归并处理。
//MySocketRD.cpp
//Run函数内,数据帧解析部分
//client && nettype=1
if (ReadData.getFirst(rddata))
{
this->AddFrame(rddata.Buf, rddata.len);
ReadData.removeFirst();
}
//client && nettype=2
while (ReadData.getFirst(rddata))
{
this->AddFrame(rddata.Buf, rddata.len);
ReadData.removeFirst();
}
//server && nettype=1
while (ReadData.getFirst(rdataGx))
{
this->AddFrame(rdataGx.flag, rdataGx.data.Buf, rdataGx.data.len);
ReadData.removeFirst();
}
//server && nettype=2
while (ReadData.getFirst(rdataGx))
{
this->AddFrame(rdataGx.flag, rdataGx.data.Buf, rdataGx.data.len);
ReadData.removeFirst();
}
因此可以把这些重复部分提炼出来,增加一个函数来处理,设计如下,然后这四个地方调用该函数,实现代码精简。
void MySocketRD::Cache_doit()
{
#ifdef _SERVERIO_
RDS rddata;
#else
TCP_Data<DATA_SIZE> rddata;
#endif
//数据帧解析
while (ReadData.getFirst(rddata))
{
#ifdef _SERVERIO_
this->AddFrame(rddata.data.Buf, rddata.data.len,rddata.flag);
#else
this->AddFrame(rddata.Buf, rddata.len);
#endif
ReadData.removeFirst();
}
}
又如,在MySocketPrivate.cpp内,由于原来开发过程中增加了太多头文件引用,但其实可能不少编译时是不需要的,通过编译确认进行删减,精简代码。
再调整代码的同时,在注释方面最好也是同步调整,便于后面时间久了遗忘。
四、代码优化后的项目
经过上述一些系列代码优化操作,项目的目录结构如下,已经优化了不少。
#
TCP_StructData
bin #编译输出结果
client_test
client_test.exe
server_test
server_test.exe
common #共同功能模块或数据结构源码
DataDef.h #结构化数据
hashmap.h #结构化数据作为容器Key实现
hashmap.cpp
Log.h #日志模块
Log.cpp
Mutex.h #互斥锁
Mutex.cpp
myThread.h #windows和linux系统下线程类实现
myThread.cpp
queuedata.h
socket_io #Socket的API功能源码
MySocket.h
MySocket.cpp
MySocketPrivate.h
MySocketPrivate.cpp
MySocketRD.h
MySocketRD.cpp
MySocketSrv.h
MySocketSrv.cpp
MySocketWD.h
MySocketWD.cpp
client_test #客户端业务功能源码
build_win #客户端windows编辑中间文件输出目录
build_linux #客户端linux编辑中间文件输出目录
main.cpp
CMakeLists.txt #cmake配置文件
svr_test #服务端业务功能源码
build_win #客户端windows编辑中间文件输出目录
build_linux #客户端linux编辑中间文件输出目录
main.cpp #
CMakeLists.txt #cmake配置文件
新旧版本纯代码及编译配置文件打包后,代码量如下:
当然代码重构是一个持续输出的过程,不要想着一蹴而就,该代码虽然进行了很大调整,但其还有很多可以优化的地方,代码重构在路上,本文仅是就这个小项目做一些抛转引玉的建议。
章节五、附录-源码文件,给出了全部源码,大家感兴趣的可以按目录结构组织一下编译体验。源码也打包上传到CSDN,但设置了付费资源模式,大家还是老实自己动手从附件中拷贝组织一下使用吧:
https://download.csdn.net/download/py8105/87429547
编译指令一往如继:
//客户端程序编译指令
win:
cd client_test && mkdir build_win && cd build_win
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_BUILD_TYPE=Release .. -Wno-dev
#vs 命令窗口
msbuild client_test.sln /p:Configuration="Release" /p:Platform="x64"
linux:
cd client_test && mkdir build_linux && cd build_linux
cmake ..
make
//服务端程序编译指令
cd srv_test && mkdir build_win && cd build_win
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_BUILD_TYPE=Release .. -Wno-dev
#vs 命令窗口
msbuild server_test.sln /p:Configuration="Release" /p:Platform="x64"
linux:
cd srv_test && mkdir build_linux && cd build_linux
cmake ..
make
运行:
win:srv_test.exe client_test.exe 127.0.0.1 70001
Linux:./srv_test ./client_test 127.0.0.1 70001
win重新编译及运行如下:
Linux编译及运行如下:
五、附录-源码文件
5.1 common目录
DataDef.h
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef _DATA_DEF_H_
#define _DATA_DEF_H_
/***********************************************************************
*Copyright 2023-02-06, pyfree
*
*File Name : DataDef.h
*File Mark :
*Summary :
*服务端及客户端共用数据结构类型定义
*
*Current Version : 1.00
*Author : pyfree
*FinishDate :
*
*Replace Version :
*Author :
*FinishDate :
************************************************************************/
#include <string>
#ifdef __linux__
#include <string.h>
#include <stdio.h>
#endif
struct NetArg
{
NetArg()
: ipStr("127.0.0.1"),port(70001),type(1)
{
};
std::string ipStr; //
int port; //
int type; //Protocol
};
模块化数据传输示例结构/
typedef struct TCP_Data_Model
{
unsigned type;
int len;
float val;
char desc[32];
}TcpSocket,*PTcpSocket;
/
#define RDC_SIZE 1024 //服务端从socket读取数据时的缓存大小
#define DATA_SIZE 512 //服务及客户端的数据传输(读取及写入)的缓存大小
template<int SIZE = DATA_SIZE>
struct TCP_Data
{
TCP_Data()
: len(0)
{
memset(Buf,0,SIZE);
};
TCP_Data(unsigned char *buf,int nlen)
{
memset(Buf,0,SIZE);
memcpy(Buf,buf,nlen);
len = nlen;
};
~TCP_Data()
{
};
TCP_Data& operator=(const TCP_Data &rval)
{
if (this!=&rval)
{
memset(Buf,0,SIZE);
memcpy(Buf,rval.Buf,rval.len);
len = rval.len;
}
return *this;
};
int add(unsigned char *buf,int nlen)
{
try{
memset(Buf+len,0,SIZE-len);
memcpy(Buf+len,buf,nlen);
len += nlen;
}catch(...)
{
printf("RDClient::add error \r\n");
}
return len;
};
unsigned char Buf[SIZE];
int len;
};
/
//服务端读取从socket读取到的数据缓存结构(已解码)
struct RDS
{
RDS() : data(),flag("")
{
};
RDS(TCP_Data<DATA_SIZE> _data,std::string _f = "")
: data(_data),flag(_f)
{
};
RDS& operator=(const RDS &rval)
{
if (this == &rval) {
return *this;
}
data = rval.data;
flag = rval.flag;
return *this;
};
TCP_Data<DATA_SIZE> data;
std::string flag;
};
/
//服务端准备写入socket的数据缓存结构(未编码)
struct WDS
{
WDS() : ipInt(0), data()
{
};
WDS(unsigned long long _ipInt,TCP_Data<DATA_SIZE> _data)
: ipInt(_ipInt), data(_data)
{
};
WDS& operator=(const WDS &rval)
{
if (this == &rval) {
return *this;
}
ipInt = rval.ipInt;
data = rval.data;
return *this;
};
unsigned long long ipInt;
TCP_Data<DATA_SIZE> data;
};
#endif
hashmap.h
#pragma once
#ifndef HASH_MAP_H
#define HASH_MAP_H
/*
*自定义map容器的Key
*/
#include <map>
#include <iostream>
//
class KeyObj_Client
{
public:
KeyObj_Client(std::string _ipStr, int _port);
//
static long cmp_Key(const KeyObj_Client &obj1, const KeyObj_Client &obj2);
std::string m_ipStr;
int m_port;
int linkFlag;
long m_ip; //网络地址整型表述
private:
};
inline bool operator==(const KeyObj_Client& obj1, const KeyObj_Client& obj2) { return KeyObj_Client::cmp_Key(obj1, obj2) == 0; }
inline bool operator!=(const KeyObj_Client& obj1, const KeyObj_Client& obj2) { return KeyObj_Client::cmp_Key(obj1, obj2) != 0; }
inline bool operator>=(const KeyObj_Client& obj1, const KeyObj_Client& obj2) { return KeyObj_Client::cmp_Key(obj1, obj2) >= 0; }
inline bool operator<=(const KeyObj_Client& obj1, const KeyObj_Client& obj2) { return KeyObj_Client::cmp_Key(obj1, obj2) <= 0; }
inline bool operator>(const KeyObj_Client& obj1, const KeyObj_Client& obj2) { return KeyObj_Client::cmp_Key(obj1, obj2) > 0; }
inline bool operator<(const KeyObj_Client& obj1, const KeyObj_Client& obj2) { return KeyObj_Client::cmp_Key(obj1, obj2) < 0; }
#endif //HASH_MAP_H
hashmap.cpp
#include "hashmap.h"
#ifdef WIN32
#include <Winsock2.h>
#else
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#include "myFunc.h"
#include "Log.h"
KeyObj_Client::KeyObj_Client(std::string _ipStr, int _port)
: m_ipStr(_ipStr), m_port(_port), linkFlag(0)
{
m_ip = PFunc::ipToInt(_ipStr);
};
//
long KeyObj_Client::cmp_Key(const KeyObj_Client &obj1, const KeyObj_Client &obj2)
{
long diff = obj1.m_ip - obj2.m_ip;
if (diff != 0) return diff;
diff = obj1.m_port - obj2.m_port;
if (diff != 0) return diff;
return 0;
};
Log.h
#ifndef CHANNELLOG_H
#define CHANNELLOG_H
#include <stdio.h>
#include <stdarg.h>
#include <string>
#ifdef linux
#include <string.h>
#endif
#include "myThread.h"
#include <queue>
#include "Mutex.h"
#ifndef WIN32
#include <string>
#include <sstream>
namespace std
{
template < typename T > std::string to_string(const T & n)
{
std::ostringstream stm;
stm << n;
return stm.str();
}
}
int GetPrivateProfileString(const char *AppName, const char *key, const char *defaultvalue, char *lpReturnedString, const int nSize, const char *lpFileName);
int GetPrivateProfileInt(const char *AppName,const char *key,const int defaultvalue,const char *lpFileName);
#endif
enum eLogType
{
eHardError = 1,
eSoftError = 2,
eConfigError = 3,
eParameterError = 4,
eReadError = 5,
eWriteError = 6,
eControlMessage = 7,
eResponseMessage = 8,
eTipMessage = 9
};
struct MyLogStruct
{
MyLogStruct():type(0)
{
memset(szBuffer, 0, 1024);
};
int type;
char szBuffer[1024];
};
class CLogger : public MyThread
{
public:
CLogger();
~CLogger();
int Run();
public:
void Log(const eLogType type, const char* lpszFormat, ...);
static CLogger* createInstance( void );
private:
bool getFirstLog(MyLogStruct &it);
void addLog(MyLogStruct it);
private:
static CLogger* m_pLogInstance;
bool running;
//for cache
std::queue<MyLogStruct> mylogs;
PYMutex m_Mutex_Log;
int i_log_over;
};
#endif
Log.cpp
#include "Log.h"
#include <time.h>
#include <sys/timeb.h>
#ifdef __linux__
#ifndef sprintf_s
#define sprintf_s sprintf
#endif
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#endif
CLogger* CLogger::m_pLogInstance = NULL;
//extern void WriteLog( const int iMsgType, const std::string strMsg);
extern char LOG_FILE_NAME[128]; //LOGFILE Name, should be defined
extern std::string logdir;
void WriteLog1( const int iMsgType, const char * strMsg)
{
try {
time_t tt;
struct timeb tm0;
struct tm tm1;
char buf[512];
FILE * fpLog = NULL;
//time(&tt);
ftime(&tm0);
tt = tm0.time;
#ifdef WIN32
localtime_s(&tm1, &tt);
#else
localtime_r(&tt, &tm1);
#endif
sprintf_s(buf, "%04d-%02d-%02d %02d:%02d:%02d.%03d "
, tm1.tm_year + 1900, tm1.tm_mon + 1, tm1.tm_mday
, tm1.tm_hour, tm1.tm_min, tm1.tm_sec, tm0.millitm);
std::string strTime = buf;
buf[10] = '\0';
//file name
std::string strPath = logdir;
#ifdef WIN32
strPath += "\\";
#else
strPath += "/";
#endif
strPath += buf;
strPath += "_";
//
switch (iMsgType)
{
case eHardError:
strTime += "[HardErrorIMsg] ";
break;
case eSoftError:
strTime += "[SoftErrorIMsg] ";
break;
case eConfigError:
strTime += "[ConfErrorIMsg] ";
break;
case eParameterError:
strTime += "[ParamErrorMsg] ";
break;
case eReadError:
strTime += "[ReadErrorIMsg] ";
break;
case eWriteError:
strTime += "[WriteErrorMsg] ";
break;
case eControlMessage:
strTime += "[ControlExeMsg] ";
//strPath += "chain_";
break;
case eResponseMessage:
strTime += "[ResponseUpMsg] ";
//strPath += "chain_";
break;
case eTipMessage:
strTime += "[NoticeTipIMsg] ";
break;
default:
strTime += "[PromptUnNoMsg] ";
break;
}
strPath += LOG_FILE_NAME;
//open
#ifdef WIN32
fopen_s(&fpLog, strPath.c_str(), "a+");
#else
fpLog = fopen(strPath.c_str(), "a+");
#endif
if (NULL != fpLog)
{
fseek(fpLog, 0, SEEK_END);
fwrite(strTime.c_str(), strTime.length(), 1, fpLog);
fwrite(strMsg, strlen(strMsg), 1, fpLog);
fwrite("\n", 1, 1, fpLog);
fclose(fpLog);
}
}
catch (...) {
printf("write log[%d]{%s}error\n", iMsgType, strMsg);
}
}
#ifdef WIN32
#include <windows.h>
#include <atlcomtime.h>
extern char SVCNAME[128];
void WriteLog( const int iMsgType, const char * strMsg)
{
try {
if (iMsgType < int(eConfigError))
{
HANDLE hEventSource;
LPCTSTR lpszStrings[2];
hEventSource = RegisterEventSource(NULL, SVCNAME);
if (NULL != hEventSource)
{
lpszStrings[0] = SVCNAME;
lpszStrings[1] = strMsg;
ReportEvent(hEventSource, // event log handle
EVENTLOG_ERROR_TYPE, // event type
0, // event category
0, // event identifier
NULL, // no security identifier
2, // size of lpszStrings array
0, // no binary data
lpszStrings, // array of strings
NULL); // no binary data
DeregisterEventSource(hEventSource);
}
}
}
catch (...) {
printf("WriteLog[%d]{%s}for Evnet error\n", iMsgType, strMsg);
}
WriteLog1(iMsgType, strMsg);
}
#else
void WriteLog( const int iMsgType, const char * strMsg)
{
WriteLog1(iMsgType, strMsg);
}
#endif
CLogger::CLogger()
: running(true)
, i_log_over(0)
{
char buf[256] = {0};
sprintf_s(buf,"mkdir %s",logdir.c_str());
system(buf);
this->start();
};
CLogger::~CLogger()
{
running = false;
};
CLogger* CLogger::createInstance( void )
{
if (m_pLogInstance == NULL)
{
m_pLogInstance = new CLogger();
return m_pLogInstance;
}
else
return m_pLogInstance;
};
int CLogger::Run()
{
MyLogStruct log_;
while (running) {
if (getFirstLog(log_))
{
WriteLog(log_.type, log_.szBuffer);
#ifndef WIN32
printf("Log::[%d]-->%s\n", getpid(), log_.szBuffer);
#else
printf("Log::-->%s\n", log_.szBuffer);
#endif
}
#ifdef WIN32
Sleep(10);
#else
usleep(10000);
#endif
}
return 0;
};
void CLogger::Log(const eLogType type, const char* lpszFormat, ...)
{
va_list args;
//char szBuffer[2048] = {0};
MyLogStruct log_;
log_.type = static_cast<int>(type);
va_start(args, lpszFormat);
#ifdef WIN32
vsnprintf_s(log_.szBuffer,sizeof(log_.szBuffer), lpszFormat, args);
#else
vsnprintf(log_.szBuffer, sizeof(log_.szBuffer), lpszFormat, args);
#endif
va_end(args);
addLog(log_);
}
bool CLogger::getFirstLog(MyLogStruct &it) {
bool ret = false;
m_Mutex_Log.Lock();
if (!mylogs.empty()) {
it = mylogs.front();
mylogs.pop();
ret = true;
}
m_Mutex_Log.Unlock();
return ret;
}
void CLogger::addLog(MyLogStruct it) {
m_Mutex_Log.Lock();
if (mylogs.size() > 100) {
i_log_over++;
mylogs.pop();
}
mylogs.push(it);
m_Mutex_Log.Unlock();
if (i_log_over >= 100) {//每溢出100次,报告一次
MyLogStruct log_;
log_.type = static_cast<int>(eTipMessage);
sprintf(log_.szBuffer,"the size of mylogs queue is up to limmit size[100],[%s %s %d]."
, __FILE__, __FUNCTION__, __LINE__);
m_Mutex_Log.Lock();
mylogs.push(log_);
m_Mutex_Log.Unlock();
i_log_over = 0;
}
}
#ifndef WIN32
#include <sys/vfs.h>
#include <mntent.h>
//int GetPrivateProfileInt(const char * lpAppName, const char *lpKeyName, int nDefault, const char * lpFileName)
//{
// return nDefault;
//}
//int GetPrivateProfileString(const char * lpAppName, const char * lpKeyName, const char * szDefault, char * szOut, const int nLen ,const char * lpFileName)
//{
// strncpy(szOut, szDefault, nLen);
// return 0;
//}
int GetPrivateProfileString(const char *AppName, const char *key, const char *defaultvalue, char *lpReturnedString, const int nSize, const char *lpFileName)
{
bool bFindAppName = false;
char tem[1000];
char *ptr;
FILE *fp;
char name[150];
snprintf(name, sizeof(name), "[%s]", AppName);
strncpy(lpReturnedString,defaultvalue, nSize);
if( (lpFileName == NULL) || ((fp=fopen(lpFileName,"rt"))==NULL) )// || fgets(tem,len,fp) == NULL)
{
return strlen(lpReturnedString);
}
while(fgets(tem,sizeof(tem),fp))
{
if(tem[0] == '[')
{
bFindAppName = false;
if(strstr(tem,name)==tem)
bFindAppName = true;
}
else
{
if(bFindAppName == true)
{
unsigned int n =strcspn(tem,"=");
if(static_cast<unsigned int>(strlen(key)) == n
&& static_cast<int>(strncasecmp(tem,key,n)) == 0)
{
strncpy(lpReturnedString, tem+n+1,nSize);
if( (ptr = strchr(lpReturnedString, '\n')) != NULL)
*ptr = '\0';
if( (ptr = strchr(lpReturnedString, '\r')) != NULL)
*ptr = '\0';
break;
}
}
}
}
fclose(fp);
return strlen(lpReturnedString);
}
int GetPrivateProfileInt(const char *AppName,const char *key,const int defaultvalue,const char *lpFileName)
{
char str[20];
int nRet = defaultvalue;
if(GetPrivateProfileString(AppName, key, "", str, sizeof(str), lpFileName) > 0)
{
nRet = atoi(str);
}
return nRet;
}
#endif
Mutex.h
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef PYMUTEX_H
#define PYMUTEX_H
#ifdef WIN32
//#include <windows.h>
#else
#include <pthread.h>
#endif
typedef void *HANDLE;
class IMutex
{
public:
virtual ~IMutex() {}
virtual void Lock() const = 0;
virtual bool TryLock() const = 0;
virtual void Unlock() const = 0;
};
class PYMutex : public IMutex
{
public:
PYMutex();
~PYMutex();
virtual void Lock() const;
virtual bool TryLock() const;
virtual void Unlock() const;
private:
#ifdef _WIN32
HANDLE m_mutex;
#else
mutable pthread_mutex_t m_mutex;
#endif
};
#endif //PYMUTEX_H
Mutex.cpp
#include "Mutex.h"
#ifdef WIN32
#include <windows.h>
#endif
//#include <iostream>
#include <stdio.h>
PYMutex::PYMutex()
{
#ifdef _WIN32
m_mutex = ::CreateMutex(NULL, FALSE, NULL);
#else
pthread_mutex_init(&m_mutex, NULL);
#endif
}
PYMutex::~PYMutex()
{
#ifdef _WIN32
::CloseHandle(m_mutex);
#else
pthread_mutex_destroy(&m_mutex);
#endif
}
void PYMutex::Lock() const
{
#ifdef _WIN32
//DWORD d = WaitForSingleObject(m_mutex, INFINITE);
WaitForSingleObject(m_mutex, INFINITE);
/// \todo check 'd' for result
#else
pthread_mutex_lock(&m_mutex);
#endif
}
bool PYMutex::TryLock() const
{
#ifdef _WIN32
DWORD dwWaitResult = WaitForSingleObject(m_mutex, 0);
if (dwWaitResult != WAIT_OBJECT_0 && dwWaitResult != WAIT_TIMEOUT) {
printf("thread WARNING: bad result from try-locking mutex\n");
}
return (dwWaitResult == WAIT_OBJECT_0) ? true : false;
#else
return (0==pthread_mutex_trylock(&m_mutex))?true:false;
#endif
};
void PYMutex::Unlock() const
{
#ifdef _WIN32
::ReleaseMutex(m_mutex);
#else
pthread_mutex_unlock(&m_mutex);
#endif
}
myFunc.h
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef _MYFUNC_H_
#define _MYFUNC_H_
/*
public function
*/
#include <string>
#include <vector>
namespace PFunc
{
//字符串分割
bool string_divide(std::vector<std::string> &_strlist, const std::string src, const std::string div);
//hex to ascii
int string2bytes(const char* pSrc, unsigned char* pDst, int nSrcLength);
//ascii to hex
int bytes2string(const unsigned char* pSrc, char* pDst, int nSrcLength);
//frame code
int code(const unsigned char *buff, const int len, unsigned char *outbuf);
//frame uncode
int uncode(const unsigned char *buff, int len, unsigned char *outbuf);
//
bool ipCheck(std::string ip_str);
long ipToInt(std::string ip_str);
std::string intToIp(long ip_int);
//crc
unsigned int crc16(unsigned char *ptr, unsigned int len);
//年-月-日 时:分:秒
std::string getCurrentTime();
};
#endif
myFunc.cpp
#include "myFunc.h"
#include <stdlib.h>
#ifdef WIN32
#include <Winsock2.h>
#else
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#endif
#include <time.h>
#include "Log.h"
bool PFunc::string_divide(std::vector<std::string> &_strlist, const std::string src, const std::string div)
{
std::string _src = src;
std::string::size_type _pos = _src.find(div);
while (std::string::npos != _pos)
{
std::string _buf = "";
_buf = _src.substr(0, _pos);
_strlist.push_back(_buf);
_src = _src.erase(0, _pos + div.size());
_pos = _src.find(div.c_str());
}
if (!_src.empty())
{
_strlist.push_back(_src);
}
return true;
};
int PFunc::string2bytes(const char* pSrc, unsigned char* pDst, int nSrcLength)
{
for (int i = 0; i < nSrcLength; i += 2)
{
if (*pSrc >= '0' && *pSrc <= '9')
*pDst = (*pSrc - '0') << 4;
else
*pDst = (*pSrc - 'A' + 10) << 4;
pSrc++;
// 输出低4位
if (*pSrc >= '0' && *pSrc <= '9')
*pDst |= *pSrc - '0';
else
*pDst |= *pSrc - 'A' + 10;
pSrc++;
pDst++;
}
return (nSrcLength / 2);
};
int PFunc::bytes2string(const unsigned char* pSrc, char* pDst, int nSrcLength)
{
const char tab[] = "0123456789ABCDEF"; // 0x0-0xf的字符查找表
for (int i = 0; i < nSrcLength; i++)
{
*pDst++ = tab[*pSrc >> 4];
*pDst++ = tab[*pSrc & 0x0f];
pSrc++;
}
*pDst = '\0';
return nSrcLength * 2;
};
int PFunc::code(const unsigned char *buff, const int len, unsigned char *outbuf)
{
char ch = 0;
int nLen = 0;
unsigned char * buf = (unsigned char *)buff;
*outbuf++ = 0XF1;//头字节
nLen+=1;
for (int i = 0; i < len; i++, nLen++)
{
ch = buf[i];
if ((buf[i] | 0x0f) == 0xff && i > 0 && i < (len - 1))
{
*outbuf++ = 0xf0 & buf[i];
*outbuf++ = 0x0f & buf[i];
nLen += 1;
}
else {
*outbuf++ = ch;
}
}
*outbuf++ = 0XFF;//末字节
nLen+=1;
buf = NULL;
return nLen;
}
int PFunc::uncode(const unsigned char *buff, int len, unsigned char *outbuf)
{
char ch = 0;
int nLen = 0;
unsigned char * buf = (unsigned char *)buff;
//头、末尾字节判断
if(len<=2&&0XF1!=buf[0]&&0XFF!=buf[len-1]){
printf("uncode func, start bit or end bit Error!\r\n");
return 0;
}
for (int i = 1; i < (len-1); i++, nLen++)
{
ch = buf[i];
if (buf[i] == 0xf0)
{
#ifdef _DEBUG
if (i > len - 2)
printf("Error!\r\n");
if (buf[i + 1] > 0x0f)
printf("Error!\r\n");
#endif
ch = 0xf0 | buf[++i];
}
*outbuf++ = ch;
}
buf = NULL;
return nLen;
}
bool PFunc::ipCheck(std::string ip_str)
{
if (INADDR_NONE != inet_addr(ip_str.c_str()))
{
return true;
}
return false;
};
long PFunc::ipToInt(std::string ip_str)
{
if (INADDR_NONE != inet_addr(ip_str.c_str()))
{
return ntohl(inet_addr(ip_str.c_str()));
}
else {
CLogger::createInstance()->Log(eConfigError
, "ip format [%s] error: %s %s %d,please check the file format and code!"
, ip_str.c_str(), __FILE__, __FUNCTION__, __LINE__);
return 0;
}
};
std::string PFunc::intToIp(long ip_int)
{
char ip[64] = { 0 };
#ifdef WIN32
strcpy_s(ip, inet_ntoa(*(in_addr*)&ip_int));
#else
strcpy(ip, inet_ntoa(*(in_addr*)&ip_int));
#endif
return std::string(ip);
};
//CRC校验
unsigned int PFunc::crc16(unsigned char *ptr, unsigned int len)
{
unsigned int wcrc = 0XFFFF;//预置16位crc寄存器,初值全部为1
unsigned char temp;//定义中间变量
unsigned int i = 0, j = 0;//定义计数
for (i = 0; i < len; i++)//循环计算每个数据
{
temp = *ptr & 0X00FF;//将八位数据与crc寄存器亦或
ptr++;//指针地址增加,指向下个数据
wcrc ^= temp;//将数据存入crc寄存器
for (j = 0; j < 8; j++)//循环计算数据的
{
if (wcrc & 0X0001)//判断右移出的是不是1,如果是1则与多项式进行异或。
{
wcrc >>= 1;//先将数据右移一位
wcrc ^= 0XA001;//与上面的多项式进行异或
}
else//如果不是1,则直接移出
{
wcrc >>= 1;//直接移出
}
}
}
temp = wcrc;//crc的值
return wcrc;
};
std::string PFunc::getCurrentTime()
{
time_t _t = time(NULL);
struct tm _tt;
#ifdef WIN32
localtime_s(&_tt, &_t);
#else
localtime_r(&_t, &_tt);
#endif
_tt.tm_year += 1900;
_tt.tm_mon += 1;
char buf[32] = { 0 };
sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d"
, _tt.tm_year, _tt.tm_mon, _tt.tm_mday, _tt.tm_hour, _tt.tm_min, _tt.tm_sec);
return std::string(buf);
}
myThread.h
#ifndef _MYTHREAD_H
#define _MYTHREAD_H
/***********************************************************************
*Copyright 2023-02-06, pyfree
*
*File Name : myThread.h
*File Mark :
*Summary :
*支持windows和linux的线程类,提供基本的线程功能(循环、启动、退出)
*
*Current Version : 1.00
*Author : pyfree
*FinishDate :
*
*Replace Version :
*Author :
*FinishDate :
************************************************************************/
#ifdef WIN32
#include <process.h>
#include <iostream>
typedef void* HANDLE_THREAD;
#else
#include <pthread.h>
#include <unistd.h>
typedef pthread_t HANDLE_THREAD;
#endif
class MyThread
{
public://func
MyThread(); // constructed function
~MyThread();
/**
* the entity for thread running
* @param null {void } 无参数
* @return {int} 运行返回结果
*/
virtual int Run()=0;
/**
* start thread
* @param null {void } 无参数
* @return {bool} 是否启动成功
*/
bool start();
/**
* get thread ID
* @param null {void } 无参数
* @return {HANDLE_THREAD} 线程句柄
*/
HANDLE_THREAD getThreadID();
#ifdef __linux__
//get thread status
int getState();
//wait for thread end
void join();
//wait for thread end in limit time
void join(unsigned long millisTime);
#endif
public://val
#ifdef __linux__
//threadStatus-new create
static const int THREAD_STATUS_NEW = 0;
//threadStatus-running
static const int THREAD_STATUS_RUNNING = 1;
//threadStatus-end
static const int THREAD_STATUS_EXIT = -1;
#endif
private://func
#ifdef WIN32
static void agent(void *p);
#else
//get manner pointer of execution
static void* run0(void* pVoid);
//manner of execution inside
void* run1();
#endif
private://val
HANDLE_THREAD hThread;
#ifdef __linux__
//thread status
int threadStatus;
#endif
};
#endif /* _MYTHREAD_H */
myThread.cpp
#include "myThread.h"
#ifdef WIN32
#include <windows.h>
#else
#include <stdio.h>
#endif
MyThread::MyThread()
{
#ifdef __linux__
hThread = 0;
threadStatus = THREAD_STATUS_NEW;
#endif
}
MyThread::~MyThread()
{
#ifdef WIN32
WaitForSingleObject(hThread, INFINITE);
#else
join(10);
#endif
}
int MyThread::Run()
{
#ifdef WIN32
printf("Base Thread\n");
#else
while(true){
printf("thread is running!\n");
sleep(100);
}
#endif
return 0;
}
bool MyThread::start()
{
#ifdef WIN32
return NULL!=(hThread =(HANDLE_THREAD)_beginthread(agent, 0, (void *)this));
#else
return pthread_create(&hThread, NULL, run0, this) == 0;
#endif
}
HANDLE_THREAD MyThread::getThreadID()
{
return hThread;
}
#ifdef WIN32
void MyThread::agent(void *p)
{
MyThread *agt = (MyThread *)p;
agt->Run();
}
#else
void* MyThread::run0(void* pVoid)
{
MyThread* p = (MyThread*) pVoid;
p->run1();
return p;
}
void* MyThread::run1()
{
threadStatus = THREAD_STATUS_RUNNING;
hThread = pthread_self();
Run();
threadStatus = THREAD_STATUS_EXIT;
hThread = 0;
pthread_exit(NULL);
}
int MyThread::getState()
{
return threadStatus;
}
void MyThread::join()
{
if (hThread > 0)
{
pthread_join(hThread, NULL);
}
}
void MyThread::join(unsigned long millisTime)
{
if (hThread == 0)
{
return;
}
if (millisTime == 0)
{
join();
}else
{
unsigned long k = 0;
while (threadStatus != THREAD_STATUS_EXIT && k <= millisTime)
{
usleep(100);
k++;
}
}
}
#endif
queuedata.h
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef _QUEUE_DATA_H_
#define _QUEUE_DATA_H_
/***********************************************************************
*Copyright 2023-02-06, pyfree
*
*File Name : queuedata.h
*File Mark :
*Summary :
*数据队列类,线程安全
*
*Current Version : 1.00
*Author : pyfree
*FinishDate :
*
*Replace Version :
*Author :
*FinishDate :
************************************************************************/
#include <deque>
#include <stdio.h>
#include <string.h>
#include "Mutex.h"
#include "Log.h"
template <class T>
class QueueData
{
public:
QueueData(std::string desc = "thread_queue");
~QueueData();
//
/**
* 获取队列大小
* @return {int } 队列大小
*/
int size();
/**
* 判定队列是否为空
* @return {bool } 是否为空队列
*/
bool isEmpty();
/**
* 获取队列头元素
* @param it {T&} 头元素
* @return {bool } 是否成功
*/
bool getFirst(T &it);
/**
* 删除元素
* @return {bool } 是否成功
*/
bool removeFirst();
/**
* 获取队列头元素,并从队列终删除
* @param it {T&} 头元素
* @return {bool } 是否成功
*/
bool pop(T &it);
/**
* 从队列头开始逐步获取多个元素,并剔除
* @param its {queue<T>&} 获取到的元素集
* @param sizel {int} 一次获取多少个
* @return {bool } 至少获取一个元素以上则成功
*/
bool getList(std::queue<T> &its,unsigned int sizel=5);
/**
* 从队列尾部添加元素
* @param it {T} 被添加元素
* @return {void } 无返回
*/
void add(T it);
/**
* 从队列头部添加元素
* @param it {T} 被添加元素
* @return {void } 无返回
*/
void add_front(T it);
/**
* 清空元素
* @return {void }
*/
void clear();
private:
void init();
QueueData& operator=(const QueueData&) {return this;};
protected:
std::string queue_desc;
private:
/点集转发
//协议解析结果缓存
std::deque<T> datacache_queue; //队列容器
PYMutex m_Mutex; //线程锁,或者如果更彻底采用acl库,采用acl::thread_mutex替代
//
static unsigned int QSize; //队列大小约束,超出是会从队列头剔除旧数据腾出空位在对末添加数据
//
int queue_overS; //队列溢出次数计数
};
template <class T>
unsigned int QueueData<T>::QSize = 100;
template <class T>
QueueData<T>::QueueData(std::string desc)
: queue_desc(desc)
{
init();
};
template <class T>
void QueueData<T>::init()
{
queue_overS = 0;
};
template <class T>
QueueData<T>::~QueueData()
{
}
//
template <class T>
int QueueData<T>::size()
{
int ret = 0;
m_Mutex.Lock();
ret = static_cast<int>(datacache_queue.size());
m_Mutex.Unlock();
return ret;
}
template <class T>
bool QueueData<T>::isEmpty()
{
bool ret = false;
m_Mutex.Lock();
ret = datacache_queue.empty();
m_Mutex.Unlock();
return ret;
}
template <class T>
bool QueueData<T>::getFirst(T &it)
{
bool ret = false;
m_Mutex.Lock();
if (!datacache_queue.empty())
{
it = datacache_queue.front();
ret = true;
}
m_Mutex.Unlock();
return ret;
}
template <class T>
bool QueueData<T>::removeFirst()
{
bool ret = false;
m_Mutex.Lock();
if (!datacache_queue.empty())
{
datacache_queue.pop_front();
ret = true;
}
m_Mutex.Unlock();
return ret;
}
template <class T>
bool QueueData<T>::pop(T &it)
{
bool ret = false;
m_Mutex.Lock();
if (!datacache_queue.empty())
{
it = datacache_queue.front();
datacache_queue.pop_front();
ret = true;
}
m_Mutex.Unlock();
return ret;
};
template <class T>
bool QueueData<T>::getList(std::queue<T> &its,unsigned int sizel)
{
m_Mutex.Lock();
while (!datacache_queue.empty())
{
its.push(datacache_queue.front());
datacache_queue.pop_front();
if (its.size() >= sizel)
{
break;
}
}
m_Mutex.Unlock();
return !its.empty();
};
template <class T>
void QueueData<T>::add(T it)
{
m_Mutex.Lock();
if (datacache_queue.size() > QSize)
{
queue_overS++;
datacache_queue.pop_front();
}
datacache_queue.push_back(it);
m_Mutex.Unlock();
if (queue_overS >= 10)
{
//每溢出10次,报告一次
CLogger::createInstance()->Log(eSoftError
,"add item to queue %s at end,but the size of QueueData is up to limmit size: %d.\n"
, queue_desc.c_str(), QSize);
queue_overS = 0;
}
}
template <class T>
void QueueData<T>::add_front(T it)
{
m_Mutex.Lock();
if (datacache_queue.size() > QSize)
{
queue_overS++;
datacache_queue.pop_front();
}
datacache_queue.push_front(it);
m_Mutex.Unlock();
if (queue_overS >= 10)
{
//每溢出10次,报告一次
CLogger::createInstance()->Log(eSoftError,
"add item to queue %s at first,but the size of QueueData is up to limmit size: %d.\n"
, queue_desc.c_str(), QSize);
queue_overS = 0;
}
}
template <class T>
void QueueData<T>::clear()
{
m_Mutex.Lock();
datacache_queue.clear();
m_Mutex.Unlock();
queue_overS = 0;
}
#endif //_QUEUE_DATA_H_
5.2 socket_io目录
MyThread.h
/***********************************************************************
*Copyright 2023-01-27, Zhuhai Singyes Applied Materials Technology Co., Ltd.
*
*File Name : MySocket.h
*File Mark :
*Summary : TCP communication which is to achieve by CSocket API
*
*Current Version : 1.00
*Author : PengYong
*FinishDate :
*
*Replace Version :
*Author :
*FinishDate :
************************************************************************/
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef _MySocket_H_
#define _MySocket_H_
#include "DataDef.h"
class MySocketPrivate;
class MySocketRD;
class MySocketWD;
#ifdef _SERVERIO_
/*
*建立socket服务端
*/
class MySocketSrv;
#else
/*
*建立socket客户端
*/
#include <string>
#endif
class MySocket
{
public:
MySocket(NetArg _netarg);
virtual ~MySocket(void);
public:
virtual int Read(){ return -1; };
virtual int Write(){ return -1; };
//
//int Read(char* buf, int size);
int Write(const char* buf, int size);
private:
#ifdef _SERVERIO_
MySocketSrv *my_SocketSrv;
#else
NetArg netarg;
#endif
MySocketPrivate *my_PrivateData;
MySocketRD *m_MySocketRD;
MySocketWD *m_MySocketWD;
};
#endif //_MYSOCKET_H_
MyThread.cpp
#include "MySocket.h"
#include "MySocketPrivate.h"
#include "MySocketWD.h"
#include "MySocketRD.h"
#include "Log.h"
#ifdef _SERVERIO_
#include "MySocketSrv.h"
#endif
*MySocket*///
MySocket::MySocket(NetArg _netarg)
{
try {//防止构造时异常出现内存泄漏
#ifdef _SERVERIO_
my_PrivateData = new MySocketPrivate(_netarg.port);
#else
netarg = _netarg;
//TCP/IP客户端,连接监控服务或其他平台
my_PrivateData = new MySocketPrivate( netarg.port, netarg.ipStr);
#endif
if (my_PrivateData->onConnect() <= 0)
{
#ifdef _SERVERIO_
my_SocketSrv = NULL;
m_MySocketRD = NULL;
m_MySocketWD = NULL;
CLogger::createInstance()->Log(eSoftError,
"listen port(%u) error, [%s %s %d]"
, _netarg.port
, __FILE__, __FUNCTION__, __LINE__);
#else
CLogger::createInstance()->Log(eSoftError,
"connect server[%s,%d] error,please check it,[%s %s %d]!"
, netarg.ipStr.c_str(), netarg.port
, __FILE__, __FUNCTION__, __LINE__);
#endif
}
else
{
#ifdef _SERVERIO_
my_SocketSrv = new MySocketSrv();
my_SocketSrv->setPDataPtr(my_PrivateData);
my_SocketSrv->start();
#endif
//数据接收线程
m_MySocketRD = new MySocketRD(my_PrivateData, _netarg.type);
m_MySocketRD->start();
//数据发送线程
m_MySocketWD = new MySocketWD(my_PrivateData, _netarg.type);
m_MySocketWD->start();
}
}
catch (...) {
#ifdef _SERVERIO_
delete my_SocketSrv;
my_SocketSrv = NULL;
#endif
delete m_MySocketRD;
m_MySocketRD = NULL;
delete m_MySocketWD;
m_MySocketWD = NULL;
delete my_PrivateData;
my_PrivateData = NULL;
CLogger::createInstance()->Log(eSoftError,
"MySocket init error, [%s %s %d]"
, __FILE__, __FUNCTION__, __LINE__);
}
};
MySocket::~MySocket(void)
{
#ifdef _SERVERIO_
if (NULL != my_SocketSrv)
{
delete my_SocketSrv;
my_SocketSrv = NULL;
}
#endif
if (NULL != m_MySocketRD)
{
delete m_MySocketRD;
m_MySocketRD = NULL;
}
if (NULL != m_MySocketWD)
{
delete m_MySocketWD;
m_MySocketWD = NULL;
}
if(NULL!=my_PrivateData)
{
delete my_PrivateData;
my_PrivateData = NULL;
}
};
int MySocket::Write(const char* buf, int size)
{
if (size <= 0|| NULL == buf ||NULL == m_MySocketWD)
{
return -1;
}
return m_MySocketWD->add_data(buf, size);
};
MySocketPrivate.h
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef _MYSOCKETPRIVATE_H_
#define _MYSOCKETPRIVATE_H_
#ifdef WIN32
#include "afxsock.h"
#endif
#ifdef __linux__
#include <string.h>
#include <stdio.h>
#endif
#ifdef _SERVERIO_
#include <map>
#include <queue>
#include <set>
#ifdef WIN32
#define MY_SOCKET SOCKET
#define MY_SOCKET_NULL NULL
#endif //WIN32
#ifdef __linux__
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define printf_s printf
#define sprintf_s sprintf
#define MY_SOCKET int
#define MY_SOCKET_NULL (-1)
#endif //__linux__
#include "Mutex.h"
#include "hashmap.h"
#else //_SERVERIO_
#ifdef WIN32
#endif //WIN32
#ifdef __linux__
#endif //__linux__
#endif //_SERVERIO_
#include <string>
#include "DataDef.h"
class MySocketPrivate
{
public:
MySocketPrivate(unsigned int port,std::string ip="127.0.0.1");
~MySocketPrivate();
public:
int onConnect();
void disConnect();
#ifdef _SERVERIO_
int Read(std::map<KeyObj_Client,TCP_Data<RDC_SIZE> > &bufs);
int Write(unsigned long long ipInt,const char* buf, int size);
bool Accept();
bool get_ipInt_list(std::set<long> &ipintlist); //获取在线端的整型IP
#else
bool isConnect(){ return m_OnConnect; };
int reSetSocket();
int Read(TCP_Data<RDC_SIZE> &bufs);
int Read(char* buf, int size);
#endif
int Write(const char* buf, int size);
#ifdef WIN32
private:
void SocketThreadInit();
#endif
#ifdef _SERVERIO_
private:
void deleteSSocket(); //删除服务端
void deleteCSocket(); //删除所有客户端
void deleteCSocket(MY_SOCKET m_CSocket);//删除指定客户端
#endif
private:
unsigned int m_Port; //端口变量
#ifdef _SERVERIO_
MY_SOCKET m_SSocket; //服务端
bool m_OnListen; //用于标注侦听
PYMutex m_MyMutex;
std::map<KeyObj_Client,MY_SOCKET> m_CSockets; //绑定客户端
#else
std::string m_IpAddress; //网络地址
int sock_fd;
bool m_OnConnect; //链接状态
bool m_OnConnecting; //当前写入失败及读取线程都可重新建立链接,m_OnConnecting设置防止冲突
bool m_ConnectONLog; //防止链接错误日志反复记录,切换状态时必定记录
unsigned int m_log_Interval; //防止链接错误日志长时间不记录,2018-10-08
#endif
};
#endif //_MYSOCKETPRIVATE_H_
MySocketPrivate.cpp
#include "MySocketPrivate.h"
#ifdef _SERVERIO_
#include "myFunc.h"
#else
#ifdef WIN32
#include <mstcpip.h>
#endif //WIN32
#endif //_SERVERIO_
#ifdef __linux__
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <errno.h>
#define printf_s printf
#define sprintf_s sprintf
#pragma message("def printf_s from printf And def sprintf_s from sprintf")
#endif
#include "Log.h"
#ifdef WIN32
void MySocketPrivate::SocketThreadInit()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0)
{
//printf("WSAStartup failed with error: %d\n", err);
CLogger::createInstance()->Log(eSoftError,
"WSAStartup failed with error: %d, [%s %s %d]"
, err
, __FILE__, __FUNCTION__, __LINE__);
return;
}
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
//printf("Could not find a usable version of Winsock.dll\n");
CLogger::createInstance()->Log(eSoftError,
"Could not find a usable version of Winsock.dll: [%s %s %d]"
, __FILE__, __FUNCTION__, __LINE__);
WSACleanup();
return;
}
else {
printf("The Winsock 2.2 dll was found okay\n");
}
}
#endif
MySocketPrivate::MySocketPrivate(unsigned int port,std::string ip)
: m_Port(port)
#ifdef _SERVERIO_
, m_OnListen(false)
#else
, m_IpAddress(ip)
#endif
{
#ifdef _SERVERIO_
m_SSocket = MY_SOCKET_NULL;
m_CSockets.clear();
#else
sock_fd = -1;
#endif
#ifdef WIN32
/*
* This function should be called once in each secondary thread
* before the first socket is created in the new thread.
*/
SocketThreadInit();
#endif
#ifndef _SERVERIO_
m_OnConnect = false;
m_OnConnecting = false;
m_ConnectONLog = true;
m_log_Interval = static_cast<unsigned int>(time(NULL));
#endif
};
MySocketPrivate::~MySocketPrivate()
{
disConnect();
};
#ifdef _SERVERIO_
int MySocketPrivate::onConnect()
{
if (m_OnListen) //服务器Socket是否已经创建
{
//printf_s("it's has been Listten! \r\n");
CLogger::createInstance()->Log(eTipMessage,
"it's has been Listten, [%s %s %d]!"
, __FILE__, __FUNCTION__, __LINE__);
return 1;
}
else {
#ifdef WIN32
m_SSocket = socket(AF_INET, SOCK_STREAM, 0);
SOCKADDR_IN addrServ;
addrServ.sin_family = AF_INET;
addrServ.sin_port = htons(m_Port);
addrServ.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
bind(m_SSocket, (SOCKADDR*)&addrServ, sizeof(SOCKADDR));
/*
*3.在send(),recv()过程中有时由于网络状况等原因,收发不能预期进行,可以设置收发时限:
*int nNetTimeout = 1000; //1秒
*发送时限
*setsockopt( socket, SOL_SOCKET, SO_SNDTIMEO, ( char * )&nNetTimeout, sizeof( int ) );
*接收时限
*setsockopt( socket, SOL_SOCKET, SO_RCVTIMEO, ( char * )&nNetTimeout, sizeof( int ) );
*4.在send()的时候,返回的是实际发送出去的字节(同步)或发送到socket缓冲区的字节(异步);系统默认的状态发送和接收一次为8688字节(约
*为8.5K);在实际的过程中如果发送或是接收的数据量比较大,可以设置socket缓冲区,避免send(),recv()不断的循环收发:
* 接收缓冲区
*int nRecvBufLen = 32 * 1024; //设置为32K
*setsockopt( s, SOL_SOCKET, SO_RCVBUF, ( const char* )&nRecvBufLen, sizeof( int ) );
*发送缓冲区
*int nSendBufLen = 32*1024; //设置为32K
*setsockopt( s, SOL_SOCKET, SO_SNDBUF, ( const char* )&nSendBufLen, sizeof( int ) );
*5.在发送数据的时,不执行由系统缓冲区到socket缓冲区的拷贝,以提高程序的性能:
*int nZero = 0;
*setsockopt( socket, SOL_SOCKET, SO_SNDBUF, ( char * )&nZero, sizeof( nZero ) );
*6.在接收数据时,不执行将socket缓冲区的内容拷贝到系统缓冲区:
*int nZero = 0;
*setsockopt( s, SOL_SOCKET, SO_RCVBUF, ( char * )&nZero, sizeof( int ) );
*/
//如果创建Socket失败则提示,成功则开始监听
if (listen(m_SSocket, 20) == SOCKET_ERROR)
{
closesocket(m_SSocket);
//printf_s("ServerSocket Create failed! error:%d \r\n",static_cast<int>(GetLastError()));
CLogger::createInstance()->Log(eParameterError,
"ServerSocket Create failed! error:%d, [%s %s %d]"
, static_cast<int>(GetLastError())
, __FILE__, __FUNCTION__, __LINE__);
return -1;
}
else {
CLogger::createInstance()->Log(eTipMessage, "on listen port(%d)", m_Port);
m_OnListen = true;
return 1;
}
#else
m_SSocket = socket(AF_INET, SOCK_STREAM, 0);
if (MY_SOCKET_NULL == m_SSocket)
{
CLogger::createInstance()->Log(eSoftError,
"socket create fail ![%s %s %d]!"
, __FILE__, __FUNCTION__, __LINE__);
return -1;
}
struct sockaddr_in s_add;
bzero(&s_add, sizeof(struct sockaddr_in));
s_add.sin_family = AF_INET;
s_add.sin_addr.s_addr = htonl(INADDR_ANY);
s_add.sin_port = htons(m_Port);
if (-1 == bind(m_SSocket, (struct sockaddr *)(&s_add), sizeof(struct sockaddr)))
{
CLogger::createInstance()->Log(eSoftError,
"socket bind fail, %d ![%s %s %d]",m_Port
, __FILE__, __FUNCTION__, __LINE__);
return -1;
}
else {
CLogger::createInstance()->Log(eTipMessage,
"bind success, %d! [%s %s %d]!",m_Port
, __FILE__, __FUNCTION__, __LINE__);
}
if (-1 == listen(m_SSocket, 5))
{
CLogger::createInstance()->Log(eSoftError,
"listen %d fail ![%s %s %d]",m_Port
, __FILE__, __FUNCTION__, __LINE__);
return -1;
}
else {
CLogger::createInstance()->Log(eTipMessage,
"listen success, %d ! [%s %s %d]!",m_Port
, __FILE__, __FUNCTION__, __LINE__);
}
m_OnListen = true;
return 1;
#endif
}
}
bool MySocketPrivate::Accept()
{
bool bRet = true;
if (m_OnListen)
{
#ifdef WIN32
SOCKADDR_IN cliAddr;
int length = sizeof(SOCKADDR);
SOCKET cliSock = accept(m_SSocket, (SOCKADDR*)&cliAddr, &length);
if (INVALID_SOCKET == cliSock)
{
closesocket(cliSock);
//printf_s("Connect Accept Failed: %d! \r\n",static_cast<int>(GetLastError()));
CLogger::createInstance()->Log(eSoftError,
"Connect Accept Failed: %d! , [%s %s %d]"
, static_cast<int>(GetLastError())
, __FILE__, __FUNCTION__, __LINE__);
bRet = false;
}
else {
//cliAddr.sin_addr.S_un.S_addr;
char _ipport[64] = { 0 };
//sprintf_s(_ipport,"%s",(char*)inet_ntoa((*(in_addr*)&(cliAddr.sin_addr))));
sprintf_s(_ipport, "%s:%d", (char*)inet_ntoa((*(in_addr*)&(cliAddr.sin_addr))), cliAddr.sin_port);
//std::string _linkInfo = _ipport;
KeyObj_Client _linkInfo((char*)inet_ntoa((*(in_addr*)&(cliAddr.sin_addr))), cliAddr.sin_port);
int nNetTimeout = 100; //1秒
//setsockopt(cliSock, SOL_SOCKET, SO_SNDTIMEO, (char *)&nNetTimeout, sizeof(int));
setsockopt(cliSock, SOL_SOCKET, SO_RCVTIMEO, (char *)&nNetTimeout, sizeof(int));
m_MyMutex.Lock();
m_CSockets[_linkInfo] = cliSock;//添加客户端
m_MyMutex.Unlock();
//printf_s("Connect Accept Success: %s \r\n", _ipport);
CLogger::createInstance()->Log(eTipMessage,
"Connect Accept Success: %s,[%s %s %d]"
, _ipport
, __FILE__, __FUNCTION__, __LINE__);
}
#else
int sin_size = sizeof(struct sockaddr_in);
struct sockaddr_in c_add;
// printf("MySocketPrivate::Accept 1\n");
int nfp = accept(m_SSocket, (struct sockaddr *)(&c_add), (socklen_t*)&sin_size);
if (-1 == nfp)
{
//printf("accept fail !\r\n");
CLogger::createInstance()->Log(eParameterError,
"accept fail![%s %s %d]"
, __FILE__, __FUNCTION__, __LINE__);
bRet = false;
}
else {
char _ipport[64] = { 0 };
std::string _ipStr = inet_ntoa((*(in_addr*)&(c_add.sin_addr)));
//std::string _ipStr = PFunc::intToIp(htonl(c_add.sin_addr.s_addr));
int _port = static_cast<int>(htons(c_add.sin_port));
sprintf(_ipport, "%s:%d", _ipStr.c_str(), _port);
/*
struct timeval timeout = {3,0};
//setsockopt(nfp,SOL_SOCKET,SO_SNDTIMEO,(char *)&timeout,sizeof(struct timeval));
setsockopt(nfp,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout,sizeof(struct timeval));
KeyObj_Client _linkInfo((char*)inet_ntoa((*(in_addr*)&(c_Addr.sin_addr))), cliAddr.sin_port);
*/
int x = fcntl(nfp, F_GETFL, 0);
fcntl(nfp, F_SETFL, x | O_NONBLOCK);
KeyObj_Client _linkInfo(_ipStr, _port);
m_MyMutex.Lock();
//nfps.push_back(nfp);
//nfps[KeyObj_Client(_ipStr, _port)] = nfp;
m_CSockets[_linkInfo] = nfp;
m_MyMutex.Unlock();
//printf("accept ok!\r\nServer start get connect from %s\r\n", _ipport);
CLogger::createInstance()->Log(eTipMessage,
"accept ok!\r\nServer start get connect from %s.[%s %s %d]"
, _ipport
, __FILE__, __FUNCTION__, __LINE__);
}
#endif
}
else {
bRet = false;
//printf_s("m_OnListen is false, please check Listen state, Accept error \r\n");
CLogger::createInstance()->Log(eTipMessage,
"m_OnListen is false, please check Listen state, Accept error,[%s %s %d]"
, __FILE__, __FUNCTION__, __LINE__);
}
return bRet;
};
bool MySocketPrivate::get_ipInt_list(std::set<long> &ipintlist)
{
for (std::map<KeyObj_Client, MY_SOCKET>::iterator it = m_CSockets.begin();it!= m_CSockets.end();it++)
{
ipintlist.insert(it->first.m_ip);
}
return !ipintlist.empty();
}
void MySocketPrivate::disConnect()
{
deleteCSocket();//删除客户端
deleteSSocket();//删除服务端
#ifdef WIN32
WSACleanup();
#endif
CLogger::createInstance()->Log(eTipMessage,
"socket disConnect success and exit: [%s %s %d]!"
, __FILE__, __FUNCTION__, __LINE__);
}
void MySocketPrivate::deleteCSocket()
{
m_MyMutex.Lock();
std::map<KeyObj_Client, MY_SOCKET>::iterator it = m_CSockets.begin();
while (it != m_CSockets.end())
{
//删除链接
deleteCSocket(it->second);
#ifdef WIN32
it = m_CSockets.erase(it);
#else
std::map<KeyObj_Client, MY_SOCKET>::iterator ittemp = it++;
m_CSockets.erase(ittemp);
#endif
}
m_MyMutex.Unlock();
}
void MySocketPrivate::deleteCSocket(MY_SOCKET m_CSocket)
{
try {
if (MY_SOCKET_NULL != m_CSocket)
{
#ifdef WIN32
closesocket(m_CSocket);
#else
close(m_CSocket);
#endif
m_CSocket = MY_SOCKET_NULL;
}
}
catch (...) {
CLogger::createInstance()->Log(eSoftError,
"socket deleteCSocket exception and failed! [%s %s %d]!"
, __FILE__, __FUNCTION__, __LINE__);
}
}
void MySocketPrivate::deleteSSocket()
{
m_OnListen = false;
try {
if (MY_SOCKET_NULL != m_SSocket)
{
#ifdef WIN32
closesocket(m_SSocket);
#else
close(m_SSocket);
#endif
m_SSocket = MY_SOCKET_NULL;
}
}
catch (...) {
CLogger::createInstance()->Log(eSoftError,
"socket deleteSSocket exception and failed! [%s %s %d]!"
, __FILE__, __FUNCTION__, __LINE__);
}
};
//return success read count
int MySocketPrivate::Read(std::map<KeyObj_Client, TCP_Data<RDC_SIZE> > &bufs)
{
int ret = 0;
m_MyMutex.Lock();
std::map<KeyObj_Client, MY_SOCKET>::iterator it = m_CSockets.begin();
while (it != m_CSockets.end())
{
char _buf[512] = { 0 };
#ifdef WIN32
int re_one = recv(it->second, _buf, 512, 0);
if (re_one <= 0)
{
int _error = GetLastError();
if (_error != 10060)
{
//printf_s("read data failed from %s! return val is %d. \r\n", it->first.c_str(), re);
CLogger::createInstance()->Log(eReadError,
"read data failed from %s! return val is %d,error(%d).[%s %s %d]"
, it->first.m_ipStr.c_str(), re_one, _error
, __FILE__, __FUNCTION__, __LINE__);
//删除链接
deleteCSocket(it->second);
it = m_CSockets.erase(it);
continue;
}
else {
re_one = 0;
}
}
#else
int re_one = recv(it->second, _buf, 256, MSG_DONTWAIT);
if (re_one <= 0)
{
if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)
{
usleep(10);
re_one = 0;
}
else {
CLogger::createInstance()->Log(eReadError,
"read data failed from %s! return val is %d.[%s %s %d]"
, it->first.m_ipStr.c_str(), re_one
, __FILE__, __FUNCTION__, __LINE__);
//删除连接
deleteCSocket(it->second);
std::map<KeyObj_Client, MY_SOCKET>::iterator ittemp = it++;
m_CSockets.erase(ittemp);
continue;
}
}
#endif
if (re_one>0)
{
ret += 1;
std::map<KeyObj_Client, TCP_Data<RDC_SIZE> >::iterator itrd = bufs.find(it->first);
if (itrd != bufs.end())
{
itrd->second.add((unsigned char*)_buf, re_one);
}
else {
bufs[it->first] = TCP_Data<RDC_SIZE>((unsigned char*)_buf, re_one);
}
}
it++;
}
m_MyMutex.Unlock();
return ret;
};
//return success count
int MySocketPrivate::Write(const char* buf, int size)
{
int ret = 0;
m_MyMutex.Lock();
std::map<KeyObj_Client, MY_SOCKET>::iterator it = m_CSockets.begin();
while (it != m_CSockets.end())
{
// printf_s("write data %d to client is started!\r\n",size);
#ifdef WIN32
int re = send(it->second, buf, size, 0);
if (re <= 0)
{
int _error = GetLastError();
if (_error != 10060)
{
CLogger::createInstance()->Log(eWriteError,
"socket write data failed! return val is %d,%s.[%s %s %d]"
, re, buf
, __FILE__, __FUNCTION__, __LINE__);
//删除连接
deleteCSocket(it->second);
it = m_CSockets.erase(it);
continue;
}
else {
re = 0;
}
}
#else
int re = send(it->second, buf, size, MSG_DONTWAIT);
if (re <= 0)
{
if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)
{
usleep(10);
re = 0;
}
else {
CLogger::createInstance()->Log(eWriteError,
"Write Data Failed! error(%d,%s)! [%s %s %d]"
, errno, strerror(errno)
, __FILE__, __FUNCTION__, __LINE__);
//删除连接
deleteCSocket(it->second);
std::map<KeyObj_Client, MY_SOCKET>::iterator ittemp = it++;
m_CSockets.erase(ittemp);
continue;
}
}
#endif
else{
ret += 1;
}
it++;
}
m_MyMutex.Unlock();
return ret;
};
//return success count
int MySocketPrivate::Write(unsigned long long ipInt, const char* buf, int size)
{
int ret = 0;
m_MyMutex.Lock();
std::map<KeyObj_Client, MY_SOCKET>::iterator it = m_CSockets.begin();
while (it != m_CSockets.end())
{
// printf_s("write data %d to client is started!\r\n",size);
//当前版本只针对网络地址做判断,即一台电脑多个客户端连接,都会被发送数据
if ((unsigned long long)it->first.m_ip == ipInt)
{
#ifdef WIN32
int re = send(it->second, buf, size, 0);
if (re < 0)
{
int _error = GetLastError();
if (_error != 10060)
{
CLogger::createInstance()->Log(eWriteError,
"socket write data failed! return val is %d,%s.[%s %s %d]"
, re, buf
, __FILE__, __FUNCTION__, __LINE__);
//删除连接
deleteCSocket(it->second);
it = m_CSockets.erase(it);
continue;
}
else {
re = 0;
}
}
#else
int re = send(it->second, buf, size, MSG_DONTWAIT);
if (re <= 0)
{
if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)
{
usleep(10);
re = 0;
}
else {
CLogger::createInstance()->Log(eWriteError,
"Write Data Failed! error(%d,%s)! [%s %s %d]"
, errno, strerror(errno)
, __FILE__, __FUNCTION__, __LINE__);
//删除连接
deleteCSocket(it->second);
std::map<KeyObj_Client, MY_SOCKET>::iterator ittemp = it++;
m_CSockets.erase(ittemp);
continue;
}
}
#endif
else {
ret += 1;
}
}
it++;
}
m_MyMutex.Unlock();
return ret;
}
#else //_SERVERIO_
int MySocketPrivate::onConnect()
{
if (m_OnConnect) //
{
CLogger::createInstance()->Log(eTipMessage,
"it is on connecting,Please disconnect!, [%s %s %d]!"
, __FILE__, __FUNCTION__, __LINE__);
return 0;
}
//防止链接冲突调用
if (m_OnConnecting)
{
return 0;
}
try {
m_OnConnecting = true;
#ifdef WIN32
sock_fd = static_cast<int>(socket(AF_INET, SOCK_STREAM, 0));
SOCKADDR_IN ser_addr;
memset(&ser_addr, 0, sizeof(ser_addr));
ser_addr.sin_family = AF_INET;
ser_addr.sin_addr.s_addr = inet_addr(m_IpAddress.c_str());
ser_addr.sin_port = htons(static_cast<unsigned short>(m_Port));
if (connect(sock_fd, (struct sockaddr *)&ser_addr, sizeof(ser_addr)) < 0)
{
//printf("%s:%d, connect socket failed,%s:%d \r\n", __FILE__, __LINE__,m_IpAddress.c_str(),m_Port);
if (m_ConnectONLog|| m_log_Interval < static_cast<unsigned int>(time(NULL)))
{
m_ConnectONLog = false;
m_log_Interval = static_cast<unsigned int>(time(NULL)) + 3600;
CLogger::createInstance()->Log(eConfigError,
"connect socket failed,%s:%d, [%s %s %d]"
, m_IpAddress.c_str(), m_Port
, __FILE__, __FUNCTION__, __LINE__);
}
m_OnConnecting = false;
return -1;
}
printf("connect socket %s:%d !\r\n", m_IpAddress.c_str(), m_Port);
CLogger::createInstance()->Log(eTipMessage,
"connect socket %s:%d, [%s %s %d]!"
, m_IpAddress.c_str(), m_Port
, __FILE__, __FUNCTION__, __LINE__);
int nNetTimeout = 10; //10毫秒
setsockopt(sock_fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&nNetTimeout, sizeof(int));
setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&nNetTimeout, sizeof(int));
//KeepAlive
bool bKeepAlive = true;
int nRet = setsockopt(sock_fd, SOL_SOCKET, SO_KEEPALIVE,(char*)&bKeepAlive, sizeof(bKeepAlive));
if (nRet == SOCKET_ERROR)
{
CLogger::createInstance()->Log(eTipMessage
, "connect socket %s:%d and setsockopt(SO_KEEPALIVE=true) fail!"
, m_IpAddress.c_str(), m_Port);
}
// set KeepAlive parameter
tcp_keepalive alive_in;
tcp_keepalive alive_out;
alive_in.keepalivetime = 1000; // 1s
alive_in.keepaliveinterval = 3000; //3s
alive_in.onoff = true;
unsigned long ulBytesReturn = 0;
nRet = WSAIoctl(sock_fd, SIO_KEEPALIVE_VALS, &alive_in, sizeof(alive_in),
&alive_out, sizeof(alive_out), &ulBytesReturn, NULL, NULL);
if (nRet == SOCKET_ERROR)
{
CLogger::createInstance()->Log(eTipMessage
, "connect socket %s:%d and setsockopt(tcp_keepalive) fail!"
, m_IpAddress.c_str(), m_Port);
}
m_OnConnect = true;
m_OnConnecting = false;
m_ConnectONLog = true;
return 1;
#else
sock_fd = socket(PF_INET, SOCK_STREAM, 0);
//sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == sock_fd)
{
CLogger::createInstance()->Log(eTipMessage,
"socket fail!, [%s %s %d]!"
, __FILE__, __FUNCTION__, __LINE__);
m_OnConnecting = false;
return -1;
}
//printf("socket ok !\r\n");
CLogger::createInstance()->Log(eTipMessage,
"socket ok !, [%s %s %d]!"
, __FILE__, __FUNCTION__, __LINE__);
struct sockaddr_in s_add;
bzero(&s_add, sizeof(struct sockaddr_in));
s_add.sin_family = PF_INET;
s_add.sin_addr.s_addr = inet_addr(m_IpAddress.c_str());
s_add.sin_port = htons(m_Port);
printf("s_addr = %#x ,port : %#x\r\n", s_add.sin_addr.s_addr, s_add.sin_port);
CLogger::createInstance()->Log(eTipMessage,
"s_addr = %#x ,port : %#x, [%s %s %d]"
, s_add.sin_addr.s_addr, s_add.sin_port
, __FILE__, __FUNCTION__, __LINE__);
//int x=fcntl(sock_fd,F_GETFL,0);
//fcntl(sock_fd,F_SETFL,x | O_NONBLOCK);
if (-1 == connect(sock_fd, (struct sockaddr *)(&s_add), sizeof(struct sockaddr)))
{
if (m_ConnectONLog)
{
m_ConnectONLog = false;
CLogger::createInstance()->Log(eConfigError,
"connect fail !, [%s %s %d]!"
, __FILE__, __FUNCTION__, __LINE__);
}
m_OnConnecting = false;
return -1;
}
int x = fcntl(sock_fd, F_GETFL, 0);
fcntl(sock_fd, F_SETFL, x | O_NONBLOCK);
//signal(SIGCHLD, SIG_IGN);
//FD_ZERO(&read_flags); // Zero the flags ready for using
//FD_ZERO(&write_flags);
//FD_SET(sock_fd, &read_flags);
//FD_SET(sock_fd, &write_flags);
/*
struct timeval timeout = {0,100};
setsockopt(sock_fd,SOL_SOCKET,SO_SNDTIMEO,(char *)&timeout,sizeof(struct timeval));
int tSet = setsockopt(sock_fd,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout,sizeof(struct timeval));
socklen_t len=sizeof(timeout);
getsockopt(sock_fd,SOL_SOCKET,SO_RCVTIMEO,&timeout,&len);
printf("setsockopt(%d),socklen_t(%d)!\r\n",tSet,len);
KeepAlive实现,单位秒
//下面代码要求有ACE,如果没有包含ACE,则请把用到的ACE函数改成linux相应的接口
int keepAlive = 1;//设定KeepAlive
int keepIdle = 5;//开始首次KeepAlive探测前的TCP空闭时间
int keepInterval = 5;//两次KeepAlive探测间的时间间隔
int keepCount = 3;//判定断开前的KeepAlive探测次数
if(setsockopt(s,SOL_SOCKET,SO_KEEPALIVE,(void*)&keepAlive,sizeof(keepAlive)) == -1)
{
CLogger::createInstance()->Log(eTipMessage,"setsockopt SO_KEEPALIVE error!");
}
if(setsockopt(s,SOL_TCP,TCP_KEEPIDLE,(void *)&keepIdle,sizeof(keepIdle)) == -1)
{
CLogger::createInstance()->Log(eTipMessage,"setsockopt TCP_KEEPIDLE error!");
}
if(setsockopt(s,SOL_TCP,TCP_KEEPINTVL,(void *)&keepInterval,sizeof(keepInterval)) == -1)
{
CLogger::createInstance()->Log(eTipMessage,setsockopt TCP_KEEPINTVL error!");
}
if(setsockopt(s,SOL_TCP,TCP_KEEPCNT,(void *)&keepCount,sizeof(keepCount)) == -1)
{
CLogger::createInstance()->Log(eTipMessage,setsockopt TCP_KEEPCNT error!");
}
*/
CLogger::createInstance()->Log(eTipMessage,
"connect ok !, [%s %s %d]!"
, __FILE__, __FUNCTION__, __LINE__);
m_OnConnect = true;
m_OnConnecting = false;
return 1;
#endif
}
catch (...) {
#ifdef WIN32
CLogger::createInstance()->Log(eSoftError,
"ClientSocket::onConnect error: %d.[%s %s %d]", static_cast<int>(GetLastError())
, __FILE__, __FUNCTION__, __LINE__);
#else
CLogger::createInstance()->Log(eSoftError,
"ClientSocket::onConnect error: %s. [%s %s %d]", strerror(errno)
, __FILE__, __FUNCTION__, __LINE__);
#endif
m_OnConnecting = false;
return -2;
}
}
void MySocketPrivate::disConnect()
{
m_OnConnect = false;
if (-1 != sock_fd)
{
#ifdef WIN32
closesocket(sock_fd);
#else
close(sock_fd);
#endif
sock_fd = -1;
}
}
int MySocketPrivate::reSetSocket()
{
disConnect();
return onConnect();
}
int MySocketPrivate::Read(TCP_Data<RDC_SIZE> &bufs)
{
try {
if (m_OnConnect)
{
char buf[256] = { 0 };
#ifdef WIN32
int re = recv(sock_fd, buf, 256, 0);
if (re <= 0)
{
int _error = GetLastError();
if (_error != 10060 && 0 != _error)
//if (_error != 10060)
{
CLogger::createInstance()->Log(eReadError,
"Read Datas Failed! ret(%d) error(%d)! [%s %s %d]"
, re, _error
, __FILE__, __FUNCTION__, __LINE__);
disConnect();
}
else
{
re = 0;
}
}
#else
//int re = read(sock_fd, buf, 256);
int re = recv(sock_fd, buf, 256, MSG_DONTWAIT);
if (re <= 0)
{
if(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)
{
usleep(10);
re = 0;
}
else
{
CLogger::createInstance()->Log(eReadError,
"Read Data Failed! error(%d,%d,%s)! [%s %s %d]"
, re, errno, strerror(errno)
, __FILE__, __FUNCTION__, __LINE__);
disConnect();
}
//static int index = 0;
//printf("..%d..%d,%s\n",index++,errno,strerror(errno));
}
#endif
if (re > 0)
{
/*
for(int j=0; j<re; j++){
printf("%02X ",buf[j]);
}
printf("\n");
*/
bufs.add((unsigned char*)buf, re);
return bufs.len;
}
return re;
}
else
{
printf("Read Data Failed!unconnect!");
return -2;
}
}
catch (...)
{
disConnect();
#ifdef WIN32
CLogger::createInstance()->Log(eSoftError,
"Read Data Failed!unknown error: %d! [%s %s %d]", static_cast<int>(GetLastError())
, __FILE__, __FUNCTION__, __LINE__);
#else
CLogger::createInstance()->Log(eSoftError,
"Read Data Failed!unknown error: %s! [%s %s %d]", strerror(errno)
, __FILE__, __FUNCTION__, __LINE__);
#endif
return -3;
}
};
int MySocketPrivate::Read(char* buf, int size)
{
try {
if (m_OnConnect)
{
#ifdef WIN32
//int re = m_CSocket->Receive(buf, size);
int re = recv(sock_fd, buf, size, 0);
if (re <= 0)
{
int _error = GetLastError();
if (_error != 10060 && 0 != _error)
//if (_error != 10060)
{
CLogger::createInstance()->Log(eReadError,
"Read Data Failed!ret(%d),error(%d)! [%s %s %d]"
, re, _error
, __FILE__, __FUNCTION__, __LINE__);
disConnect();
}
else
{
re = 0;
}
}
#else
//int re = read(sock_fd, buf, size);
int re = recv(sock_fd, buf, size, MSG_DONTWAIT);
if (re <= 0)
{
if(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)
{
usleep(10);
re = 0;
}
else
{
CLogger::createInstance()->Log(eReadError,
"Read Data Failed! error(%d,%d,%s)! [%s %s %d]"
,re , errno, strerror(errno)
, __FILE__, __FUNCTION__, __LINE__);
disConnect();
}
}
#endif
return re;
}
else
{
printf("Read Data Failed! unconnect! \n");
return -2;
}
}
catch (...)
{
disConnect();
#ifdef WIN32
CLogger::createInstance()->Log(eSoftError,
"Read Data Failed!unknown error: %d! [%s %s %d]", static_cast<int>(GetLastError())
, __FILE__, __FUNCTION__, __LINE__);
#else
CLogger::createInstance()->Log(eSoftError,
"Read Data Failed!unknown error: %s! [%s %s %d]", strerror(errno)
, __FILE__, __FUNCTION__, __LINE__);
#endif
return -3;
}
}
int MySocketPrivate::Write(const char* buf, int size)
{
try {
if (m_OnConnect)
{
#ifdef WIN32
int re = send(sock_fd, buf, size, 0);
if (re <= 0)
{
int _error = GetLastError();
if (_error != 10060 && 0 != _error)
{
CLogger::createInstance()->Log(eWriteError,
"Write Data Failed! ret(%d)! error(%d)! [%s %s %d]"
, re, _error
, __FILE__, __FUNCTION__, __LINE__);
disConnect();
}
}
#else
//int re = write(sock_fd, buf, size);
int re = send(sock_fd, buf, size, MSG_DONTWAIT);
if (re <= 0)
{
if(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)
{
usleep(10);
re = 0;
}
else
{
CLogger::createInstance()->Log(eWriteError,
"Write Data Failed! error(%d,%d,%s)! [%s %s %d]"
, re, errno, strerror(errno)
, __FILE__, __FUNCTION__, __LINE__);
disConnect();
}
}
#endif
return re;
}
else {
//CLogger::createInstance()->Log(eWriteError,
// "Write Data Failed! unconnect! [%s %s %d]\r\n"
// , __FILE__, __FUNCTION__, __LINE__);
printf("Write Data Failed! unconnect!");
if (!m_OnConnecting)
{
reSetSocket();
}
return -2;
}
}
catch (...)
{
disConnect();
#ifdef WIN32
CLogger::createInstance()->Log(eSoftError,
"Write Data Failed! unknown error: %d! [%s %s %d]", static_cast<int>(GetLastError())
, __FILE__, __FUNCTION__, __LINE__);
#else
CLogger::createInstance()->Log(eSoftError,
"Write Data Failed! unknown error: %d! [%s %s %d]", strerror(errno)
, __FILE__, __FUNCTION__, __LINE__);
#endif
return -3;
}
}
#endif //_SERVERIO_
MySocketRD.h
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef _MYSOCKETGXRD_H_
#define _MYSOCKETGXRD_H_
/*
该线程从socket服务接口读取数据,并将数据分帧
*/
#include "myThread.h"
#include "DataDef.h"
#include "queuedata.h"
class MySocketPrivate;
class MySocketRD : public MyThread
{
public:
MySocketRD(MySocketPrivate* myPDataPrt_, int netType_=1);
virtual ~MySocketRD(void);
int Run();
//从缓存中读取帧数据处理,请按需自行处理该函数
int AddFrame(const unsigned char *buf, int len,const std::string link="");
private:
void Cache_doit();
private:
bool running;
int netType;//数据读写处理类型
MySocketPrivate *myPDataPrt;
#ifdef _SERVERIO_
QueueData<RDS> ReadData;
#else
QueueData<TCP_Data<DATA_SIZE> > ReadData;
#endif
};
#endif
MySocketRD.cpp
#include "MySocketRD.h"
#include "MySocketPrivate.h"
#include "myFunc.h"
#include "Log.h"
MySocketRD::MySocketRD( MySocketPrivate* myPDataPrt_, int netType_)
: running(true)
, netType(netType_)
, myPDataPrt(myPDataPrt_)
{
}
MySocketRD::~MySocketRD(void)
{
running = false;
};
int MySocketRD::AddFrame( const unsigned char *buf, int len,const std::string link)
{
if(NULL == buf)
return 0;
printf("rev:%s\r\n",(char*)buf);
// TcpSocket ts;
// memcpy(&ts,buf,len);
// printf("rev:%u,%d,%0.2f,%s\r\n",ts.type,ts.len,ts.val,ts.desc);
return 0;
};
void MySocketRD::Cache_doit()
{
#ifdef _SERVERIO_
RDS rddata;
#else
TCP_Data<DATA_SIZE> rddata;
#endif
//数据帧解析
while (ReadData.getFirst(rddata))
{
#ifdef _SERVERIO_
this->AddFrame(rddata.data.Buf, rddata.data.len,rddata.flag);
#else
this->AddFrame(rddata.Buf, rddata.len);
#endif
ReadData.removeFirst();
}
}
#ifdef _SERVERIO_
int MySocketRD::Run()
{
if (NULL == myPDataPrt )
{
CLogger::createInstance()->Log(eSoftError,
"MySocketRD start fail for myPDataPrt is NULL,[%s %s %d]!"
, __FILE__, __FUNCTION__, __LINE__);
return 0;
}
std::map<KeyObj_Client, TCP_Data<RDC_SIZE> > bufs;
while (running)
{
int re = myPDataPrt->Read(bufs);
if (re <= 0)
{
#ifdef _DEBUG
printf_s("Read Data Failed or NULL\n!");
#else
;
#endif
}else {
switch (netType)
{
case 1:
{
try {
std::map<KeyObj_Client, TCP_Data<RDC_SIZE> >::iterator it = bufs.begin();
while (it != bufs.end())
{
if (it->second.len > 0)
{
RDS rdata(TCP_Data<DATA_SIZE>(it->second.Buf, it->second.len), it->first.m_ipStr);
ReadData.add(rdata);
}
it++;
}
bufs.clear();
}
catch (const std::exception& e)
{
CLogger::createInstance()->Log(eSoftError,
"Exception for Reading and Parsing Error[%s],NetType(%d), [%s %s %d]"
, e.what()
, netType
, __FILE__, __FUNCTION__, __LINE__);
}
catch (...) {
CLogger::createInstance()->Log(eSoftError,
"Exception for Reading and Parsing Error,NetType(%d),[%s %s %d]!"
, netType
, __FILE__, __FUNCTION__, __LINE__);
}
Cache_doit();
break;
}
case 2:
{
try {
std::map<KeyObj_Client, TCP_Data<RDC_SIZE> >::iterator it = bufs.begin();
while (it != bufs.end())
{
unsigned char * buff = it->second.Buf;
int start_frame = 0;
unsigned char ctype = 0;
for (int i = 0; i < it->second.len; i++)
{
//printf_s("%02X ",buff[i]);
if (buff[i] > 0xf0) {
if (buff[i] == 0xff)
{
if (ctype)
{
ctype = 0;
int re_len = i - start_frame + 1;
unsigned char * pBuf = new unsigned char[re_len];
//
int nLen = PFunc::uncode(buff + start_frame, re_len, pBuf);
RDS rdata(TCP_Data<DATA_SIZE>(pBuf, nLen), it->first.m_ipStr);
// printf("rev01:%s\r\n",(char*)pBuf);
printf("rev01:%d\r\n",nLen);
ReadData.add(rdata);
start_frame = i + 1;
delete[] pBuf;
pBuf = NULL;
}
}
else {
ctype = buff[i];
start_frame = i;
}
}
}
buff = NULL;
if (start_frame < it->second.len)
{
TCP_Data<RDC_SIZE> _newrd(it->second.Buf + start_frame, it->second.len - start_frame);
it->second = _newrd;
it++;
}
else {
#ifdef WIN32
it = bufs.erase(it);
#else
std::map<KeyObj_Client, TCP_Data<RDC_SIZE> >::iterator ittemp = it++;
bufs.erase(ittemp);
#endif
}
}
}
catch (const std::exception& e)
{
CLogger::createInstance()->Log(eSoftError,
"Data Deserialize false[%s],[%s %s %d]"
, e.what()
, __FILE__, __FUNCTION__, __LINE__);
}
catch (...) {
CLogger::createInstance()->Log(eSoftError,
"Data Deserialize false,[%s %s %d]!"
, __FILE__, __FUNCTION__, __LINE__);
}
Cache_doit();
break;
}
default:
break;
}
}
#ifdef WIN32
Sleep(10);
#else
usleep(10000);
#endif
}
return 0;
};
#else
int MySocketRD::Run()
{
if (NULL == myPDataPrt )
{
CLogger::createInstance()->Log(eSoftError,
"MySocketRD start fail for myPDataPrt is NULL"
",[%s %s %d]!"
, __FILE__, __FUNCTION__, __LINE__);
return 0;
}
TCP_Data<RDC_SIZE> rdc_data;
while (running)
{
if (!myPDataPrt->isConnect())
{
myPDataPrt->reSetSocket();//read or write thread do it
if (!myPDataPrt->isConnect())
{
#ifdef WIN32
Sleep(1000);
#else
usleep(1000000);
#endif
}
}
else
{
//读取帧数据
switch (netType)
{
case 1:
{
//直接读取,不用做分帧处理,ACSII字段
char buf[256] = { 0 };
int len = myPDataPrt->Read(buf, 256);
if (len > 0)
{
TCP_Data<DATA_SIZE> rdata((unsigned char*)buf, len);
ReadData.add(rdata);
}
//数据帧解析
Cache_doit();
}
break;
case 2:
{
//数据有特定帧头和结尾,做分帧处理
int ret = myPDataPrt->Read(rdc_data);
if (ret > 0)
{
//printf("read(%d) from pcs_server\n",ret);
unsigned char * buff = rdc_data.Buf;
int frame_start = 0;
unsigned char ctype = 0;
for (int i = 0; i < rdc_data.len; ++i)
{
//printf("%02X ",buff[i]);
if (buff[i] > 0xf0)
{
if (buff[i] == 0xff)
{
if (ctype)
{
ctype = 0;
unsigned char * pBuf = new unsigned char[i - frame_start + 1];
int nLen = PFunc::uncode(buff + frame_start, i - frame_start + 1, pBuf);//反序列化处理
TCP_Data<DATA_SIZE> rdata(pBuf, nLen);
ReadData.add(rdata);
frame_start = i + 1;
delete[] pBuf;
pBuf = NULL;
}
}
else
{
ctype = buff[i];
frame_start = i;
}
}
}
buff = NULL;
if (frame_start < rdc_data.len)
{
TCP_Data<RDC_SIZE> _newrd(rdc_data.Buf + frame_start, rdc_data.len - frame_start);
rdc_data = _newrd;
}
else
{
rdc_data.len = 0;
}
}
//数据帧解析
Cache_doit();
}
break;
default:
CLogger::createInstance()->Log(eSoftError,
"Exception for Reading and Parsing is undef NetType(%d),[%s %s %d]!"
, netType
, __FILE__, __FUNCTION__, __LINE__);
break;
}
}
#ifdef WIN32
Sleep(10);
#else
usleep(10000);
#endif
}
return 0;
};
#endif
MySocketSrv.h
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef _MYSOCKETSRV_H_
#define _MYSOCKETSRV_H_
#include "myThread.h"
class MySocketPrivate;
class MySocketSrv : public MyThread
{
public:
MySocketSrv();
virtual ~MySocketSrv();
void setPDataPtr(MySocketPrivate *myPData);
int Run();
private:
MySocketPrivate *myPDataPrt;
};
#endif
MySocketSrv.cpp
#include "MySocketSrv.h"
#include "MySocketPrivate.h"
#include "Log.h"
MySocketSrv::MySocketSrv(void)
: myPDataPrt(NULL)
{
}
MySocketSrv::~MySocketSrv(void)
{
}
void MySocketSrv::setPDataPtr(MySocketPrivate *myPData)
{
myPDataPrt=myPData;
};
int MySocketSrv::Run()
{
if (NULL == myPDataPrt)
{
CLogger::createInstance()->Log(eSoftError,
"MySocketSrv start fail for myPDataPrt is NULL,[%s %s %d]!"
, __FILE__, __FUNCTION__, __LINE__);
return 0;
}
while(1)
{
myPDataPrt->Accept();
#ifdef WIN32
Sleep(300);
#else
usleep(300000);
#endif
}
return 0;
}
MySocketWD.h
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef _MySocketWD_H_
#define _MySocketWD_H_
#include "myThread.h"
#include "DataDef.h"
#include "queuedata.h"
class MySocketPrivate;
/*
该线程向socket服务接口写入数据,将数据协议编码并序列化
*/
class MySocketWD : public MyThread
{
public:
MySocketWD(MySocketPrivate* myPDataPrt_,int netType_=1);
virtual ~MySocketWD(void);
int Run();
int add_data(const char* buf, int len);
int getBuffer(unsigned char* _buf, unsigned long long *_ipInt=NULL);
private:
#ifdef _SERVERIO_
void server_run();
int send(unsigned long long _ipInt, unsigned char* buf, int len);
#else
void client_run();
int getHeartBeatBuffer(unsigned char * buf);
#endif
private:
bool running;
int netType; //数据读写处理类型
#ifdef _SERVERIO_
QueueData<WDS> WriteData;
#else
unsigned int heartBeatWrite;
QueueData<TCP_Data<DATA_SIZE> > WriteData;
#endif
MySocketPrivate *myPDataPrt;
};
#endif
MySocketWD.cpp
#include "MySocketWD.h"
#include "MySocketPrivate.h"
#include "myFunc.h"
#include "Log.h"
#ifdef __linux__
#include <stdexcept>
#endif
#ifdef _SERVERIO_
#include <set>
#else
#define heartBeat_interval 10
#endif
MySocketWD::MySocketWD(MySocketPrivate *myPData, int _netType)
: running(true)
, netType(_netType)
#ifndef _SERVERIO_
, heartBeatWrite(static_cast<unsigned int>(time(NULL)))
#endif
, myPDataPrt(myPData)
{
}
MySocketWD::~MySocketWD(void)
{
running = false;
}
int MySocketWD::Run()
{
if (NULL == myPDataPrt)
{
CLogger::createInstance()->Log(eSoftError,
"MySocketWD start fail for myPDataPrt is NULL,[%s %s %d]!"
, __FILE__, __FUNCTION__, __LINE__);
return 0;
}
while(running)
{
#ifdef _SERVERIO_
server_run();
#else
client_run();
#endif
//server_run or client_run内置了sleep处理
}
return 0;
};
int MySocketWD::add_data(const char* buf, int len)
{
if(len>0&&NULL!=buf){
if(len>=512){
printf("buf len is >=512!\r\n");
}else{
#ifdef _SERVERIO_
std::set<long> ipintlist;
if(!myPDataPrt->get_ipInt_list(ipintlist))
{
return 0;
}
std::set<long>::iterator it = ipintlist.begin();
while (it != ipintlist.end())
{
/* code */
WDS wdata(*it,TCP_Data<DATA_SIZE>((unsigned char*)buf, len));
WriteData.add(wdata);
it++;
}
#else
TCP_Data<DATA_SIZE> rdata((unsigned char*)buf, len);
WriteData.add(rdata);
#endif
return len;
}
}
return 0;
}
int MySocketWD::getBuffer(unsigned char* _buf, unsigned long long *_ipInt)
{
if(NULL == _buf)
return 0;
int ret = 0;
#ifdef _SERVERIO_
WDS wdata;
#else
TCP_Data<DATA_SIZE> wdata;
#endif
if(WriteData.getFirst(wdata))
{
try{
if (!WriteData.removeFirst())
{
#ifdef WIN32
throw std::exception("removeFirst WData failed!");
#else
throw std::logic_error("removeFirst WData failed!");
#endif
}
#ifdef _SERVERIO_
*_ipInt = wdata.ipInt;
memcpy(_buf,wdata.data.Buf,wdata.data.len);
ret = wdata.data.len;
#else
memcpy(_buf,wdata.Buf,wdata.len);
ret = wdata.len;
printf("send:%s\r\n",_buf);
#endif
}
catch (const std::exception& e)
{
CLogger::createInstance()->Log(eSoftError,
"write item info to socket failed! have error[%s]. [%s %s %d]"
, e.what()
, __FILE__, __FUNCTION__, __LINE__);
ret = -1;
}
catch (...) {
//printf_s("write item info to socket failed! have error. \r\n");
CLogger::createInstance()->Log(eSoftError,
"write item info to socket failed! have error. [%s %s %d]"
, __FILE__, __FUNCTION__, __LINE__);
ret = -2;
}
}
return ret;
}
#ifdef _SERVERIO_
void MySocketWD::server_run()
{
try {
unsigned long long _ipInt = 0;
unsigned char buf[512] = { 0 };
int len = this->getBuffer( buf,&_ipInt);
if (len > 0)
{
int ret = send(_ipInt,buf,len);
if (ret <=0)
{
//printf("send data: %d, buf %d\n",len,ret);
CLogger::createInstance()->Log(eTipMessage,
"MySocketWD send data(%s,%d) fail. [%s %s %d]"
,buf,len
, __FILE__, __FUNCTION__, __LINE__);
}
//else{
// printf("send data: %d, and real send %d\n",len,ret);
//}
}
}
catch (const std::exception& e)
{
CLogger::createInstance()->Log(eSoftError,
"MySocketWD Run for data writing exception[%s],[%s %s %d]"
, e.what()
, __FILE__, __FUNCTION__, __LINE__);
}
catch (...) {
CLogger::createInstance()->Log(eSoftError,
"MySocketWD Run for data writing exception, [%s %s %d]!"
, __FILE__, __FUNCTION__, __LINE__);
}
#ifdef WIN32
Sleep(10);
#else
usleep(10000);
#endif
}
int MySocketWD::send(unsigned long long _ipInt, unsigned char* buf, int len)
{
int ret = -1;
switch (netType)
{
case 1:
{
ret = myPDataPrt->Write(_ipInt, (const char*)buf, len);
break;
}
case 2:
{
// printf("send data: %s\r\n",buf);
unsigned char* _buf = new unsigned char[2 * len + 1];
memset(_buf, 0, 2 * len + 1);
len = PFunc::code(buf, len, _buf);//序列化处理
printf("send data: %d\r\n",len);
ret = myPDataPrt->Write(_ipInt, (const char*)_buf, len);
delete[] _buf;
_buf = NULL;
break;
}
default:
{
char warBuf[128] = { 0 };
sprintf(warBuf, "MySocketWD::Run For Unkown NetType(%02X)", netType);
#ifdef WIN32
throw std::exception(warBuf);
#else
throw std::domain_error(warBuf);
#endif
break;
}
}
return ret;
}
#else
void MySocketWD::client_run()
{
if (!myPDataPrt->isConnect())
{
myPDataPrt->reSetSocket();//read or write thread do it
if (!myPDataPrt->isConnect())
{
#ifdef WIN32
Sleep(1000);
#else
usleep(1000000);
#endif
}
}
else {
//由读取进程去重新建立链接,写入线程只判定链接状态,进行数据写入
unsigned char buf[512] = { 0 };
int len = this->getBuffer(buf);
if (len <= 0 && (heartBeatWrite+heartBeat_interval)<static_cast<unsigned int>(time(NULL)))
{
len = this->getHeartBeatBuffer(buf);
}
if (len > 0) {
switch (netType)
{
case 1:
{
int ret = myPDataPrt->Write((const char*)buf, len);
if (ret != len) {
//printf("send data: %d, buf %d\n",len,ret);
CLogger::createInstance()->Log(eTipMessage,
"send point data: %d, buf %d. [%s %s %d]"
, len, ret
, __FILE__, __FUNCTION__, __LINE__);
}
else {
heartBeatWrite = static_cast<unsigned int>(time(NULL));
}
}
break;
case 2:
{
int cacheLen = 2 * len + 1;
unsigned char* _buf = new unsigned char[cacheLen];
memset(_buf, 0, cacheLen);
int nLen = PFunc::code(buf, len, _buf);//序列化处理
int ret = myPDataPrt->Write((const char*)_buf, nLen);
if (ret != nLen) {
//printf("send data: %d, buf %d\n",len,ret);
CLogger::createInstance()->Log(eTipMessage,
"send point data: %d, buf %d. [%s %s %d]"
, nLen, ret
, __FILE__, __FUNCTION__, __LINE__);
}
else {
heartBeatWrite = static_cast<unsigned int>(time(NULL));
}
delete[] _buf;
_buf = NULL;
}
break;
default:
CLogger::createInstance()->Log(eConfigError,
"Exception for Write data and unkown NetType(%d),[%s %s %d]!"
, netType
, __FILE__, __FUNCTION__, __LINE__);
break;
}
}
}
#ifdef WIN32
Sleep(1);
#else
usleep(1000);
#endif
}
int MySocketWD::getHeartBeatBuffer(unsigned char * buf)
{
if (NULL != buf)
{
int idx = 0;
std::string cur_time_str = PFunc::getCurrentTime();
char buf_[64]={0};
sprintf(buf_,"HeartBeat:%s",cur_time_str.c_str());
idx = (int)strlen(buf_);
memcpy(buf,buf_,idx);
return idx;
}
else
{
return 0;
}
};
#endif
5.3 client_test目录
CMakeLists.txt
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (client_test)
#
if(WIN32)
message(STATUS "windows compiling...")
add_definitions(-D_PLATFORM_IS_WINDOWS_)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
set(WIN_OS true)
else(WIN32)
message(STATUS "linux compiling...")
add_definitions( -D_PLATFORM_IS_LINUX_)
add_definitions("-Wno-invalid-source-encoding")
set(UNIX_OS true)
set(_DEBUG true)
endif(WIN32)
#
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../bin)
# 指定源文件的目录,并将名称保存到变量
SET(source_h
#
${PROJECT_SOURCE_DIR}/../common/DataDef.h
${PROJECT_SOURCE_DIR}/../common/queuedata.h
${PROJECT_SOURCE_DIR}/../common/Mutex.h
${PROJECT_SOURCE_DIR}/../common/myFunc.h
${PROJECT_SOURCE_DIR}/../common/myThread.h
${PROJECT_SOURCE_DIR}/../common/Log.h
${PROJECT_SOURCE_DIR}/../socket_io/MySocket.h
${PROJECT_SOURCE_DIR}/../socket_io/MySocketPrivate.h
${PROJECT_SOURCE_DIR}/../socket_io/MySocketRD.h
${PROJECT_SOURCE_DIR}/../socket_io/MySocketWD.h
)
SET(source_cpp
#
${PROJECT_SOURCE_DIR}/../common/Mutex.cpp
${PROJECT_SOURCE_DIR}/../common/myFunc.cpp
${PROJECT_SOURCE_DIR}/../common/myThread.cpp
${PROJECT_SOURCE_DIR}/../common/Log.cpp
${PROJECT_SOURCE_DIR}/../socket_io/MySocket.cpp
${PROJECT_SOURCE_DIR}/../socket_io/MySocketPrivate.cpp
${PROJECT_SOURCE_DIR}/../socket_io/MySocketRD.cpp
${PROJECT_SOURCE_DIR}/../socket_io/MySocketWD.cpp
${PROJECT_SOURCE_DIR}/main.cpp
)
#头文件目录
include_directories(
${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/../common
${PROJECT_SOURCE_DIR}/../socket_io
)
if (${UNIX_OS})
add_definitions(
"-W"
"-fPIC"
"-Wall"
# "-Wall -g"
"-Werror"
"-Wshadow"
"-Wformat"
"-Wpointer-arith"
"-D_REENTRANT"
"-D_USE_FAST_MACRO"
"-Wno-long-long"
"-Wuninitialized"
"-D_POSIX_PTHREAD_SEMANTICS"
"-DACL_PREPARE_COMPILE"
"-Wno-unused-parameter"
"-fexceptions"
)
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0")
link_directories()
# 指定生成目标
add_executable(client_test ${source_h} ${source_cpp} )
#link
target_link_libraries(client_test
-lpthread -pthread -lz -lrt -ldl
)
endif(${UNIX_OS})
if (${WIN_OS})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4819")
add_definitions(
"-D_CRT_SECURE_NO_WARNINGS"
"-D_WINSOCK_DEPRECATED_NO_WARNINGS"
"-DNO_WARN_MBCS_MFC_DEPRECATION"
"-DWIN32_LEAN_AND_MEAN"
)
link_directories()
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_SOURCE_DIR}/../bin)
# 指定生成目标
add_executable(client_testd ${source_h} ${source_cpp} )
#target_link_libraries(client_testd *.lib)
else(CMAKE_BUILD_TYPE)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/../bin)
# 指定生成目标
add_executable(client_test ${source_h} ${source_cpp} )
#target_link_libraries(client_test *.lib)
endif (CMAKE_BUILD_TYPE)
endif(${WIN_OS})
main.cpp
#include "MySocket.h"
#ifdef WIN32
#include <windows.h>
#else
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#endif
//log conf
char LOG_FILE_NAME[128] = "server_test.log";
std::string logdir = "log";
char SVCNAME[128] = "TCPServer_Srv";
int main(int argc, char *argv[])
{
if(3!=argc)
{
printf("CMD prompt: client_test ip_addr port\r\n");
}
NetArg _netarg;
_netarg.ipStr = std::string(argv[1]);
_netarg.port = (int)atoi(argv[2]);
_netarg.type = 1;
MySocket client_test(_netarg);
char buf[]="hello, this is client 01!";
// TcpSocket ts;
// ts.len=(int)strlen(buf);
// memcpy(ts.desc,buf,ts.len);
// ts.type = 1;
// ts.val = 10.0;
while(1)
{
client_test.Write((const char*)buf,(int)strlen(buf));
// client_test.Write((const char*)&ts,(int)sizeof(TcpSocket));
#ifdef WIN32
Sleep(10000);
#else
usleep(10000000);
#endif
}
return 0;
}
5.4 srv_test目录
CMakeLists.txt
# CMake 最低版本号要求
cmake_minimum_required (VERSION 3.2)
# 项目信息
project (server_test)
#
if(WIN32)
message(STATUS "windows compiling...")
add_definitions(-D_PLATFORM_IS_WINDOWS_)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
set(WIN_OS true)
else(WIN32)
message(STATUS "linux compiling...")
add_definitions( -D_PLATFORM_IS_LINUX_)
set(UNIX_OS true)
set(_DEBUG true)
endif(WIN32)
add_definitions("-D_SERVERIO_")
#
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../bin)
# 指定源文件的目录,并将名称保存到变量
SET(source_h
#
${PROJECT_SOURCE_DIR}/../common/queuedata.h
${PROJECT_SOURCE_DIR}/../common/Mutex.h
${PROJECT_SOURCE_DIR}/../common/hashmap.h
${PROJECT_SOURCE_DIR}/../common/myFunc.h
${PROJECT_SOURCE_DIR}/../common/myThread.h
${PROJECT_SOURCE_DIR}/../common/Log.h
${PROJECT_SOURCE_DIR}/../socket_io/MySocket.h
${PROJECT_SOURCE_DIR}/../socket_io/MySocketRD.h
${PROJECT_SOURCE_DIR}/../socket_io/MySocketWD.h
${PROJECT_SOURCE_DIR}/../socket_io/MySocketPrivate.h
${PROJECT_SOURCE_DIR}/../socket_io/MySocketSrv.h
)
SET(source_cpp
#
${PROJECT_SOURCE_DIR}/../common/Mutex.cpp
${PROJECT_SOURCE_DIR}/../common/hashmap.cpp
${PROJECT_SOURCE_DIR}/../common/myFunc.cpp
${PROJECT_SOURCE_DIR}/../common/myThread.cpp
${PROJECT_SOURCE_DIR}/../common/Log.cpp
${PROJECT_SOURCE_DIR}/../socket_io/MySocket.cpp
${PROJECT_SOURCE_DIR}/../socket_io/MySocketRD.cpp
${PROJECT_SOURCE_DIR}/../socket_io/MySocketWD.cpp
${PROJECT_SOURCE_DIR}/../socket_io/MySocketPrivate.cpp
${PROJECT_SOURCE_DIR}/../socket_io/MySocketSrv.cpp
${PROJECT_SOURCE_DIR}/main.cpp
)
#头文件目录
include_directories(
${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/../common
${PROJECT_SOURCE_DIR}/../socket_io
)
if (${UNIX_OS})
add_definitions(
"-W"
"-fPIC"
"-Wall"
"-Werror"
"-Wshadow"
"-Wformat"
"-Wpointer-arith"
"-D_REENTRANT"
"-D_USE_FAST_MACRO"
"-Wno-long-long"
"-Wuninitialized"
"-D_POSIX_PTHREAD_SEMANTICS"
"-DACL_PREPARE_COMPILE"
"-Wno-unused-parameter"
"-fexceptions"
)
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0")
link_directories()
# 指定生成目标
add_executable(server_test ${source_h} ${source_cpp} )
#link
target_link_libraries(server_test
-lpthread -pthread -lz -lrt -ldl
)
endif(${UNIX_OS})
if (${WIN_OS})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4819")
add_definitions(
"-D_CRT_SECURE_NO_WARNINGS"
"-D_WINSOCK_DEPRECATED_NO_WARNINGS"
"-DNO_WARN_MBCS_MFC_DEPRECATION"
"-DWIN32_LEAN_AND_MEAN"
)
link_directories()
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_SOURCE_DIR}/../bin)
# 指定生成目标
add_executable(server_testd ${source_h} ${source_cpp} )
else(CMAKE_BUILD_TYPE)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/../bin)
# 指定生成目标
add_executable(server_test ${source_h} ${source_cpp} )
endif (CMAKE_BUILD_TYPE)
endif(${WIN_OS})
main.cpp
#include "MySocket.h"
#ifdef WIN32
#include <windows.h>
#else
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#endif
const unsigned int PORT = 60008;
//log conf
char LOG_FILE_NAME[128] = "server_test.log";
std::string logdir = "log";
char SVCNAME[128] = "TCPServer_Srv";
int main(int argc, char *argv[])
{
NetArg net_arg;
MySocket server_test(net_arg);
char buf[]="hello, this is server!";
// TcpSocket ts;
// ts.len=(int)strlen(buf);
// memcpy(ts.desc,buf,ts.len);
// ts.type = 1;
// ts.val = 10.0;
while(1)
{
server_test.Write((const char*)buf,(int)strlen(buf));
// server_test.Write((const char*)&ts,(int)sizeof(TcpSocket));
#ifdef WIN32
Sleep(10000);
#else
usleep(10000000);
#endif
}
return 0;
}