最近公司項目需要把原本windows的代碼搞成可跨平臺的,過程中遇到一些跨平臺方面的細節,記錄在這裏。
1、Linux端口檢測
檢測端口是否被佔用,這個在windows平臺下一般用GetTcpTable系統API來實現。而在Linux下沒有直接的API,在網上看看了最終提出一個解決方案,就是通過調用bind來判斷端口是否被佔用。如果有其他更好的解決方案麻煩告知一下。
#include <sys/socket.h>
#include <netinet/in.h>
bool checkPort(int port)
{
int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in servaddr;
int on = 1;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(port);
if (bind(fd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0)
{
cout << "false" << endl;
return false;
}
else
{
close(fd);
cout << "true" << endl;
return true;
}
}
2、Linux切換執行目錄,獲取當前程序運行目錄
這些功能在程序需要執行外部批命令的時候需要用到。Windows下可以直接調用系統API獲得,Linux下解決方案如下。
void changePathTest()
{
system("mkdir test1");
chdir("/root");//更改運行目錄
system("mkdir test2");
char path[255];
readlink("/proc/self/exe", path, sizeof(path));//獲取當前程序路徑
cout << string(path).substr(0, string(path).find_last_of('/')).data() << endl;//獲取程序的目錄
chdir(string(path).substr(0,string(path).find_last_of('/')).data());//更改回本來的目錄
system("mkdir test3");
}
3、Linux判斷目錄或文件是否存在、Linux創建目錄
這些功能其實在Linux下實現起來更簡單一些
if (access(path, F_OK) != -1) //判斷路徑是否存在
{
cout << path << " exists" << endl;
}
if(mkdir(string("mkdir " + string(path) + "test").data(), 00666) != 0)//創建目錄,所有用戶可讀可寫
{
cout << "fail" << endl;
}
4、Linux根據進程名獲取pid和安裝路徑
void getPidByName(char * task_name)
{
DIR *dir;
struct dirent * ptr;
FILE *fp;
char file_path[MAX_PATH];
char cur_task_name[MAX_PATH];
char buf[BUF_SIZE];
dir = opendir("/proc");
int pid = 0;
if (NULL != dir)
{
while ((ptr = readdir(dir)) != NULL)//循環讀取路徑下的每一個文件和文件夾
{
//如果讀取到的是"."或者".."則跳過,讀取到的不是文件夾名字也跳過
if((strcmp(ptr->d_name, ".") == 0) || (strcmp(ptr->d_name, "..") == 0))
continue;
if (DT_DIR != ptr->d_type)
continue;
sprintf(file_path, "/proc/%s/status", ptr->d_name); //生成要讀取的文件的路徑
fp = fopen(file_path, "r"); //打開文件
if(NULL != fp)
{
if (fgets(buf, BUF_SIZE - 1, fp) == NULL)
{
fclose(fp);
continue;
}
sscanf(buf, "%*s %s", cur_task_name);
//如果文件內容滿足要求則打印路徑的名字(即進程的PID)
if(!strcmp(task_name, cur_task_name))
{
printf("PID: %s\n", ptr->d_name);
char path[255];
readlink((string("/proc/")+ptr->d_name+"/exe").data(), path, sizeof(path)); //獲取程序路徑
cout << "path: " << path << endl;
}
fclose(fp);
}
}
}
closedir(dir);
}
5、Linux下通配符遍歷文件、遞歸遍歷、文件名匹配
void fnmatchTest(string path, const string &pattern)
{
DIR *dir;
struct dirent *entry;
dir = opendir(path.c_str());
if (NULL != dir)
{
while ((entry = readdir(dir)) != NULL)
{
if ((strcmp(entry->d_name, ".") == 0) || (strcmp(entry->d_name, "..") == 0))
continue;
if (DT_DIR == entry->d_type)
{
fnmatchTest(path + "/" + entry->d_name, pattern);
}
if (DT_REG == entry->d_type)
{
int ret = fnmatch(pattern.c_str(), entry->d_name, FNM_PATHNAME | FNM_PERIOD);
if (ret == 0)
{
cout << path + "/" + entry->d_name << endl;
}
}
}
}
closedir(dir);
}
6、Linux下獲取文件時間
void getFileModifyTime(char *file)
{
struct stat s;
lstat(file, &s);
time_t st_time= s.st_mtime;
tm *tm_ = localtime(&st_time);
char buf[64];
strftime(buf, 64, "%Y-%m-%d %H:%M:%S", tm_);
std::cout << buf << std::endl;
}
7、Linux文件讀寫
linux下的文件描述符是一個非負整數,標準輸入輸出等都是一個文件描述符。下面代碼是《UNIX環境高級編程》上的一個實例。可以實現任何文件的複製。
int main(int argc, char *argv[])
{
int n;
char buf[1024];
while ((n = read(STDIN_FILENO, buf, 1024)) > 0)
{
if (write(STDOUT_FILENO, buf, n) != n)
{
cout << "write error" << endl;
}
if (n < 0)
{
cout << "read error" << endl;
}
}
return 0;
}
8、Linux通過va_list,va_start,va_end實現可變參數格式化
std::string str_fmt(const char * _Format, ...)
{
va_list arg_list2, arg_list1;
va_start(arg_list1, _Format);
va_copy(arg_list2, arg_list1);
size_t num_of_chars = vsnprintf(0, 0, _Format, arg_list2);
va_end(arg_list2);
std::string _str;
_str.resize(num_of_chars);
vsnprintf((char *)_str.c_str(), num_of_chars + 1, _Format, arg_list1);
va_end(arg_list1);
return _str;
}
9、Linux下通過管道自定義core文件生成目錄、名稱等信息
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>
#include<algorithm>
using namespace std;
int main(int argc,char *argv[])
{
char ll[10];
int i = 10 / 0;
cout << "dsadsa" << endl;
string exe_path;
string exe_file_name;
if (argc > 2)
{
exe_file_name = argv[1];
exe_path = argv[2];
}
replace(exe_path.begin(), exe_path.end(), '!', '/');
size_t index = exe_path.find_last_of('/');
if (index == string::npos)
{
return -1;
}
exe_path = exe_path.substr(0, index+1);
struct tm *t;
time_t tt;
time(&tt);
t = localtime(&tt);
char current_time[256];
sprintf(current_time,"%4d%02d%02d%02d%02d%02d", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
string core_file = exe_path + "core." + exe_file_name +"_" +string(current_time);
int fd = open(core_file.c_str(),O_WRONLY|O_CREAT,0666);
int n;
char buf[4096];
while ((n = read(STDIN_FILENO, buf, 4096)) > 0)
write(fd, buf, n);
cout << "over" << endl;
return 0;
}
10、boost:thread線程控制
#include <iostream>
#include <chrono>
#include <boost/thread.hpp>
using namespace std;
class MyTask
{
public:
void task()
{
try
{
while (true)
{
cout << "hello world!" << endl;
boost::this_thread::sleep_for(boost::chrono::seconds(2));
}
}
catch (boost::thread_interrupted&)
{
cout << "stop!" << endl;
}
}
void start()
{
if (!thread.joinable())
{
thread = boost::thread(&MyTask::task, this);
}
else
{
cout << "yijingqidong !" << endl;
}
//thread.detach();
}
void stop()
{
if (!thread.joinable())
{
cout << "yijingtingzhi" << endl;
}
else
{
thread.interrupt();
thread.join();
}
}
private:
boost::thread thread;
};
int main(int argc, char *argv[])
{
MyTask task;
task.start();
task.start();
task.start();
boost::this_thread::sleep_for(boost::chrono::seconds(11));
task.stop();
task.stop();
task.stop();
boost::this_thread::sleep_for(boost::chrono::seconds(11));
return 0;
}
11、std::thread線程控制
#include <iostream>
#include <chrono>
#include <thread>
#include <atomic>
#include <mutex>
#include <stdlib.h>
using namespace std;
class MyTask
{
public:
MyTask()
: m_bExit(false)
, m_isrunning(false)
{
}
void start()
{
if (!m_isrunning)
{
m_thread = std::thread(&MyTask::doTask, this);
set_priority();
m_isrunning = true;
}
else
{
cout << "yijingqidong" << endl;
}
}
void stop()
{
if (m_bExit)
{
cout << "yijingtingzhi" << endl;
return;
}
mutex_for_bExit.lock();
m_bExit = true;
mutex_for_bExit.unlock();
m_thread.join();
}
void set_priority()
{
sched_param sch;
sch.sched_priority = 99;
if (pthread_setschedparam(m_thread.native_handle(), SCHED_FIFO, &sch)) {
std::cout << "Failed to setschedparam: " << '\n';
}
}
private:
void doTask()
{
while (!m_bExit)
{
cout << "Hello World!" << endl;
this_thread::sleep_for(std::chrono::seconds(1));
}
}
std::thread m_thread;
std::mutex mutex_for_bExit;
atomic<bool> m_bExit;
atomic<bool> m_isrunning;
};
int main(int argc, char *argv[])
{
MyTask task;
task.start();
task.start();
task.start();
std::this_thread::sleep_for(std::chrono::seconds(11));
task.stop();
task.stop();
task.stop();
task.stop();
task.start();
std::this_thread::sleep_for(std::chrono::seconds(11));
task.stop();
task.start();
std::this_thread::sleep_for(std::chrono::seconds(11));
task.stop();
std::this_thread::sleep_for(std::chrono::seconds(11));
return 0;
}