linux C : 子程序監聽父程序使用的socket埠問題
前言
在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埠設定成埠地址可複用。
工程下載點
實驗
工程實現的預覽,就按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 [email protected] $^ $(SHLIBS) $(INC) $(LIBPATH) $(LIBS)
.cpp.o:
$(CC) -c $(CFLAGS) -D$(MACRO_ON_MAKEFILE_BUILD_AS) $^ -o [email protected] $(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_