|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
本文将描述在使用inetd守护进程时,如何通过syslog函数打印消息到日志文件。
6 j2 B% ]. {& ^& E6 @: A0 S1 k( @& L
为什么需要这样做呢?根据《UNIX网络编程 卷1:套接字联网API》一书第13章的描述:由于守护进程没有控制终端,它们不能把消fprintf到stderr上。
2 |2 s" t" S1 x6 a+ \8 N# T/ t
$ v) \. {, z5 n4 Y/ q& ~- Z4 }从守护进程中登记消息的常用技巧就是调用syslog函数。( R3 L7 i& j4 g0 ?
5 \8 X* K W# R# G而sysolog函数需要syslogd服务的支持。因此在编译busybox时需要使能syslogd。
4 t3 t z# D9 k8 ?+ ?) D6 N1 }: x w, S/ D h1 {
7 x$ k$ G- K9 J( L
* N& E: Q: w$ `' |6 ~
, O- Y o3 W4 P* P( L/ _+ B3 q! Z1 O
% |: Q( W/ {( Y2 f0 C0 RLinux系统启动后,需要打开syslogd服务。先来看看syslogd的命令选项:
( p0 Y+ ?8 h& x+ j( X3 O. M
, y& j( M- q2 o% R[root@BGM /]#syslogd -h
0 ]% o. Q* z! b3 w& }! F& fsyslogd: invalid option -- 'h'
" e$ I. H& D5 U) M# S* _BusyBox v1.16.0 (2013-04-15 16:07:27 CST) multi-call binary.
7 l2 `9 g) z; X* f! m! N! |% B- ^/ I4 u, V, s* n
Usage: syslogd [OPTIONS]
" w. y/ s. B, X6 |% e6 E. }# l4 a1 P3 r6 Q1 O$ y+ Q ~
System logging utility.
# W$ ?/ F- D/ A" l, R4 g- D! [) {Note that this version of syslogd ignores /etc/syslog.conf. z' F m P$ h# q
3 I. E% p z4 MOptions:8 a; e5 P* l4 [4 \
-n Run in foreground. R2 E# F# w: H# ?5 z
-O FILE Log to given file (default:/var/log/messages)
% ]5 E( c+ S6 H" \* x4 L( N% d -l n Set local log level
" Q J5 N/ t0 P* Y5 Q. p3 j -S Smaller logging output# {; y) z; f5 i
-s SIZE Max size (KB) before rotate (default:200KB, 0=off)
- m1 |5 Z% F" Z; u: S' q2 {! I; H -b N N rotated logs to keep (default:1, max=99, 0=purge) [8 j% E- x$ A2 T' R L# x
-R HOST[: PORT] Log to IP or hostname on PORT (default PORT=514/UDP)
5 g) A' }& F. @ Z- N3 r -L Log locally and via network (default is network only if -R)
! k8 M6 Q6 i3 W. e -D Drop duplicates
& I4 x! u+ z) S5 m B -C[size(KiB)] Log to shared mem buffer (read it using logread)
) S4 G' J/ r% ^: Z. G8 x6 L; G8 ?* [$ k1 f4 v. [! j* j! O% \5 Z2 H
这里我们注意到该syslogd不支持/etc/syslog.conf文件。
5 t, C Y3 H: ]* A0 H3 E5 E/ H8 s1 H6 R1 L: \
我们需要使用-L选项,让消息输出到本地(locally),其次其默认的本地输出文件为/var/log/message,2 K+ U& j: U# Z& R. @6 J# i$ [$ s
8 C- d2 s& f' _0 o' [" s2 |3 y
如果要修改输出文件,则使用-O选项。
& L$ M( @: d, \& g& n+ j9 f: ]$ |; H# x0 l8 G4 N! O
因此,我这里使用的syslogd命令如下:& x7 q: N7 i0 _ I* i
4 H, H$ ^5 j% v/sbin/syslogd -L
2 V/ T* @) T3 Q# F% h, G8 w$ i2 b; v- q9 O
这里建议将该命令添加到系统的启动脚本中。# B- l8 }3 g) a! _' E$ _& ^" y6 g2 Z
7 d3 w$ d; ]$ c+ b! n
为了测试函数需要编写一个简单的TCP服务器程序和相应的客户程序,参照《UNIX网络编程 卷1:套接字联网API》的13.6小结编写测试用例,# c' y; G& T" C c
+ S) F1 g& D5 P% C9 e5 l! h程序如下:
( I, F0 W$ m/ y, k, E! S# k) O+ J
- m9 \" ~4 [/ e服务器程序:, J; I5 g. u4 q* b* z" V
& j: b7 X/ [9 X4 n$ l1 hint main(void)
8 J7 e0 L: ]! @: k2 N{; ` V& Z, K& l k9 `, h; Z7 l/ l
socklen_t len;
0 }. m5 x3 r5 \8 x( r$ b struct sockaddr *cliaddr;, ]. H* d2 h8 n3 @1 @% n9 o
char buf[MAX_TCPSERV_BUF];; M7 E/ G3 x1 T2 {0 q3 K* J
/ i4 E+ Z: C, v# u* T8 ~
int ret, tmp;
" Q, n2 R8 d$ R T9 o: {! @
- P' F3 c: P, ]% U# B) ]. @4 N openlog("bgmtcpserv", LOG_PID, 0);# ?( w+ Y. o6 x3 X
( x9 x% P4 M6 @4 w
dc = malloc(sizeof(struct data_content));# k! N7 W1 G3 O' p! p. k, y
if(!dc){9 r4 r7 ^1 [7 h! F
perror("Unable to malloc data_content ");1 Y. K0 I+ M6 N- c: {% \ b
exit -1;
1 E; C# e5 ?( e6 d9 F }
! Y% N# Q$ H- G2 p# d5 P1 m3 n3 m- d. H: w. |7 E7 j: m0 J& x7 b$ S
cliaddr = malloc(sizeof(struct sockaddr_storage));
8 L& }- Y( z3 Z/ g if(!cliaddr){
) q! i8 @* F p) Y perror("Unable to malloc sockaddr_storage ");1 L/ s! p+ e( Q7 z- s$ K
exit -1;, u" U7 l; s+ e& ^4 D; \
}
$ C" \, A- D! m( w) F8 V
# v0 a# ?# j* ?6 v( r1 |: _ len = sizeof(struct sockaddr_storage);, Z, ^, u- | c- W C% W/ `
if (getpeername(0, cliaddr, &len) == -1){/ u V# H9 P" [7 M% @1 O3 c2 r
perror("Getpeername error ");, |+ x; V$ E/ V8 A2 |+ ?
exit -1;, P& p" D' h, M4 ~& Y* M
}' v. y$ f" F8 d3 ?4 [: k2 i' @
, p5 w* g# b3 i' U+ N! K syslog(LOG_USER|LOG_ALERT, "Connecting from %s\n", Sock_ntop(cliaddr,len));
" E" g* C5 J& A
( E. [( q' w; k5 z close(0); ; X& G- R% A% l2 H& S B
closelog();
# G8 w9 F- [9 W5 k" u( _ X exit(0);4 i, r. S) F7 J7 g# o
}# S* H& I" U' I' N/ P# u) a* D; w
/* include sock_ntop */
$ J& d) P# d5 T5 a- z9 \char *
& l' l! W/ }+ Usock_ntop(const struct sockaddr *sa, socklen_t salen)
3 R# ~" e( j' i8 I{6 _* \$ X) p2 y7 G
char portstr[8];$ J8 f8 k& b! e0 @
static char str[128]; /* Unix domain is largest */
5 ?' h: p- x2 L8 S. X( g; ^/ H! L. b" W) |3 y0 U
switch (sa->sa_family) {
: b. Q( | Y3 ]# r6 k9 a! F) ~ case AF_INET: {5 ^! M& E k R! t/ n5 u# f3 E
struct sockaddr_in *sin = (struct sockaddr_in *) sa;
! ?" n% J2 P2 P/ \& H, B+ m6 D! x& b6 u/ S$ H
if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str)) == NULL)2 e$ y5 y4 z& L2 R! N3 x5 w
return(NULL);
; {! R2 S7 z( i2 ~) \) E6 y if (ntohs(sin->sin_port) != 0) {4 B9 C( P3 [5 h' M1 p5 ^
snprintf(portstr, sizeof(portstr), ":%d", ntohs(sin->sin_port));
5 ?( v* k7 i& } |5 {# o strcat(str, portstr);+ E; c/ S b: h k9 l, q& R
}
3 c% b* M w% w1 K9 O' n return(str);
5 |" c" g4 Q( R3 ]$ P( a }1 g; I( i. f1 |! r! X
/* end sock_ntop */
* x% g0 q! q- c- L7 S8 U
- g7 X- ?4 E9 W( ]5 w/ t#ifdef IPV6
9 s# ?: D, n6 z+ T. j$ A( C/ u case AF_INET6: {# ]9 Z- Y8 G5 u n, v/ y
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;( K) Z0 f$ n' V" g: t' ]# S/ t$ r S
s N3 {2 F, b3 T5 Z str[0] = '[';
b! Z( a6 J( u R8 | if (inet_ntop(AF_INET6, &sin6->sin6_addr, str + 1, sizeof(str) - 1) == NULL)0 Z7 h. B2 L' f; A# n2 Z5 I! U
return(NULL);' ~: ?4 G/ Z1 A! T7 }2 I9 i
if (ntohs(sin6->sin6_port) != 0) {4 {% s: x9 i. t5 H3 L% b
snprintf(portstr, sizeof(portstr), "]:%d", ntohs(sin6->sin6_port));
/ N% y0 Q0 x. @1 S strcat(str, portstr);' x; D, ~/ u0 u1 R4 c- _- n
return(str);& c$ t' j. @5 m( ~0 v! U
} Y5 m8 O5 l3 X" y3 u( T
return (str + 1);' u& t- e% A# n. Y8 P* f/ Z
}2 ?7 O5 Z a" J8 J! D, i
#endif
0 \% z/ {9 f$ F! ~ F3 z% f) K0 j! g/ E/*$ @. l$ a- ]/ v$ u) y
#ifdef AF_UNIX
' b! D4 D8 p) v; P case AF_UNIX: {
- S2 W2 D- a3 l5 u# T struct sockaddr_un *unp = (struct sockaddr_un *) sa;- E! j' H# X1 U- R
OK to have no pathname bound to the socket: happens on3 W. b1 w# _' O! z
every connect() unless client calls bind() first.
* ^' `5 |8 o# p/ Y if (unp->sun_path[0] == 0)
) h# u* [8 c# k# I& a! \ strcpy(str, "(no pathname bound)");, {5 u3 x$ M8 r* I; Z
else$ w) M6 I3 C" p6 n" {7 s9 F
snprintf(str, sizeof(str), "%s", unp->sun_path);) b; E+ R. Z! L N
return(str);
3 I1 P5 Y; {" V+ g/ ~9 { }0 F) g' i. K2 f" W& B
#endif*/, i8 T: P" ]6 B" x* A! D
& U0 x' `% l2 ^3 D N( I
// #ifdef HAVE_SOCKADDR_DL_STRUCT; |/ M8 q* I0 G D
// case AF_LINK: {/ k0 O3 P, R. Z
// struct sockaddr_dl *sdl = (struct sockaddr_dl *) sa;, a t- g' ^+ r5 Z3 T
/ i& I& a' |( P" I9 J( h: m. U6 x
// if (sdl->sdl_nlen > 0)! f4 t7 L# ?' p5 ]2 B
// snprintf(str, sizeof(str), "%*s (index %d)",; h% `3 n" o) N1 b
// sdl->sdl_nlen, &sdl->sdl_data[0], sdl->sdl_index);1 }' `- r& g( q7 [0 a
// else& E3 [1 s8 r. x8 d3 k: G
// snprintf(str, sizeof(str), "AF_LINK, index=%d", sdl->sdl_index);8 v, X( h1 _4 I; S2 i j
// return(str);
& `; X4 M4 j0 D' H* p* c* k2 ~// }
1 n7 |6 J& i- D) I6 H// #endif
e/ H/ R# f# C default:0 v3 S7 J' X" G2 v
snprintf(str, sizeof(str), "sock_ntop: unknown AF_xxx: %d, len %d",
4 D+ S/ D/ J& f8 h sa->sa_family, salen);: n4 ?; @. F2 Q# L( j: I# G4 ^
return(str);
; @3 k0 Y& D+ s+ {+ ~9 d3 r! C }
! K! z! R; g A% P) B- I6 B: V return (NULL);& o B! v+ q" [* s3 ^9 B% i
}1 O, P4 M/ Y: {( O t( L$ T
8 g# W" t3 o; p9 |1 F8 C) s
char *$ L1 q D$ C; f
Sock_ntop(const struct sockaddr *sa, socklen_t salen)
1 K( @" Z* `2 l: s{
, x) m6 f; m: p6 C5 a char *ptr;5 g; K3 X& b$ p: ~. W
+ d. t- ?/ K+ H% s5 R
if ( (ptr = sock_ntop(sa, salen)) == NULL)+ u1 C& }$ Y& p1 j* ]
perror("sock_ntop error"); /* inet_ntop() sets errno */3 h+ o' U% g. x. K# ]. \+ v
return(ptr);
9 {) d9 R: c" L j+ G, f3 I}8 y1 D, |1 C. y5 h+ P4 R% u; _
3 E+ l J8 s# O$ E, [; ~5 u4 c2 _; D客户端程序:
* a. M, C, \* ]! }6 e#define SERV_PORT 30001
H0 u, h6 c$ L; i#define SERVIPADDR "192.168.0.200"9 Z, k% g8 S' B2 g" |4 z4 {' n1 r
" y- k- W. Z6 q4 v$ s- A |: a( Z
ssize_t /* Read "n" bytes from a descriptor. */
3 p- Q" ?$ U3 \; _9 s) _readn(int fd, void *vptr, size_t n)
% |' m6 h; C9 d* }* g{
0 @1 w+ W, X( f c8 P4 n+ Y size_t nleft;
7 c$ ^% B- |/ O* f( Y4 a+ F7 O ssize_t nread;
4 ]# ] o' n( |2 p3 s. i7 o3 A. f. | char *ptr;
7 b! t* B8 A ^: B6 r
5 q6 j) l* Y% e# G5 l% s0 [! N ptr = vptr;
% i' `7 Q e; ?% z# P% p1 m nleft = n;/ F9 k5 q7 E. L
while (nleft > 0) {
5 [1 c8 M7 x# _; D. K ] if ( (nread = read(fd, ptr, nleft)) < 0) {7 a7 }- w8 m# q7 ]) c
if (errno == EINTR)
2 w0 B6 c5 s, T nread = 0; /* and call read() again */" ]2 N( v, R! _; o [
else4 o. l) e0 _# Y+ S& O8 D. H1 B5 F
return(-1);3 ^/ f5 F0 S3 }$ E
} else if (nread == 0)' k1 B9 o8 s- \( {" h
break; /* EOF */6 w/ G* j! s7 C `! M7 ^' ^# B, N, I
$ C; v `; S) t! O+ S7 t7 s
nleft -= nread;8 z1 H: M1 E1 s9 M1 U
ptr += nread;# |2 a, q. f5 m0 M2 v! j4 O' {
}
c; {5 K0 M2 q: U1 P4 u7 Y return(n - nleft); /* return >= 0 */
8 A) i6 h& S( K$ C}
1 o Z' \$ O$ P E' @9 {7 U
* F" m7 U8 P k7 ?+ Vint main(void)' K) V& t |5 U0 M/ L
{" [: l$ K* C% g
int sockfd, ret;5 S$ S! C0 A% Z! m# X( t
struct sockaddr_in servaddr;
' ~. K) t) r& z& p, H0 t int n;: \/ V, ]+ c1 q5 t
char buf[512] ;6 G+ J& ^* a/ N7 _
5 d, R5 b7 C/ s
sockfd = socket(AF_INET, SOCK_STREAM, 0);' A& L7 a+ R U1 I: U7 X% {
if(sockfd < 0){
$ l4 N6 ]' P; S+ O perror("Socket error");
% @" B: r7 w/ \5 a! h P! b3 T9 s return -1;# H; K0 ^( R( m1 y7 h
}
0 r5 {- e" G/ ]: t" P+ F/ C
. p- \; q% d8 m) \- [9 A8 E/ L memset(&servaddr, 0, sizeof(struct sockaddr_in));
! ^$ R! d, {! F" i2 [& t9 `$ W //bzero(&servaddr, sizeof(servaddr));, Y* w0 D% R e+ A: Q
servaddr.sin_family = AF_INET;
/ j; B& ]* v: _( q3 p4 o# M servaddr.sin_port = htons(SERV_PORT);- v) `6 P$ t R6 x( \. y. Y
ret = inet_pton(AF_INET, SERVIPADDR, &servaddr.sin_addr);
; @2 n1 s0 q& a! f8 x if(ret < 1){
* F' @0 R' S, K( s5 a/ x# R perror("Inet_pton error");
9 _/ V$ C5 w o7 h5 f+ z ? return -1;0 F( Q' ^* Q G9 }- g1 a6 X
}6 P* P7 T O6 u& d2 `
) P; |( A" z* T E ret = connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
7 a @5 R( V, ~ if(ret < 0){
& O- t! M& U1 }, L) l5 O perror("Connect error");
4 i' e' q: S7 \6 R2 e& H' Z3 r return -1; _5 p6 }( f1 `/ o6 ?6 o7 r5 X
}5 c# A, @$ o0 @7 W' `
' O- K C( h1 V* I+ B4 }- ` close(sockfd);% ~$ z& b& W( n$ d+ ]3 M/ O- p
}
5 G' J! Z9 ]. v- m& ]6 x服务器程序编写完以后,为了让inetd能够调用我们的服务器程序,需要修改配置文件。
% x4 d K) Y% G! i7 H+ l% Z$ k# j J. z% r5 r
首先,修改/etc/services,增加如下:
" K/ ~% L' e6 l$ G6 z2 u5 C7 I; ~+ ]' I8 }
mytcpser 30001/tcp # Used by BGM
4 k' i! Y C% ]7 r- O2 q; O7 W% u8 `$ }0 X: l$ A6 K
其次,修改/etc/inetd.conf,增加如下:
. D0 Z! e) m/ l' E( E7 F9 f$ J7 o# X3 J& g* N5 y9 a; |
mytcpser stream tcp nowait root /home/bgm/bgmtcpser bgmtcpser
+ l; F* C* W9 l$ v" g( v7 S: q9 e( _2 ~
这里的mytcpser需要和services文件中的第一个字段相同,其次/home/bgm/bgmtcpser为服务器程序所在的路径。/ y& y9 y# O- D% @% R6 G. o
, e0 j6 J u% J修改完配置文件后,将服务器程序bgmtcpser复制到/home/bgm目录下。
5 w) h" s* O' g) ^) l
3 H7 W+ `! k* X- B使用netstat 来查看是否inetd已经创建端口号为30001的监听套接字:
6 h) _1 N1 `/ M) h/ V* H& V# r
6 j" o y+ G6 p, |$ S' g7 D[root@BGM /]#netstat -an | grep 30001- k" O7 D$ i6 V5 ?1 Z4 Y# `
! `$ O( P5 H' L9 ztcp 0 0 0.0.0.0:30001 0.0.0.0:* LISTEN
2 y( O k% Z) e2 ~3 p* Z) T. C7 E6 R; s0 `7 ]4 u
然后我们执行客户程序cli,执行完以后我们查看/var/log/messages中的内容:
) v: N$ r6 A# @! VJul 23 13:13:42 BGM user.alert bgmtcpserv[2587]: Connecting from 192.168.0.200:40571
3 Q" A) g5 n) I) T# w
% }" ]5 f3 V6 N+ ~% Q. w这里的"Connecting from。。。"正是由syslog函数打印的。4 X. B7 K3 _; l! W9 Y5 W
4 Z8 {" K% l7 |6 }
) E5 {& s* N' r) O$ H, b) H
6 g/ h0 z; n m. N7 G1 l U
% G$ X, J, K3 ?' q' x( \& @' I
, W& Y, T& B' V# E. v' S4 Q0 f1 W; F. R) l5 b$ c/ }
3 P. I R& n' c8 s2 q. n b3 F, x
|
|