转自:blog.csdn.net/minpro
/**********************************************************************************
以下实现TCP的客户端和服务端通信,使用同一条TCP连接每隔5秒发一次“hello!”,直到网络故障或者强制程序退出,如果客户端异常退出,可以通过守护进程自动重启。
此程序参照《UNIX网络编程》,头文件直接使用书中打包好的头(做了一些修改)
env:
我的服务端是在这里跑的:
HP-UX hp94 B.11.11 U 9000/800 4183772791 unlimited-user license
客户端是在这里跑的:
Linux iprn215 2.4.21-32.EL #1 Fri Apr 15 21:29:19 EDT 2005 i686 i686 i386 GNU/Linux
服务端配置文件:
LISTEN_PORT 60005
客户端配置文件:
TCPTEST_SERADDR 192.168.2.89
TCPTEST_SERPORT 60005
说明:为了测试网络闪断,本来想找个现成的TCP通信程序,但是在网络上的示例程序都是使用一个socket做一次收发操作,然后就close掉了。所以,只能硬着头皮自己写了。参照《UNIX网络编程》写,在我写守护的时候,按照书上的经典例程做,结果出了一个“疯狂的进程”,无论我想什么办法都杀不死,现在还在疯狂地活着,(我迟早要kill了它!呵呵....)不过,最后经过几天的研究终于实现了基本功能,但是对自己程序的稳定性还是没什么底呀!要是有哪位高手给予指点,不胜感激,感激涕零呀。。。。。。
最后要说的就是,我的程序估计很拙劣,但是希望抛砖引玉,得到大家的指点,另外,如果有人也有跟我曾经一样的烦恼,找不到一个合适的例子,希望我的砖头能帮点忙!
^_^
**********************************************************************************/
Server端:
/*包含一个init,它启动server,并使server后台运行而不占用此windows终端*/
server / init :
#include "unp.h"
#include "error.c"
#include "wrap.c"
void myinit()
{
char filename[50];
char *cinDir = getenv("CINDIR");
if(cinDir == NULL)
exit(0);
if(fork() == 0)
{
memset(filename, 0, sizeof(filename));
sprintf(filename, "%s/bin/tcptest_server", cinDir);
chdir("/");
umask(0);
execlp(filename, "tcptest_server", (char *)0);
_exit(0);
}
}
int main(void)
{
void sig_chld(int);
if(fork()!=0) _exit(0);
//init进程中:
setsid();
myinit();
exit(0); //这个守护的目的就是使server脱离终端
}
server / TcpServer.c :
#include "wrap.c"
#define MAXLISTENNUM 10
int lineNUM = 0;
void writeLog(const char *fmt, ...);
void changeLogFile();
void alarmFunc(int signo)
{
writeLog("receive client msg timeout !/n");
exit(0); //如果收消息超时,处理此client的子进程退出
}
void sig_chld(int signo)
{
pid_t pid;
int stat;
while((pid = waitpid(-1, &stat, WNOHANG)) > 0)
{
//printf("child %d terminated ! /n", pid);
writeLog("socket terminated : %d", pid);
}
signal(SIGCHLD, sig_chld);
}
void writeLog(const char *fmt, ...)
{
time_t timer;
struct tm *ptm;
char wDay[20];
int n;
char buf[256];
char logfilename[50];
FILE *fp;
char *cinDir = getenv("CINDIR");
sprintf(logfilename, "%s/log/tcptest_server.log", cinDir);
if((fp = fopen(logfilename, "a+")) == NULL)
{
printf("open log file error ! /n");
exit(0);
}
timer = time(NULL);
ptm = localtime(&timer);
memset(wDay, 0, sizeof(wDay));
switch (ptm->tm_wday)
{
case 0: strcpy(wDay, "Sunday"); break;
case 1: strcpy(wDay, "Monday"); break;
case 2: strcpy(wDay, "Tuesday"); break;
case 3: strcpy(wDay, "Wednesday"); break;
case 4: strcpy(wDay, "Thursday"); break;
case 5: strcpy(wDay, "Friday"); break;
case 6: strcpy(wDay, "Saturday"); break;
}
memset(buf, 0, sizeof(buf));
sprintf(buf, "%04d/%02d/%02d %s %02d:%02d:%02d | ",
(1900 + ptm->tm_year),
ptm->tm_mon,
ptm->tm_mday,
wDay,
ptm->tm_hour,
ptm->tm_min,
ptm->tm_sec);
n = strlen(buf);
va_list ap;
va_start(ap, fmt);
#ifdef HAVE_VSNPRINTF
vsnprintf(buf+n, 256, fmt, ap);
#else
vsprintf(buf+n, fmt, ap);
#endif
va_end(ap);
fprintf(fp, buf, strlen(buf));
fprintf(fp, "/r/n");
fclose(fp);
lineNUM++;
//printf("linenum: %d /n", lineNUM);
changeLogFile();
return;
}
void changeLogFile()
{
char logfilename[50];
FILE *fp;
char *cinDir = getenv("CINDIR");
sprintf(logfilename, "%s/log/tcptest_server.log", cinDir);
if(lineNUM > 30000)
{
lineNUM = 0;
char oldfilename[256];
char newfilename[256];
time_t timer;
struct tm *ptm;
timer = time( NULL );
ptm = localtime( &timer );
sprintf(oldfilename,"%s.%04d%02d%02d%02d%02d",logfilename,(int)ptm->tm_year+1900,(int)ptm->tm_mon+1,(int)ptm->tm_mday,
(int)ptm->tm_hour,(int)ptm->tm_min);
unlink(oldfilename);
rename(logfilename, oldfilename);
if((fp = fopen(logfilename, "wt")) == NULL)
printf("can not open log file : %s /n", logfilename);
else
fclose(fp);
}
}
int main(int argc, char *argv[])
{
int sockfd, clientfd;
time_t timer;
struct tm *ptm;
char str[100];
pid_t pid;
pid_t childpid;
struct sockaddr_in serveraddr;
struct sockaddr_in clientaddr;
#ifdef _AIX
socklen_t sin_size; /* 234 mod for ibmtest*/
#elif _LINUX
socklen_t sin_size;
#else
int sin_size;
#endif
//int sin_size;
int n;
char buf[8];
void sig_chld(int);
printf("||------------------------------------------/n");
printf("||----tcptest server begin init ... /n");
FILE *cfgfp;
char *cinDir = getenv("CINDIR");
char cfgfilename[100];
sprintf(cfgfilename, "%s/etc/tcptest_server.config", cinDir);
cfgfp = fopen(cfgfilename, "rt");
if(cfgfp == NULL )
{
printf("can not open config file !/n");
exit(1);
}
int listenport = 0;
char temp[256];
fscanf(cfgfp, "%s", temp);
if(strcmp(temp, "LISTEN_PORT") == 0)
{
fscanf(cfgfp, "%s", temp);
listenport = atoi(temp);
}
else
printf("read config error!/n");
fclose(cfgfp);
printf("||----read config ok !/n");
signal(SIGCHLD, sig_chld);
//创建socket
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
//fprintf(logfp, "creat socket error !");
writeLog("creat socket error : %s!", strerror(errno));
exit(1);
}
printf("||----create socket ok! /n");
//填充结构
bzero(&serveraddr, sizeof(struct sockaddr_in));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(listenport);
//bind
if(bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(struct sockaddr)) < 0)
{
//fprintf(logfp, "bind error !/n");
writeLog("bind error : %s !", strerror(errno));
exit(1);
}
printf("||----bind socket ok ! /n");
//listen
if(listen(sockfd, MAXLISTENNUM))
{
//fprintf(logfp, "listen error !/n");
writeLog("listen error : %s !", strerror(errno));
exit(1);
}
printf("||----listen socket ok ! /n");
printf("||------------------------------------------/n");
for(;;)
{
sin_size=sizeof(struct sockaddr_in);
if((clientfd = accept(sockfd, (struct sockaddr *)&clientaddr, &sin_size)) < 0)
{
if(errno == EINTR)
continue;
else
{
//fprintf(logfp, "accept error !/n");
writeLog("accept error : %s !", strerror(errno));
exit(1);
}
}
writeLog(" accept ok : client : %d!", clientfd);
if((childpid = fork()) == 0)
{
writeLog("the child server fork ok : %d ! /n", getpid());
close(sockfd);
signal(SIGALRM,alarmFunc);
alarm(10); //如果客户端异常退出,那么这里读超时.超时时间是8秒
while((n = Read(clientfd, buf, MAXLINE)) != -1) //对端正常终止(显示close)这里才会读-1, 如果对端ctrl+c,那么这里不会走正常的终止序列
{
if(n >0){
alarm(10);
Write(clientfd, buf, n);
writeLog("receive and send msg : %s", buf);
if(strcmp(buf, "hello!") != 0)
writeLog("receive string error : %s ", buf);
}
else //如果对端没有数据输入,这里是0
continue;
}
exit(0);
}
close(clientfd);
}
exit(0);
}
client端:
client / init :
int initNUM = 0;
void myinit(int initflag)
{
char filename[50];
char *cinDir = getenv("RNDIR");
if(cinDir == NULL)
exit(0);
if(initflag == 1)
sleep(5);
if(initflag == 2)
sleep(10);
if(initflag == 3)
sleep(20);
if(initflag == 4)
sleep(40);
if ( fork() == 0 )
{
memset(filename, 0, sizeof(filename));
sprintf(filename, "%s/bin/tcptest_client", cinDir);
chdir("/");
umask(0);
execlp(filename, "tcptest_client", (char *)0);
_exit(0);
}
}
void sig_chld(int signo) //子进程结束才能进到这里
{
pid_t pid;
int stat;
signal(SIGCHLD, sig_chld);
while((pid = waitpid(-1, &stat, WNOHANG)) > 0)
{
initNUM++; //如果客户端连接失败,那么子进程会退出,在这里试图重启12次
if(initNUM > 4)
{
//exit(0); //让它一直连,直到连上为止,或者强制退出
initNUM = 0;
}
myinit(initNUM);
}
}
int main(void)
{
void sig_chld(int);
//printf("the main pid : %d /n", getpid());
if(fork()!=0) _exit(0);
//init进程中:
signal(SIGCHLD, sig_chld);
setsid();
myinit(0);
for(;;)
{
sleep(10);
}
}
client / TcpClient.c :
#include "wrap.c"
void changeLogFile();
void writeLog(const char *fmt, ...);
int lineNUM = 0;
void sig_chld(int signo) //子进程结束才能进到这里
{
int i;
pid_t pid;
pid_t pPid;
int stat;
while((pid = waitpid(-1, &stat, WNOHANG)) > 0)
{
printf("the child terminal : %d /n", pid); //根本进不来
}
exit(0);
}
void writeLog(const char *fmt, ...)
{
time_t timer;
struct tm *ptm;
char wDay[20];
int n;
char buf[256];
char logfilename[50];
FILE *fp;
char *cinDir = getenv("RNDIR");
sprintf(logfilename, "%s/log/tcptest_client.log", cinDir);
if((fp = fopen(logfilename, "a+")) == NULL)
{
printf("open log file error ! /n");
exit(0);
}
timer = time(NULL);
ptm = localtime(&timer);
memset(wDay, 0, sizeof(wDay));
switch (ptm->tm_wday)
{
case 0: strcpy(wDay, "Sunday"); break;
case 1: strcpy(wDay, "Monday"); break;
case 2: strcpy(wDay, "Tuesday"); break;
case 3: strcpy(wDay, "Wednesday"); break;
case 4: strcpy(wDay, "Thursday"); break;
case 5: strcpy(wDay, "Friday"); break;
case 6: strcpy(wDay, "Saturday"); break;
}
memset(buf, 0, sizeof(buf));
sprintf(buf, "%04d/%02d/%02d %s %02d:%02d:%02d | ",
(1900 + ptm->tm_year),
ptm->tm_mon,
ptm->tm_mday,
wDay,
ptm->tm_hour,
ptm->tm_min,
ptm->tm_sec);
n = strlen(buf);
va_list ap;
va_start(ap, fmt);
#ifdef HAVE_VSNPRINTF
vsnprintf(buf+n, 256, fmt, ap);
#else
vsprintf(buf+n, fmt, ap);
#endif
va_end(ap);
fprintf(fp, buf, strlen(buf));
fprintf(fp, "/r/n");
fclose(fp);
lineNUM++;
//printf("linenum: %d /n", lineNUM);
changeLogFile();
return;
}
void changeLogFile()
{
char logfilename[50];
FILE *fp;
char *cinDir = getenv("RNDIR");
sprintf(logfilename, "%s/log/tcptest_client.log", cinDir);
if(lineNUM > 30000)
{
lineNUM = 0;
char oldfilename[256];
char newfilename[256];
time_t timer;
struct tm *ptm;
timer = time( NULL );
ptm = localtime( &timer );
sprintf(oldfilename,"%s.%04d%02d%02d%02d%02d",logfilename,(int)ptm->tm_year+1900,(int)ptm->tm_mon+1,(int)ptm->tm_mday,
(int)ptm->tm_hour,(int)ptm->tm_min);
unlink(oldfilename);
rename(logfilename, oldfilename);
if((fp = fopen(logfilename, "wt")) == NULL)
printf("can not open log file : %s /n", logfilename);
else
fclose(fp);
}
}
int
main(int argc, char **argv)
{
int i, sockfd;
int port;
char address[21] = "127.0.0.1";
struct sockaddr_in servaddr;
char sendbuf[8];
sprintf(sendbuf, "hello!");
char recvbuf[10];
char cfgfilename[50];
FILE *cfgfp;
char *cinDir = getenv("RNDIR");
sprintf(cfgfilename, "%s/config/tcptest_client.config", cinDir);
if((cfgfp = fopen(cfgfilename, "a+")) == NULL)
{
printf("open config file error ! /n");
exit(0);
}
char temp[256];
while(fscanf(cfgfp, "%s", temp) != EOF)
{
if(strcmp(temp, "TCPTEST_SERADDR") == 0)
{
memset(address, 0, sizeof(address));
fscanf(cfgfp, "%s", address);
}
else if(strcmp(temp, "TCPTEST_SERPORT") == 0)
fscanf(cfgfp, "%d", &port);
else
printf("read config error!/n");
}
fclose(cfgfp);
sockfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(port);
Inet_pton(AF_INET, address, &servaddr.sin_addr.s_addr);
writeLog("connect server begin ......");
if(connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
{
writeLog("connect server error : %s !", strerror(errno));
exit(0);
}
writeLog("connect server ok ! /n");
for(;;)
{
Write(sockfd, sendbuf, 8);
Read(sockfd, recvbuf, 10);
//fprintf(stdout, "%s", recvbuf);
writeLog("receive msg : %s", recvbuf);
if(strcmp(recvbuf, "hello!") != 0)
writeLog("receive string error : %s ", recvbuf);
sleep(5);
}
close(sockfd);
_exit(0);
}