|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
本文将描述在使用inetd守护进程时,如何通过syslog函数打印消息到日志文件。. v2 A0 U- q. G! E3 E- W, i
/ g! H' s6 U0 H( `6 p9 z为什么需要这样做呢?根据《UNIX网络编程 卷1:套接字联网API》一书第13章的描述:由于守护进程没有控制终端,它们不能把消fprintf到stderr上。
8 o8 j( b2 W& T. b' Y8 D1 y5 h+ B J7 }( F# I6 q y. z, B
从守护进程中登记消息的常用技巧就是调用syslog函数。8 j% D7 I! X) l8 L8 V4 H! K
2 b7 _3 ~! u9 H8 e
而sysolog函数需要syslogd服务的支持。因此在编译busybox时需要使能syslogd。7 Q; S: N! o x7 q. X
3 R. X& f! |4 d# N% M
5 i4 h! I" E% G) `: f: ]7 e
8 }0 p0 W( C- S$ a( W+ v
& j8 o" \9 g( R& K& j2 Z2 `9 O# |9 q% O4 ?2 m2 \
Linux系统启动后,需要打开syslogd服务。先来看看syslogd的命令选项:
7 s P3 P5 ]3 Q l& g( {- m4 L6 `0 w* l! J/ V8 s
[root@BGM /]#syslogd -h3 M8 r7 }# [6 v) g
syslogd: invalid option -- 'h'
" h- Z) s# Z# O$ IBusyBox v1.16.0 (2013-04-15 16:07:27 CST) multi-call binary.( F' J9 v/ J$ x. t, v
7 B. `- i2 x$ y& S, @! o
Usage: syslogd [OPTIONS]% o: Z o; s$ f) ?( |
( T1 p( u" E0 I# l$ BSystem logging utility.- Z, j9 Q) b" b; @$ s
Note that this version of syslogd ignores /etc/syslog.conf.
' J& U% n* y# F/ u/ Y7 u
5 g9 d6 f* ]3 c* T- cOptions:
, y* n7 A0 k, B: e4 s. ]. s* W -n Run in foreground
' x2 L$ E7 x% q: Y3 p -O FILE Log to given file (default:/var/log/messages)
3 N/ v2 z2 h" }1 b0 b9 x -l n Set local log level
( t( I2 K0 X7 b -S Smaller logging output) O/ U2 v' j+ x4 w* Y0 f
-s SIZE Max size (KB) before rotate (default:200KB, 0=off)% y6 F4 |! @: d5 w6 d; t% ^
-b N N rotated logs to keep (default:1, max=99, 0=purge)
# K' \/ h' `5 J -R HOST[: PORT] Log to IP or hostname on PORT (default PORT=514/UDP)$ \9 r* d8 N. O9 U, @# z2 L
-L Log locally and via network (default is network only if -R)1 |9 O2 g/ Z% D1 b% [
-D Drop duplicates
, y3 c: K8 O4 ]' b4 m7 A& } -C[size(KiB)] Log to shared mem buffer (read it using logread)
) s/ G ]) A3 ~( b- z5 V$ d5 q" e* u i
这里我们注意到该syslogd不支持/etc/syslog.conf文件。
3 j8 a; [8 `. O, m9 R9 `. G
( `8 r% d/ b6 P2 R- |% R我们需要使用-L选项,让消息输出到本地(locally),其次其默认的本地输出文件为/var/log/message,
2 j+ T: v( I) E- Y I% F: Q" k
7 c, b; o$ @% b) [- @如果要修改输出文件,则使用-O选项。# }9 d& ~, c) c; L3 l8 p, K9 [% ~4 c& H
- d! ~7 u8 J* R7 l0 ?' [
因此,我这里使用的syslogd命令如下:0 T7 ]( o# g) x4 o$ D" z- f$ O
# I( s1 C" ?' C1 w3 c( _6 t: H% Y( P/sbin/syslogd -L
/ w# z" E7 b: I$ t* t: F
! U) Q( E; \! m5 {; B/ \3 [这里建议将该命令添加到系统的启动脚本中。
& L: M7 ?- A( @; Y# x8 H* |/ P2 [! y9 @
为了测试函数需要编写一个简单的TCP服务器程序和相应的客户程序,参照《UNIX网络编程 卷1:套接字联网API》的13.6小结编写测试用例,
- |% u+ T: @/ c0 S; m
0 s0 O! P+ w, ?2 F: k程序如下:
' m! n; x3 r9 r! m5 I" B% ^2 p, `: J. f+ k( F) Y# r
服务器程序:' i2 L* C n- q: e" a% k
W; Y, Y" E( xint main(void)9 V8 g7 e" K: l* y! F* L9 c; y$ n4 [
{- r; o2 Y7 d/ @
socklen_t len;7 D5 l1 ^- h: d+ G6 J
struct sockaddr *cliaddr;
5 `& S- H6 t" H char buf[MAX_TCPSERV_BUF];3 a( c; Q4 e& l5 t, h5 Q
' L; k( [8 o0 I2 H int ret, tmp;: l8 n& F/ e+ Z
4 x3 K& H$ T |$ ^# P openlog("bgmtcpserv", LOG_PID, 0);9 x( S& g: `1 Y" P8 S2 U
# t$ X; f, W" _0 M) [ dc = malloc(sizeof(struct data_content));1 g0 r4 u9 Y4 g s: |2 w
if(!dc){
7 Q# w; ~& V& _0 v9 M4 b2 k0 S u perror("Unable to malloc data_content ");
$ X% t; N. m3 K1 ^) L$ Y exit -1;
! D) J/ X& p. I: ?) @ }- q# u% G# ^7 x- k1 ^/ j
M0 _& X) d/ r4 J5 E
cliaddr = malloc(sizeof(struct sockaddr_storage));
' O7 `' c N& ^; w if(!cliaddr){
4 P% W7 ~) x" D, o5 S" n perror("Unable to malloc sockaddr_storage ");! r- g2 i, R, O: v7 Q1 I
exit -1; a5 a, i! r* b8 |5 J) P- |6 `
}
4 @% J6 f& J, ? i8 _* g
7 Q8 ?% ?" b+ [0 H: v# m len = sizeof(struct sockaddr_storage);( \$ ?3 s0 c+ b) v1 G
if (getpeername(0, cliaddr, &len) == -1){
% @) L: ^7 ]# o Z ]% C perror("Getpeername error ");; X# [( b6 q- ^- }8 h2 [
exit -1;, ~/ @; p2 m h. x' ? X
}
) l1 C" a0 f" z5 T- |1 S k& }/ |$ y& Q
syslog(LOG_USER|LOG_ALERT, "Connecting from %s\n", Sock_ntop(cliaddr,len));
: ~* F5 n9 c) V , s9 B# A) s9 H7 R' A) P% _
close(0); 9 q, M4 h$ L2 D8 _( A+ v1 s$ A
closelog();6 ~9 [# s( |9 e; J& X% s
exit(0);& t% I5 K4 k/ ^* `
}$ V+ u5 e$ e# q* d) W* L1 |
/* include sock_ntop */! f8 W* X) ]6 a
char *+ l+ p! V) A( v
sock_ntop(const struct sockaddr *sa, socklen_t salen)! n5 y# ]9 f# j( s4 @; g
{1 }9 H! K y$ v0 N& x. W
char portstr[8];
- D( f) y* A9 `( p' v static char str[128]; /* Unix domain is largest */
& Q& r2 E- D' N- G' D) d9 g6 W/ r. Q
switch (sa->sa_family) {
4 U) q2 ~: N* v: c3 U case AF_INET: { Z7 ~# @' j5 ^; n
struct sockaddr_in *sin = (struct sockaddr_in *) sa;
+ h, {0 \: U9 \7 E- U) b% ?! h" a% _6 h" g" j' x
if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str)) == NULL)0 f5 E% E. y0 i5 V' ?" z5 z
return(NULL);
* n) L+ B- d6 W* Y$ ~1 s5 ]3 [( s! b if (ntohs(sin->sin_port) != 0) {
( v* U; V& f' Z8 v0 a4 E; G7 { snprintf(portstr, sizeof(portstr), ":%d", ntohs(sin->sin_port));) I4 O7 n4 Z j3 l) b7 o. q
strcat(str, portstr);
# D/ L d$ d& p }- e3 E8 N/ z+ |& i& X9 [, O
return(str);
3 O' j a0 N1 l6 n U }$ ?9 t7 k- I l/ s! ^ G) x
/* end sock_ntop */" E# I" d& t7 a+ z/ c7 i' u0 M I
% s5 c) ^0 g9 L ~; f
#ifdef IPV6
% U1 u9 p. g t0 { case AF_INET6: {
$ e% M- w$ x+ ~6 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;' X. |, s+ _ r; [
+ j5 O' \2 u# f! b! Z1 r str[0] = '[';. v/ |0 y. b( O# @. ^
if (inet_ntop(AF_INET6, &sin6->sin6_addr, str + 1, sizeof(str) - 1) == NULL)
1 Y/ d3 z8 s0 G2 f+ D$ Y! J return(NULL);! e& c) I0 `# s# p* M+ _
if (ntohs(sin6->sin6_port) != 0) {
6 q, K( }% B3 q6 k: _, v v. v t snprintf(portstr, sizeof(portstr), "]:%d", ntohs(sin6->sin6_port));* N$ h$ f+ {$ Y6 n" h9 v1 d
strcat(str, portstr);
, o9 W6 e4 R1 X7 q2 v& I8 s return(str);! t& Y0 m7 y, g Z+ {; U+ `
}7 `! [; {( h: X) j* Q/ D6 |8 R/ G
return (str + 1);
: l4 u2 o/ b$ |- e3 J/ y }
2 f' s `9 m+ S' D3 h9 B8 J; M#endif
: e! Q# e8 F/ }. G, q2 A/*
" ]% j. F) d; w! i2 ?#ifdef AF_UNIX
: h5 ]) a0 Z7 `2 s+ h case AF_UNIX: {
" @% S8 X* {1 O7 g. D6 h struct sockaddr_un *unp = (struct sockaddr_un *) sa;
3 e$ i6 N- A8 P- i) r% c! T OK to have no pathname bound to the socket: happens on4 \' Y7 M/ F& F# `! X4 y
every connect() unless client calls bind() first. : k; _% D' I. L' @- G7 Q; G5 X
if (unp->sun_path[0] == 0)1 H% d. [! m" t
strcpy(str, "(no pathname bound)");8 K" `/ C- T. _9 f) T) D6 j1 [! a3 N
else# U% s% @7 ?6 b! b4 T
snprintf(str, sizeof(str), "%s", unp->sun_path);
) l7 }/ H9 K' y' r0 i4 ` return(str);
- L( \$ X) N$ \& T) C }
7 p7 o7 C; V# h Q; u. ~6 m#endif*/
1 h0 P+ U- e. M# S7 _0 h6 w4 q2 k( a( U" [2 z! N6 K" o# x
// #ifdef HAVE_SOCKADDR_DL_STRUCT
$ _$ T z6 \$ d/ j0 n" K/ r// case AF_LINK: {1 D& o' s: T* i4 K2 x1 _
// struct sockaddr_dl *sdl = (struct sockaddr_dl *) sa;
. u: b A8 M+ @# [: b6 Z- p6 u/ X3 Q& j+ O5 i6 a) M
// if (sdl->sdl_nlen > 0)
8 @" \, Z, B( ?& ]// snprintf(str, sizeof(str), "%*s (index %d)",+ E) ~: s4 c9 J: b2 Q+ C
// sdl->sdl_nlen, &sdl->sdl_data[0], sdl->sdl_index);
4 U s+ v( O9 H2 Q// else u/ S1 i2 c# y; o1 W
// snprintf(str, sizeof(str), "AF_LINK, index=%d", sdl->sdl_index);; Y* [' d- b8 x
// return(str);7 {% C; A# O, t4 J$ a
// }
/ u2 l+ u( ]3 D$ H5 j; D5 s// #endif* n* _/ Q' r8 z; I% ]
default:
% r$ _* S- U) m5 c3 f- i snprintf(str, sizeof(str), "sock_ntop: unknown AF_xxx: %d, len %d",
/ b/ R$ Y4 J: R5 j0 s3 G sa->sa_family, salen); z6 ^. o5 |$ G/ H4 h* S
return(str);
( }2 K. e0 k9 L2 K, D( A3 f }
4 {$ o5 z8 S7 r3 T1 H return (NULL);
$ I6 `9 W( G/ l9 B0 F}1 y7 i% `# e, n
" Z, r# i+ q6 g$ X7 B
char *
- p8 z: c; ^/ D# w3 ~9 m/ S& G5 C4 {. ^Sock_ntop(const struct sockaddr *sa, socklen_t salen)2 q; [# ~* Q- O# K/ @4 r) X
{
+ y+ }" }$ j9 }9 F T char *ptr;
/ A7 a7 H- l7 ]; [2 s) B( m* A5 |. o4 D
if ( (ptr = sock_ntop(sa, salen)) == NULL)
& m7 w3 h- R! N \' P/ B( L perror("sock_ntop error"); /* inet_ntop() sets errno */
0 A) d' v/ d( {3 x& t; t8 Y return(ptr);$ K1 r3 U& u9 j* ~
}6 w* `4 q) e4 _/ G8 j/ z& W
+ P) B4 \( L1 i( i; N; \+ e( e5 B客户端程序: A" ?( K m7 \) _; h' N) a
#define SERV_PORT 30001. k0 ]2 V5 I8 O) O+ }9 c4 I
#define SERVIPADDR "192.168.0.200"' U+ m8 X" ? e8 @" V+ W
8 c9 B B$ K1 q% K( B9 Q/ Q
ssize_t /* Read "n" bytes from a descriptor. */2 ^9 T# j- @/ I7 j1 t* Q& J
readn(int fd, void *vptr, size_t n)1 z' G8 `& ]1 w% u" G8 m
{) y: E5 k! a; G8 z) U
size_t nleft;% D+ x' z h$ b, a
ssize_t nread;
/ s) ^% @9 J+ K2 n. t char *ptr;' v1 c8 f! O5 U& K3 I: L
# a& b" V: `' t$ g0 V$ N ptr = vptr;$ N& r I$ M' F( i9 N1 s4 @4 G" m
nleft = n;
! Z- h/ S/ u' E, I i' c# z while (nleft > 0) {
4 b. L, R% I+ H0 V: n if ( (nread = read(fd, ptr, nleft)) < 0) {
2 }8 A1 t5 d9 i1 u ~ if (errno == EINTR)
) L2 H: q+ r# Z/ T; s nread = 0; /* and call read() again */. y' F; U" k6 @& l, o) k* V# [
else
' U: d9 B3 Z9 ^, C5 ? return(-1);1 x1 v7 ^* W7 h6 d
} else if (nread == 0)/ B7 R) {3 Z t! l) [2 Z
break; /* EOF */$ r0 w/ @/ U% @. N) }! }6 u
$ @ }: ]9 D. W nleft -= nread;$ H2 t5 _! h0 [. Q8 c
ptr += nread;/ F+ \$ m2 {7 D! \
}4 k' s/ F9 g# Z% g0 s7 T! {* ]
return(n - nleft); /* return >= 0 */
3 p' a3 \6 J" H: C7 k3 R' h+ @}
. o* z2 ^4 t) } k, R, V5 p9 x, Z
/ q ?; h: o7 f' Gint main(void)) k2 l V3 D% N7 y. ?5 G A6 G
{
- k. j) n& ]% ?; W* J7 ^" w int sockfd, ret;
5 R' v9 U* `0 N$ Q& b% g6 `! }3 u struct sockaddr_in servaddr;
9 J& f6 N" R. I+ P& w int n;' N. G, m$ u; Z9 g# m
char buf[512] ;0 \ i2 A: z ]6 J* L2 ^3 w
! x. y; r) X, k, _) ^
sockfd = socket(AF_INET, SOCK_STREAM, 0);3 Q9 c/ V: n% g
if(sockfd < 0){
6 P8 w1 A) b: [ perror("Socket error");
! P; F+ _4 S6 T+ S return -1;1 o; F- U/ s$ P* C1 n9 {2 d+ e
}
7 D1 ~9 \; x5 K1 t: t1 S5 G/ t
, A" M1 D& R9 Z3 r$ Q- T f memset(&servaddr, 0, sizeof(struct sockaddr_in));$ B) V8 B$ X& }1 Y9 g `4 V
//bzero(&servaddr, sizeof(servaddr));) G6 X4 N0 x6 E
servaddr.sin_family = AF_INET;
8 Z2 O% d- ^8 ^ servaddr.sin_port = htons(SERV_PORT);- ?; Z7 C1 V# H! R
ret = inet_pton(AF_INET, SERVIPADDR, &servaddr.sin_addr);! d5 |) ]/ u7 T' T: e( K6 `) V+ l B
if(ret < 1){
5 {2 P7 R. p5 h% } s perror("Inet_pton error");
* T* k) D9 j& ]* s- ^+ @6 z, @/ _ return -1;- }- f9 F# s: e6 x$ ]
}
9 R8 L+ g6 s- d8 h+ D" L- O8 @
, N4 W" Z [! b( ^: D L- u! s ret = connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));- B& d$ X& I$ G, m! D% E& e B/ A
if(ret < 0){; O8 b) l# ~3 F0 F Y
perror("Connect error");
{0 Z" n' [5 a; [7 l2 q return -1;
5 f0 p$ _3 Q& W5 a' W) _ }
0 ^- E5 o, w. x7 G' \% i! t, \6 ?- }' r1 \$ K a
close(sockfd);
) U$ \2 H& e6 ~}! X2 d7 W. @% L% C( l9 \2 D; a
服务器程序编写完以后,为了让inetd能够调用我们的服务器程序,需要修改配置文件。1 B$ H- F) L( k+ U7 _3 i; Y
# B) M0 i( m1 v' [首先,修改/etc/services,增加如下:
2 z9 O4 L6 D3 X3 o N8 G/ c' K2 o
2 f. o+ u, q/ w! E2 C( fmytcpser 30001/tcp # Used by BGM
# X4 n1 k4 _1 o& Y2 l
. h- P, E( h- v+ U0 J) ^其次,修改/etc/inetd.conf,增加如下:
" v- f7 y/ Q, B/ ?* ]3 N v6 A8 R, w9 R
mytcpser stream tcp nowait root /home/bgm/bgmtcpser bgmtcpser
. `- {# C( R1 d1 P7 d9 x1 I" s! g0 x5 b- D; r* G' Q% s* |6 D0 Y$ X
这里的mytcpser需要和services文件中的第一个字段相同,其次/home/bgm/bgmtcpser为服务器程序所在的路径。
+ }/ W9 f) ^3 Y" a. w
6 o$ y: B# T. |. V4 I$ S修改完配置文件后,将服务器程序bgmtcpser复制到/home/bgm目录下。; B& _! C+ i% Q7 w0 j) b% L5 R
% |( H! d* v( |. N( f
使用netstat 来查看是否inetd已经创建端口号为30001的监听套接字:
9 A9 o7 W4 j3 N4 X6 ~0 m0 n1 x( x9 N" i" I9 A! y9 n( B9 S! S" w
[root@BGM /]#netstat -an | grep 30001% x# _( x! v; E; E- K
% M. P& x F* h' q3 B7 \6 e* o1 O
tcp 0 0 0.0.0.0:30001 0.0.0.0:* LISTEN ! c5 [8 d m& v0 z4 O" [
( n6 w7 f2 d) [) O1 `8 O然后我们执行客户程序cli,执行完以后我们查看/var/log/messages中的内容:
; l2 x# Y' n% p. a+ n. }Jul 23 13:13:42 BGM user.alert bgmtcpserv[2587]: Connecting from 192.168.0.200:405718 k6 T4 W1 i. z. e+ V T
" r" }. H T7 l! r这里的"Connecting from。。。"正是由syslog函数打印的。. h0 M5 s& \1 H* X/ y
, J/ P) T# }' w: `2 |2 B9 |7 S- u4 n% V# N$ n* [1 F
" z' u" C$ s: Y5 M1 d5 q
0 F: b. W& l- R g0 d* Q+ ?' C+ h3 w* s( ^- B- n, L
% v" Q. R. d: T2 ^
$ I1 Y, `: s) u |
|