linux C : 子进程监听父进程使用的socket端口问题
前言在cm中,有个服务程序,收到socket命令后,启动一个子进程。即使子进程没有任何socket操作,用lsof -i :port 来查看,也会看到子进程在监听父进程开的socket端口。如果父进程由于某种原因退出了(假设是崩溃,调试或收到了web系统的命令退出),再重启父进程,端口被子进程监听,导致bind失败。因为没想到问题原因,看代码也看不出来,就搁了一段时间。...
前言
在cm中,有个服务程序,收到socket命令后,启动一个子进程。
即使子进程没有任何socket操作,用lsof -i :port 来查看,也会看到子进程在监听父进程开的socket端口。
如果父进程由于某种原因退出了(假设是崩溃,调试或收到了web系统的命令退出),再重启父进程,端口被子进程监听,导致bind失败。
因为没想到问题原因,看代码也看不出来,就搁了一段时间。
前几天,同事发现,如果手工启动子进程,是不会占用父进程端口的。就是说,如果不是父进程启动的子进程,子进程就不会监听父进程的socket端口。
发现这个现象后,我们几个搞C的同事,立马都想得到了,哦,原来是子进程继承了父进程的socket句柄。
再去查资料,原来走在前面的同学将这个问题都解决了。当时,随便挑了一个解决方法搞定。那个方法是父进程建立socket句柄后,在父进程里,用控制API,关掉了应该继承给子进程的socket句柄(并不影响父进程自己使用刚建立的socket句柄), 这种方法感觉好暴力。还有方法是建立socket时,参数2或上SOCK_CLOEXEC标志,子进程就不继承父进程的socket句柄了,这种方法正规。
今天将这个实验做了一下。
加上Makefile的改进,将service, client, sub_proc,都放在一个工程中,根据Makefile传入参数的不同,可以分别build多个工程(不同的工程编译选项,不同的输出文件名)。又写了一个控制脚本,将编译,运行,测试都一次执行完,很方便。
测试流程为:
* 启动service, 等待client来聊天.
* 运行client, client 发命令,要求启动sub_proc,收到应答后,退出.
* service收到client命令后,启动sub_proc.
* sub_proc启动后,睡x秒退出
* 在sub_proc未退出前,用lsof命令观察sub_proc是否占用service开的socket端口。
经过实验,可得出结论。当建立一个socket后,要固定做2件事:
* 将建立的socket端口不让子进程继承
* 将建立的socket端口设置成端口地址可复用。
工程下载点
src_test_socket_opt_call_new_prog.7z
实验
工程实现的预览,就按Source Insight中的顺序来,不整理了.
#!/bin/bash
# ==============================================================================
# @file build_all_project.sh
# ==============================================================================
killall my_service
killall my_client
killall my_sub_proc
make BUILD_TYPE="service" rebuild
make BUILD_TYPE="client" rebuild
make BUILD_TYPE="sub_proc" rebuild
./my_service
./my_client
sleep 1
ps aux | grep my_
lsof -i :55555
sleep 1
killall my_service
sleep 2
./my_service
sleep 1
ps aux | grep my_
lsof -i :55555
sleep 1
ps aux | grep my_
lsof -i :55555
sleep 1
ps aux | grep my_
lsof -i :55555
// @file client.cpp
// @brief
#ifdef MACRO_ON_MAKEFILE_BUILD_AS_CLIENT
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "my_syslog.h"
#include "client.h"
void show_socket_err_log();
int client()
{
MYLOG_D(">> client");
int i_rc = -1;
int sk = SOCKET_INVALID;
struct sockaddr_in sa;
char sz_buf[1024] = {'\0'};
do {
// when create socket, use flag SOCK_CLOEXEC
// set parent's socket port don't listen by sub proc
sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (sk < 0) {
show_socket_err_log();
break;
}
// socket port re use
int i_reuse = 1;
i_rc = setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, (char *)&i_reuse, sizeof(i_reuse));
if (i_rc != 0) {
show_socket_err_log();
break;
}
MYLOG_D("socket create ok");
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = inet_addr(SERVICE_IP);
sa.sin_port = htons(SERVICE_PORT);
i_rc = connect(sk, (struct sockaddr*)&sa,sizeof(sa));
if (i_rc != SOCKET_OPT_OK) {
show_socket_err_log();
break;
}
MYLOG_D("socket connect ok");
memset(sz_buf, 0, sizeof(sz_buf));
strcpy(sz_buf, "start");
i_rc = send(sk, sz_buf, sizeof(sz_buf), 0);
if (i_rc < 0) {
show_socket_err_log();
break;
}
MYLOG_D("socket send ok");
memset(sz_buf, 0, sizeof(sz_buf));
i_rc = recv(sk, sz_buf, sizeof(sz_buf), 0);
if (i_rc < 0) {
show_socket_err_log();
break;
}
MYLOG_D("socket recv ok");
MYLOG_D("server answer : %s", sz_buf);
} while (0);
if (SOCKET_INVALID != sk) {
close(sk);
sk = SOCKET_INVALID;
}
MYLOG_D("<< client");
return 0;
}
void show_socket_err_log()
{
int i_rc = errno;
MYLOG_D("socket_error : %s", strerror(i_rc));
}
#endif // #ifdef MACRO_ON_MAKEFILE_BUILD_AS_CLIENT
// @file client.h
// @brief
#ifdef MACRO_ON_MAKEFILE_BUILD_AS_CLIENT
#include "my_syslog.h"
#define SERVICE_IP "127.0.0.1"
#define SERVICE_PORT 55555
#define SOCKET_OPT_OK 0
#define SOCKET_INVALID -1
int client();
#endif // #ifdef MACRO_ON_MAKEFILE_BUILD_AS_CLIENT
// @file main.cpp
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h> // daemon
#include <signal.h>
#include "my_syslog.h"
#ifdef MACRO_ON_MAKEFILE_BUILD_AS_SERVICE
#include "service.h"
#endif // #ifdef MACRO_ON_MAKEFILE_BUILD_AS_SERVICE
#ifdef MACRO_ON_MAKEFILE_BUILD_AS_CLIENT
#include "client.h"
#endif // #ifdef MACRO_ON_MAKEFILE_BUILD_AS_CLIENT
#ifdef MACRO_ON_MAKEFILE_BUILD_AS_SUB_PROC
#include "prog_not_use_socket.h"
#endif // #ifdef MACRO_ON_MAKEFILE_BUILD_AS_SUB_PROC
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) \
if (NULL != (p)) { \
delete (p); \
(p) = NULL; \
}
#endif // #ifndef SAFE_DELETE
void init(const char* psz_log_owner_name);
void uninit();
void proc_sig_term(int num);
int fn_test();
int main(int argc, char** argv)
{
#ifdef MACRO_ON_MAKEFILE_BUILD_AS_SERVICE
init("my_service");
#endif // #ifdef MACRO_ON_MAKEFILE_BUILD_AS_SERVICE
#ifdef MACRO_ON_MAKEFILE_BUILD_AS_CLIENT
init("my_client");
#endif // #ifdef MACRO_ON_MAKEFILE_BUILD_AS_CLIENT
#ifdef MACRO_ON_MAKEFILE_BUILD_AS_SUB_PROC
init("my_sub_proc");
#endif // #ifdef MACRO_ON_MAKEFILE_BUILD_AS_SUB_PROC
fn_test();
uninit();
MYLOG_D("THE END");
return EXIT_SUCCESS;
}
void init(const char* psz_log_owner_name)
{
int i = 0;
// only service, sub_proc prog run on background
#ifdef MACRO_ON_MAKEFILE_BUILD_AS_SERVICE
daemon(0, 0);
#else MACRO_ON_MAKEFILE_BUILD_AS_SUB_PROC
daemon(0, 0);
#endif // #ifdef MACRO_ON_MAKEFILE_BUILD_AS_SERVICE
ns_syslog::open_syslog((NULL != psz_log_owner_name) ? psz_log_owner_name : "ns_syslog");
// 设置控制变量中的日志条件, 实际应用中, 是从配置文件读取的控制开关
ns_syslog::g_log_condition.b_EMERG = false;
ns_syslog::g_log_condition.b_CRIT = true;
ns_syslog::g_log_condition.b_ALERT = true;
ns_syslog::g_log_condition.b_ERR = true;
ns_syslog::g_log_condition.b_WARNING = true;
ns_syslog::g_log_condition.b_NOTICE = true;
ns_syslog::g_log_condition.b_INFO = true;
ns_syslog::g_log_condition.b_DEBUG = true;
// 根据控制变量, 设置日志的mask
// 在实际应用中, 这里可以是动态设置, e.g. 配置文件检测线程发现配置变了, 需要变更某些级别的日志记录结果
ns_syslog::set_log_level(
ns_syslog::g_log_condition.b_EMERG,
ns_syslog::g_log_condition.b_ALERT,
ns_syslog::g_log_condition.b_CRIT,
ns_syslog::g_log_condition.b_ERR,
ns_syslog::g_log_condition.b_WARNING,
ns_syslog::g_log_condition.b_NOTICE,
ns_syslog::g_log_condition.b_INFO,
ns_syslog::g_log_condition.b_DEBUG);
// clear screen (print 25 empty line)
for (i = 0; i < 25; i++) {
MYLOG_D("");
}
signal(SIGTERM, proc_sig_term);
}
void uninit()
{
ns_syslog::close_syslog();
}
void proc_sig_term(int num)
{
MYLOG_D("SIGTERM = %d, num = %d", SIGTERM, num);
MYLOG_D("maybe can do some clean task after quit");
exit(1);
}
int fn_test()
{
MYLOG_D(">> fn_test()");
#ifdef MACRO_ON_MAKEFILE_BUILD_AS_SERVICE
service();
#endif // #ifdef MACRO_ON_MAKEFILE_BUILD_AS_SERVICE
#ifdef MACRO_ON_MAKEFILE_BUILD_AS_CLIENT
client();
#endif // #ifdef MACRO_ON_MAKEFILE_BUILD_AS_CLIENT
#ifdef MACRO_ON_MAKEFILE_BUILD_AS_SUB_PROC
sub_proc();
#endif // #ifdef MACRO_ON_MAKEFILE_BUILD_AS_SUB_PROC
MYLOG_D("<< fn_test()");
return 0;
}
# ==============================================================================
# @file makefile
# ==============================================================================
# @note
# test case - see value from Makefile commandline or in the Makefile
# make BUILD_TYPE="service" rebuild
# make BUILD_TYPE="client" rebuild
# make BUILD_TYPE="sub_proc" rebuild
MY_MAKE_FILE_PATH_NAME = $(MAKEFILE_LIST)
BIN_NAME_SERVICE = my_service
BIN_NAME_CLIENT = my_client
BIN_NAME_SUB_PROC = my_sub_proc
BUILD_TYPE_AS_SERVICE = service
BUILD_TYPE_AS_CLIENT = client
BUILD_TYPE_AS_SUB_PROC = sub_proc
IS_BUILD_TYPE_VALID = 0
IS_BUILD_TYPE_SERVICE = 0
IS_BUILD_TYPE_CLIENT = 0
IS_BUILD_TYPE_SUB_PROC = 0
MACRO_ON_MAKEFILE_BUILD_AS = MACRO_ON_MAKEFILE_BUILD_AS_UNKNOW
BIN = invalid_bin
ifdef BUILD_TYPE
ifeq ($(BUILD_TYPE), $(BUILD_TYPE_AS_SERVICE))
IS_BUILD_TYPE_VALID = 1
IS_BUILD_TYPE_SERVICE = 1
BIN = $(BIN_NAME_SERVICE)
MACRO_ON_MAKEFILE_BUILD_AS = MACRO_ON_MAKEFILE_BUILD_AS_SERVICE
else ifeq ($(BUILD_TYPE), $(BUILD_TYPE_AS_CLIENT))
IS_BUILD_TYPE_VALID = 1
IS_BUILD_TYPE_CLIENT = 1
BIN = $(BIN_NAME_CLIENT)
MACRO_ON_MAKEFILE_BUILD_AS = MACRO_ON_MAKEFILE_BUILD_AS_CLIENT
else ifeq ($(BUILD_TYPE), $(BUILD_TYPE_AS_SUB_PROC))
IS_BUILD_TYPE_VALID = 1
IS_BUILD_TYPE_SUB_PROC = 1
BIN = $(BIN_NAME_SUB_PROC)
MACRO_ON_MAKEFILE_BUILD_AS = MACRO_ON_MAKEFILE_BUILD_AS_SUB_PROC
else
IS_BUILD_TYPE_VALID = 0
endif
else
IS_BUILD_TYPE_VALID = 0
endif
LINE80 = --------------------------------------------------------------------------------
CC = g++ -std=c++98
CFLAGS = -Wall -g
INC = -I.
LIBPATH = -L/usr/lib/ -L/usr/local/lib/
ifeq (1, $(IS_BUILD_TYPE_SERVICE))
LIBS =
else ifeq (1, $(IS_BUILD_TYPE_CLIENT))
LIBS =
else ifeq (1, $(IS_BUILD_TYPE_SUB_PROC))
LIBS = -lcurses
else
LIBS =
endif
DEPEND_CODE_DIR = ./empty_dir \
DEPEND_CODE_SRC = $(shell find $(DEPEND_CODE_DIR) -name '*.cpp')
DEPEND_CODE_OBJ = $(DEPEND_CODE_SRC:.cpp=.o)
ROOT_CODE_SRC = $(shell find ./ -name '*.cpp')
ROOT_CODE_OBJ = $(ROOT_CODE_SRC:.cpp=.o)
SUB_CODE_DIR = ./socket_easy
SUB_CODE_SRC = $(shell find $(SUB_CODE_DIR) -name '*.cpp')
SUB_CODE_OBJ = $(SUB_CODE_SRC:.cpp=.o)
.PHONY: help
help:
clear
@echo "usage:"
@echo
@echo "build project as service"
@echo "make BUILD_TYPE=\"${BUILD_TYPE_AS_SERVICE}\" rebuild"
@echo
@echo "build project as client"
@echo "make BUILD_TYPE=\"${BUILD_TYPE_AS_CLIENT}\" rebuild"
@echo
@echo "build project as client"
@echo "make BUILD_TYPE=\"${BUILD_TYPE_AS_SUB_PROC}\" rebuild"
.PHONY: clean
clean:
clear
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo make clean
@echo $(LINE80)
@echo "@file $(MY_MAKE_FILE_PATH_NAME)"
@echo "IS_BUILD_TYPE_VALID = $(IS_BUILD_TYPE_VALID)"
@echo "IS_BUILD_TYPE_SERVICE = $(IS_BUILD_TYPE_SERVICE)"
@echo "IS_BUILD_TYPE_CLIENT = $(IS_BUILD_TYPE_CLIENT)"
@echo "IS_BUILD_TYPE_SUB_PROC = $(IS_BUILD_TYPE_SUB_PROC)"
@echo $(LINE80)
rm -f $(BIN) $(ROOT_CODE_OBJ) $(DEPEND_CODE_OBJ) $(SUB_CODE_OBJ)
rm -rf /usr/lib/$(BIN)
rm -rf ./$(BIN)
.PHONY: all
all:$(BIN)
@echo $(LINE80)
@echo make all
chmod 777 $(BIN)
find . -name $(BIN)
$(BIN) : $(ROOT_CODE_OBJ) $(DEPEND_CODE_OBJ) $(SUB_CODE_OBJ)
$(CC) $(CFLAGS) -o $@ $^ $(SHLIBS) $(INC) $(LIBPATH) $(LIBS)
.cpp.o:
$(CC) -c $(CFLAGS) -D$(MACRO_ON_MAKEFILE_BUILD_AS) $^ -o $@ $(INC) $(LIBPATH) $(LIBS)
.PHONY: rebuild
rebuild:
make -f $(MY_MAKE_FILE_PATH_NAME) clean
ifeq (1, $(IS_BUILD_TYPE_VALID))
@echo $(LINE80)
make -f $(MY_MAKE_FILE_PATH_NAME) all
chmod 775 ./$(BIN)
ldd ./$(BIN)
else
@echo $(LINE80)
@echo "error : make file command line input error, please see help"
@echo "please run => make help"
@echo $(LINE80)
endif
// @file my_syslog.cpp
// @brief syslog日志宏的实现
#include "my_syslog.h"
namespace ns_syslog {
TAG_LOG_CONDITION g_log_condition;
void open_syslog(const char* pszLogOwner)
{
openlog(((NULL != pszLogOwner) ? pszLogOwner : "my_syslog"), LOG_NOWAIT | LOG_PID, LOG_LOCAL1);
}
void set_log_level(
bool b_EMERG,
bool b_CRIT,
bool b_ALERT,
bool b_ERR,
bool b_WARNING,
bool b_NOTICE,
bool b_INFO,
bool b_DEBUG)
{
int i_mask = 0;
if (b_EMERG) {
// LOG_EMERG 日志会阻塞控制台程序, 必须要使这个条件为false, 不能执行这里
// LOG_EMERG 不仅是记录到日志, 还打印到正在运行的程序上, 阻塞了程序的执行. 不能用这种日志
i_mask |= LOG_MASK(LOG_EMERG);
}
if (b_ALERT) {
i_mask |= LOG_MASK(LOG_ALERT);
}
if (b_CRIT) {
i_mask |= LOG_MASK(LOG_CRIT);
}
if (b_ERR) {
i_mask |= LOG_MASK(LOG_ERR);
}
if (b_WARNING) {
i_mask |= LOG_MASK(LOG_WARNING);
}
if (b_NOTICE) {
i_mask |= LOG_MASK(LOG_NOTICE);
}
if (b_INFO) {
i_mask |= LOG_MASK(LOG_INFO);
}
if (b_DEBUG) {
i_mask |= LOG_MASK(LOG_DEBUG);
}
setlogmask(i_mask);
}
void close_syslog()
{
closelog();
}
} // namespace ns_syslog {
// @file my_syslog.h
// @brief syslog日志宏的定义
#ifndef __MY_SYSLOG_H__
#define __MY_SYSLOG_H__
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
// #include <unistd.h>
// #include <sys/types.h>
namespace ns_syslog {
typedef struct _tag_log_condition {
bool b_EMERG;
bool b_ALERT;
bool b_CRIT;
bool b_ERR;
bool b_WARNING;
bool b_NOTICE;
bool b_INFO;
bool b_DEBUG;
_tag_log_condition() {
b_EMERG = false;
b_ALERT = false;
b_CRIT = false;
b_ERR = false;
b_WARNING = false;
b_NOTICE = false;
b_INFO = false;
b_DEBUG = false;
}
} TAG_LOG_CONDITION;
extern TAG_LOG_CONDITION g_log_condition;
// ----------------------------------------------------------------------------
// syslog macro
// ----------------------------------------------------------------------------
#define MYLOG_EMERG(fmt, ...) \
if (ns_syslog::g_log_condition.b_EMERG) { \
syslog(LOG_EMERG, "[%s : %s.%d : %s()] : " fmt, "EMERG", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
#define MYLOG_EM(fmt, ...) \
if (ns_syslog::g_log_condition.b_EMERG) { \
syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "EMERG", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
// ----------------------------------------------------------------------------
#define MYLOG_ALERT(fmt, ...) \
if (ns_syslog::g_log_condition.b_ALERT) { \
syslog(LOG_ALERT, "[%s : %s.%d : %s()] : " fmt, "ALERT", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
#define MYLOG_A(fmt, ...) \
if (ns_syslog::g_log_condition.b_ALERT) { \
syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "ALERT", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
// ----------------------------------------------------------------------------
#define MYLOG_CRIT(fmt, ...) \
if (ns_syslog::g_log_condition.b_CRIT) { \
syslog(LOG_CRIT, "[%s : %s.%d : %s()] : " fmt, "CRIT", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
#define MYLOG_C(fmt, ...) \
if (ns_syslog::g_log_condition.b_CRIT) { \
syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "CRIT", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
// ----------------------------------------------------------------------------
#define MYLOG_ERR(fmt, ...) \
if (ns_syslog::g_log_condition.b_ERR) { \
syslog(LOG_ERR, "[%s : %s.%d : %s()] : " fmt, "ERR", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
#define MYLOG_E(fmt, ...) \
if (ns_syslog::g_log_condition.b_ERR) { \
syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "ERR", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
// ----------------------------------------------------------------------------
#define MYLOG_WARNING(fmt, ...) \
if (ns_syslog::g_log_condition.b_WARNING) { \
syslog(LOG_WARNING, "[%s : %s.%d : %s()] : " fmt, "WARNING", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
#define MYLOG_W(fmt, ...) \
if (ns_syslog::g_log_condition.b_WARNING) { \
syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "WARNING", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
// ----------------------------------------------------------------------------
#define MYLOG_NOTICE(fmt, ...) \
if (ns_syslog::g_log_condition.b_NOTICE) { \
syslog(LOG_NOTICE, "[%s : %s.%d : %s()] : " fmt, "NOTICE", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
#define MYLOG_N(fmt, ...) \
if (ns_syslog::g_log_condition.b_NOTICE) { \
syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "NOTICE", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
// ----------------------------------------------------------------------------
#define MYLOG_INFO(fmt, ...) \
if (ns_syslog::g_log_condition.b_INFO) { \
syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "INFO", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
#define MYLOG_I(fmt, ...) \
if (ns_syslog::g_log_condition.b_INFO) { \
syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "INFO", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
// ----------------------------------------------------------------------------
#define MYLOG_DEBUG(fmt, ...) \
if (ns_syslog::g_log_condition.b_DEBUG) { \
syslog(LOG_DEBUG, "[%s : %s.%d : %s()] : " fmt, "DEBUG", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
#define MYLOG_D(fmt, ...) \
if (ns_syslog::g_log_condition.b_DEBUG) { \
syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "DEBUG", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}
// ----------------------------------------------------------------------------
void open_syslog(const char* pszLogOwner);
void set_log_level(
bool b_EMERG = false,
bool b_CRIT = false,
bool b_ALERT = false,
bool b_ERR = false,
bool b_WARNING = false,
bool b_NOTICE = false,
bool b_INFO = false,
bool b_DEBUG = false);
void close_syslog();
} // namespace ns_syslog {
#endif // #ifndef __MY_SYSLOG_H__
// @file prog_not_use_socket.cpp
// @brief
#ifdef MACRO_ON_MAKEFILE_BUILD_AS_SUB_PROC
#include <stdio.h>
#include <unistd.h>
#include <curses.h> // aptitude install ncurses-dev
#include "prog_not_use_socket.h"
int sub_proc()
{
char c_tmp = '\0';
MYLOG_D(">> sub_proc");
/*
printf("if parent process don't process Inheritance issues, \n"
"the sub_proc will be use parent process's socket port,\n"
"even without any socket operation\n");
// flush stdin, and press 'q' + enter key to quit
printf("press 'q' key to quit\n");
fflush(stdin);
c_tmp = getchar();
while (('q' != c_tmp) && (EOF != c_tmp)) {
c_tmp = getchar();
}
*/
sleep(60);
MYLOG_D("<< sub_proc");
return 0;
}
#endif // #ifdef MACRO_ON_MAKEFILE_BUILD_AS_SUB_PROC
// @file prog_not_use_socket.h
// @brief
#ifdef MACRO_ON_MAKEFILE_BUILD_AS_SUB_PROC
#include "my_syslog.h"
int sub_proc();
#endif // #ifdef MACRO_ON_MAKEFILE_BUILD_AS_SUB_PROC
// @file service.cpp
// @brief
#ifdef MACRO_ON_MAKEFILE_BUILD_AS_SERVICE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "my_syslog.h"
#include "service.h"
int service()
{
int sk_service = SOCKET_INVALID;
int i_rc = 0;
struct sockaddr_in sa;
MYLOG_D(">> service");
do {
// when create socket, use flag SOCK_CLOEXEC
// set parent's socket port don't listen by sub proc
sk_service = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (sk_service < 0) {
show_socket_err_log();
break;
}
MYLOG_D("socket create ok");
// socket port re use
int i_reuse = 1;
i_rc = setsockopt(sk_service, SOL_SOCKET, SO_REUSEADDR, (char *)&i_reuse, sizeof(i_reuse));
if (i_rc != 0) {
show_socket_err_log();
break;
}
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = htonl(INADDR_ANY);
sa.sin_port = htons(SERVICE_PORT);
i_rc = bind(sk_service, (struct sockaddr*)&sa, sizeof(sa));
if (i_rc != SOCKET_OPT_OK) {
show_socket_err_log();
break;
}
MYLOG_D("socket bind ok");
i_rc = listen(sk_service, BACKLOG);
if (i_rc != SOCKET_OPT_OK) {
show_socket_err_log();
break;
}
MYLOG_D("socket listen ok");
fn_socket_service_proc(sk_service);
} while (0);
if (sk_service >= 0) {
close(sk_service);
sk_service = -1;
}
MYLOG_D("<< service");
return 0;
}
void fn_socket_service_proc(int sk_service)
{
int sk_client = SOCKET_INVALID;
struct sockaddr_in sa;
socklen_t len = sizeof(sa);
time_t tt_now;
char sz_recv[1024];
int i_cb_recv = 0;
while(1) {
MYLOG_D("wait client ...");
sk_client = accept(sk_service, (struct sockaddr*)&sa, &len);
if (sk_client < 0) {
show_socket_err_log();
break;
}
memset(sz_recv, 0, sizeof(sz_recv));
i_cb_recv = recv(sk_client, sz_recv, sizeof(sz_recv), 0);
if (i_cb_recv < 0) {
show_socket_err_log();
continue;
}
if (0 == strcmp(sz_recv, "start")) {
MYLOG_D("recv cmd : start");
system("/home/dev/my_sub_proc");
}
fn_log_packet(sz_recv, i_cb_recv);
memset(sz_recv, 0, sizeof(sz_recv));
tt_now = time(NULL);
sprintf(sz_recv, "%24s\r\n", ctime(&tt_now));
send(sk_client, sz_recv, strlen(sz_recv), 0);
close(sk_client);
sk_client = SOCKET_INVALID;
}
}
void fn_log_packet(const char* p_data, int i_len)
{
if ((NULL != p_data) && (i_len > 0)) {
MYLOG_D("packet len = %d", i_len);
// only print front 4 bytes
if (i_len >= 5) {
MYLOG_D("data : %2.2x %2.2x %2.2x %2.2x %2.2x : %c%c%c%c%c",
p_data[0],
p_data[1],
p_data[2],
p_data[3],
p_data[4],
p_data[0],
p_data[1],
p_data[2],
p_data[3],
p_data[4]);
}
} else {
MYLOG_D("packet invalid, can't parse");
}
}
void show_socket_err_log()
{
int i_rc = errno;
MYLOG_D("socket_error : %s", strerror(i_rc));
}
#endif // #ifdef MACRO_ON_MAKEFILE_BUILD_AS_SERVICE
// @file service.h
// @brief
#ifdef MACRO_ON_MAKEFILE_BUILD_AS_SERVICE
#define SERVICE_PORT 55555
#define SOCKET_OPT_OK 0
#define SOCKET_INVALID -1
#define BACKLOG 5
void show_socket_err_log();
void fn_socket_service_proc(int sk_service);
void fn_log_packet(const char* p_data, int i_len);
int service();
#endif // #ifdef MACRO_ON_MAKEFILE_BUILD_AS_SERVICE
// @file readme.txt
// gen log (build and run)
// ./build_all_project.sh >& /home/build_and_run.log
my_client: no process found
my_sub_proc: no process found
find: 鈥?./empty_dir鈥?: 娌℃湁閭d釜鏂囦欢鎴栫洰褰?
find: 鈥?./socket_easy鈥?: 娌℃湁閭d釜鏂囦欢鎴栫洰褰?
make -f Makefile clean
find: 鈥?./empty_dir鈥?: 娌℃湁閭d釜鏂囦欢鎴栫洰褰?
find: 鈥?./socket_easy鈥?: 娌℃湁閭d釜鏂囦欢鎴栫洰褰?
find: 鈥?./empty_dir鈥?: 娌℃湁閭d釜鏂囦欢鎴栫洰褰?
find: 鈥?./socket_easy鈥?: 娌℃湁閭d釜鏂囦欢鎴栫洰褰?
make[1]: Entering directory `/home/dev'
clear
make clean
--------------------------------------------------------------------------------
@file Makefile
IS_BUILD_TYPE_VALID = 1
IS_BUILD_TYPE_SERVICE = 1
IS_BUILD_TYPE_CLIENT = 0
IS_BUILD_TYPE_SUB_PROC = 0
--------------------------------------------------------------------------------
rm -f my_service ./service.o ./my_syslog.o ./main.o ./prog_not_use_socket.o ./client.o
rm -rf /usr/lib/my_service
rm -rf ./my_service
make[1]: Leaving directory `/home/dev'
--------------------------------------------------------------------------------
make -f Makefile all
find: 鈥?./empty_dir鈥?: 娌℃湁閭d釜鏂囦欢鎴栫洰褰?
find: 鈥?./socket_easy鈥?: 娌℃湁閭d釜鏂囦欢鎴栫洰褰?
make[1]: Entering directory `/home/dev'
g++ -std=c++98 -c -Wall -g -DMACRO_ON_MAKEFILE_BUILD_AS_SERVICE service.cpp -o service.o -I. -L/usr/lib/ -L/usr/local/lib/
g++ -std=c++98 -c -Wall -g -DMACRO_ON_MAKEFILE_BUILD_AS_SERVICE my_syslog.cpp -o my_syslog.o -I. -L/usr/lib/ -L/usr/local/lib/
g++ -std=c++98 -c -Wall -g -DMACRO_ON_MAKEFILE_BUILD_AS_SERVICE main.cpp -o main.o -I. -L/usr/lib/ -L/usr/local/lib/
main.cpp:64:7: warning: extra tokens at end of #else directive [enabled by default]
make[1]: Warning: File `prog_not_use_socket.cpp' has modification time 17 s in the future
g++ -std=c++98 -c -Wall -g -DMACRO_ON_MAKEFILE_BUILD_AS_SERVICE prog_not_use_socket.cpp -o prog_not_use_socket.o -I. -L/usr/lib/ -L/usr/local/lib/
g++ -std=c++98 -c -Wall -g -DMACRO_ON_MAKEFILE_BUILD_AS_SERVICE client.cpp -o client.o -I. -L/usr/lib/ -L/usr/local/lib/
g++ -std=c++98 -Wall -g -o my_service service.o my_syslog.o main.o prog_not_use_socket.o client.o -I. -L/usr/lib/ -L/usr/local/lib/
--------------------------------------------------------------------------------
make all
chmod 777 my_service
find . -name my_service
./my_service
make[1]: 璀﹀憡锛氭娴嬪埌鏃堕挓閿欒銆傛偍鐨勫垱寤哄彲鑳芥槸涓嶅畬鏁寸殑銆?
make[1]: Leaving directory `/home/dev'
chmod 775 ./my_service
ldd ./my_service
linux-vdso.so.1 => (0x00007fff7c553000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00002b68c28c0000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00002b68c2bc7000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00002b68c2e4a000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00002b68c3060000)
/lib64/ld-linux-x86-64.so.2 (0x00002b68c269e000)
find: 鈥?./empty_dir鈥?: 娌℃湁閭d釜鏂囦欢鎴栫洰褰?
find: 鈥?./socket_easy鈥?: 娌℃湁閭d釜鏂囦欢鎴栫洰褰?
make -f Makefile clean
find: 鈥?./empty_dir鈥?: 娌℃湁閭d釜鏂囦欢鎴栫洰褰?
find: 鈥?./socket_easy鈥?: 娌℃湁閭d釜鏂囦欢鎴栫洰褰?
find: 鈥?./empty_dir鈥?: 娌℃湁閭d釜鏂囦欢鎴栫洰褰?
find: 鈥?./socket_easy鈥?: 娌℃湁閭d釜鏂囦欢鎴栫洰褰?
make[1]: Entering directory `/home/dev'
clear
make clean
--------------------------------------------------------------------------------
@file Makefile
IS_BUILD_TYPE_VALID = 1
IS_BUILD_TYPE_SERVICE = 0
IS_BUILD_TYPE_CLIENT = 1
IS_BUILD_TYPE_SUB_PROC = 0
--------------------------------------------------------------------------------
rm -f my_client ./service.o ./my_syslog.o ./main.o ./prog_not_use_socket.o ./client.o
rm -rf /usr/lib/my_client
rm -rf ./my_client
make[1]: Leaving directory `/home/dev'
--------------------------------------------------------------------------------
make -f Makefile all
find: 鈥?./empty_dir鈥?: 娌℃湁閭d釜鏂囦欢鎴栫洰褰?
find: 鈥?./socket_easy鈥?: 娌℃湁閭d釜鏂囦欢鎴栫洰褰?
make[1]: Entering directory `/home/dev'
g++ -std=c++98 -c -Wall -g -DMACRO_ON_MAKEFILE_BUILD_AS_CLIENT service.cpp -o service.o -I. -L/usr/lib/ -L/usr/local/lib/
g++ -std=c++98 -c -Wall -g -DMACRO_ON_MAKEFILE_BUILD_AS_CLIENT my_syslog.cpp -o my_syslog.o -I. -L/usr/lib/ -L/usr/local/lib/
g++ -std=c++98 -c -Wall -g -DMACRO_ON_MAKEFILE_BUILD_AS_CLIENT main.cpp -o main.o -I. -L/usr/lib/ -L/usr/local/lib/
main.cpp:64:7: warning: extra tokens at end of #else directive [enabled by default]
make[1]: Warning: File `prog_not_use_socket.cpp' has modification time 16 s in the future
g++ -std=c++98 -c -Wall -g -DMACRO_ON_MAKEFILE_BUILD_AS_CLIENT prog_not_use_socket.cpp -o prog_not_use_socket.o -I. -L/usr/lib/ -L/usr/local/lib/
g++ -std=c++98 -c -Wall -g -DMACRO_ON_MAKEFILE_BUILD_AS_CLIENT client.cpp -o client.o -I. -L/usr/lib/ -L/usr/local/lib/
g++ -std=c++98 -Wall -g -o my_client service.o my_syslog.o main.o prog_not_use_socket.o client.o -I. -L/usr/lib/ -L/usr/local/lib/
--------------------------------------------------------------------------------
make all
chmod 777 my_client
find . -name my_client
./my_client
make[1]: 璀﹀憡锛氭娴嬪埌鏃堕挓閿欒銆傛偍鐨勫垱寤哄彲鑳芥槸涓嶅畬鏁寸殑銆?
make[1]: Leaving directory `/home/dev'
chmod 775 ./my_client
ldd ./my_client
linux-vdso.so.1 => (0x00007fff6aac3000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00002b6f766c1000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00002b6f769c8000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00002b6f76c4b000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00002b6f76e61000)
/lib64/ld-linux-x86-64.so.2 (0x00002b6f7649f000)
find: 鈥?./empty_dir鈥?: 娌℃湁閭d釜鏂囦欢鎴栫洰褰?
find: 鈥?./socket_easy鈥?: 娌℃湁閭d釜鏂囦欢鎴栫洰褰?
make -f Makefile clean
find: 鈥?./empty_dir鈥?: 娌℃湁閭d釜鏂囦欢鎴栫洰褰?
find: 鈥?./socket_easy鈥?: 娌℃湁閭d釜鏂囦欢鎴栫洰褰?
find: 鈥?./empty_dir鈥?: 娌℃湁閭d釜鏂囦欢鎴栫洰褰?
find: 鈥?./socket_easy鈥?: 娌℃湁閭d釜鏂囦欢鎴栫洰褰?
make[1]: Entering directory `/home/dev'
clear
make clean
--------------------------------------------------------------------------------
@file Makefile
IS_BUILD_TYPE_VALID = 1
IS_BUILD_TYPE_SERVICE = 0
IS_BUILD_TYPE_CLIENT = 0
IS_BUILD_TYPE_SUB_PROC = 1
--------------------------------------------------------------------------------
rm -f my_sub_proc ./service.o ./my_syslog.o ./main.o ./prog_not_use_socket.o ./client.o
rm -rf /usr/lib/my_sub_proc
rm -rf ./my_sub_proc
make[1]: Leaving directory `/home/dev'
--------------------------------------------------------------------------------
make -f Makefile all
find: 鈥?./empty_dir鈥?: 娌℃湁閭d釜鏂囦欢鎴栫洰褰?
find: 鈥?./socket_easy鈥?: 娌℃湁閭d釜鏂囦欢鎴栫洰褰?
make[1]: Entering directory `/home/dev'
g++ -std=c++98 -c -Wall -g -DMACRO_ON_MAKEFILE_BUILD_AS_SUB_PROC service.cpp -o service.o -I. -L/usr/lib/ -L/usr/local/lib/ -lcurses
g++ -std=c++98 -c -Wall -g -DMACRO_ON_MAKEFILE_BUILD_AS_SUB_PROC my_syslog.cpp -o my_syslog.o -I. -L/usr/lib/ -L/usr/local/lib/ -lcurses
g++ -std=c++98 -c -Wall -g -DMACRO_ON_MAKEFILE_BUILD_AS_SUB_PROC main.cpp -o main.o -I. -L/usr/lib/ -L/usr/local/lib/ -lcurses
main.cpp:64:7: warning: extra tokens at end of #else directive [enabled by default]
make[1]: Warning: File `prog_not_use_socket.cpp' has modification time 16 s in the future
g++ -std=c++98 -c -Wall -g -DMACRO_ON_MAKEFILE_BUILD_AS_SUB_PROC prog_not_use_socket.cpp -o prog_not_use_socket.o -I. -L/usr/lib/ -L/usr/local/lib/ -lcurses
prog_not_use_socket.cpp: In function 鈥榠nt sub_proc()鈥?:
prog_not_use_socket.cpp:13:7: warning: unused variable 鈥榗_tmp鈥? [-Wunused-variable]
g++ -std=c++98 -c -Wall -g -DMACRO_ON_MAKEFILE_BUILD_AS_SUB_PROC client.cpp -o client.o -I. -L/usr/lib/ -L/usr/local/lib/ -lcurses
g++ -std=c++98 -Wall -g -o my_sub_proc service.o my_syslog.o main.o prog_not_use_socket.o client.o -I. -L/usr/lib/ -L/usr/local/lib/ -lcurses
--------------------------------------------------------------------------------
make all
chmod 777 my_sub_proc
find . -name my_sub_proc
./my_sub_proc
make[1]: 璀﹀憡锛氭娴嬪埌鏃堕挓閿欒銆傛偍鐨勫垱寤哄彲鑳芥槸涓嶅畬鏁寸殑銆?
make[1]: Leaving directory `/home/dev'
chmod 775 ./my_sub_proc
ldd ./my_sub_proc
linux-vdso.so.1 => (0x00007ffff91ff000)
libncurses.so.5 => /lib/x86_64-linux-gnu/libncurses.so.5 (0x00002b8a41537000)
libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00002b8a41759000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00002b8a41983000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00002b8a41c8a000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00002b8a41f0c000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00002b8a42123000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00002b8a424ae000)
/lib64/ld-linux-x86-64.so.2 (0x00002b8a41315000)
root 18274 0.0 0.1 11888 512 ? Ss 00:26 0:00 ./my_service
root 18280 0.0 0.1 18348 564 ? Ss 00:26 0:00 /home/dev/my_sub_proc
root 18282 0.0 0.1 8060 868 pts/0 S+ 00:26 0:00 grep my_
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
my_servic 18274 root 4u IPv4 118835 0t0 TCP *:55555 (LISTEN)
my_sub_pr 18280 root 5u IPv4 118836 0t0 TCP localhost:55555->localhost:58706 (CLOSE_WAIT)
root 18280 0.0 0.1 18348 564 ? Ss 00:26 0:00 /home/dev/my_sub_proc
root 18288 0.0 0.1 11888 508 ? Ss 00:26 0:00 ./my_service
root 18291 0.0 0.1 8060 868 pts/0 S+ 00:26 0:00 grep my_
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
my_sub_pr 18280 root 5u IPv4 118836 0t0 TCP localhost:55555->localhost:58706 (CLOSE_WAIT)
my_servic 18288 root 4u IPv4 118910 0t0 TCP *:55555 (LISTEN)
root 18280 0.0 0.1 18348 564 ? Ss 00:26 0:00 /home/dev/my_sub_proc
root 18288 0.0 0.1 11888 508 ? Ss 00:26 0:00 ./my_service
root 18295 0.0 0.1 8060 868 pts/0 S+ 00:26 0:00 grep my_
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
my_sub_pr 18280 root 5u IPv4 118836 0t0 TCP localhost:55555->localhost:58706 (CLOSE_WAIT)
my_servic 18288 root 4u IPv4 118910 0t0 TCP *:55555 (LISTEN)
root 18280 0.0 0.1 18348 564 ? Ss 00:26 0:00 /home/dev/my_sub_proc
root 18288 0.0 0.1 11888 508 ? Ss 00:26 0:00 ./my_service
root 18299 0.0 0.1 8060 868 pts/0 S+ 00:26 0:00 grep my_
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
my_sub_pr 18280 root 5u IPv4 118836 0t0 TCP localhost:55555->localhost:58706 (CLOSE_WAIT)
my_servic 18288 root 4u IPv4 118910 0t0 TCP *:55555 (LISTEN)
更多推荐
所有评论(0)