///////////////////////////////////////////////////////////////////////////////////
//交易报文组成:交易报文头+交易报文体
//交易报文头:ASC码0x01 + 报文头长度(3bytes,右对齐不足左补零)+
// 是否携带文件标志('0'-不带文件, '1'-携带文件) + 文件名长度('00'--'99') +
// 文件名称 + 交易报文体长度('00000001'-'99999999') +
// 携带文件长度('0000000000'-'9999999999')
//交易报文体:由用户提供报文
//文件报文:文件报文体
//文件报文体:所携带文件的ASC码
///////////////////////////////////////////////////////////////////////////////////
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "tcppubfun.h"
# ifndef INADDR_NONE
# define INADDR_NONE 0xffffffff
# endif
extern int errno;
u_short gd_tcpportbase = 0;
int gd_tcpworksvrchildpidarr[256];
int gd_tcpworksvrchildpidarrdim = 0;
char gd_LogFile[256];
int connectsock(const char *host, const char *service, const char *transport);
int passiveTCP(const char *service, int qlen);
int passivesock(const char *service, const char *transport, int qlen);
void reaper(int sig);
int memcat(char *sr, int slen, char *dest, int pos);
int writesock(int sock, char *hdata, int hsize);
int ReadWait(int sockfds, int blocktime);
int start_tcp_serv(char *service, int qlen, int (*fun)(int sock),
int (*fconndb)(), int (*fdisconndb)(), int pnum);
void onquitsvrchild(int sig);
int TcpInWorkChild(int msock, int (*fun)(int sock));
//tcpdtime--取得当前时间和日期
//Argument:
// asctm--当前时间, hhmmss
// ascday--当前日期, yyyymmdd
int tcpdtime(char * asctm,char * ascday)
{
time_t t;
struct tm * tm1;
t = time(NULL);
tm1 = localtime(&t);
sprintf(ascday,"%04d",tm1->tm_year+1900);
sprintf(ascday+4,"%02d",tm1->tm_mon+1);
sprintf(ascday+6,"%02d",tm1->tm_mday);
sprintf(asctm,"%02d",tm1->tm_hour);
sprintf(asctm+2,"%02d",tm1->tm_min);
sprintf(asctm+4,"%02d",tm1->tm_sec);
return 0;
}
//Function:与服务端应用建立连接.
// return 0--Normal
// <0--Fail
//Argument:
// host --服务方的主机名称或IP地址
// service--服务方应用的端口号
int connectTCP(const char *host, const char *service)
{
int ret;
ret = connectsock(host, service, "tcp");
return ret;
}
//Function:allocate & connect a socket using TCP or UDP
// -1--service参数错误
// -2--host参数错误
// -3--transport--参数错误 Not "tcp" or "udp"
// -4--socket()函数调用失败
// -5--connect()函数调用失败
//Arguments:
// host --服务方的主机名称或IP地址
// service--服务方应用的端口号
// transport--name of transport protocol to use("tcp" or "udp")
int connectsock(const char *host, const char *service, const char *transport)
{
struct hostent *phe, *phe1; /*pointer to host information entry*/
struct servent *pse; /*pointer to service informattion entry*/
struct protoent *ppe; /*pointer to protocol information entry*/
struct sockaddr_in sin, client_addr; /*an internet endpoint address */
int s, type; /*socket descriptor and socket type */
u_long baddr;
int ret, len, buflen;
struct sockaddr *pSkAddr;
sprintf(gd_LogFile, "%s/%s", getenv("TCPLOGDIR"), TCPLOGFILE);
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
//Map service name to port number
if(pse = getservbyname(service, transport))
sin.sin_port = pse->s_port;
else if((sin.sin_port = htons((u_short)atoi(service))) == 0)
{
Tcpvwf(gd_LogFile, "In connectsock(), errno[%d]\n", errno);
return(-1);
}
//Map host name to IP address, allowing for dotted decimal
if(phe = gethostbyname(host))
{
memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
}
else
{
baddr = inet_addr(host) ;
if(baddr == INADDR_NONE)
{
Tcpvwf(gd_LogFile, "In connectsock gethostbyname inet_addr, errno[%d]\n", errno);
return(-2);
}
else
memcpy(&sin.sin_addr, &baddr, 4);
}
//Map transport protocol name to protocol number
if((ppe = getprotobyname(transport)) == 0)
{
Tcpvwf(gd_LogFile, "In connectsock getprotobyname, errno[%d]\n", errno);
return(-3);
}
//Use protocol to choose a socket type
if(strcmp(transport, "udp") == 0)
type = SOCK_DGRAM;
else
type = SOCK_STREAM;
//Allocate a socket
s = socket(PF_INET, type, ppe->p_proto);
if(s < 0)
{
Tcpvwf(gd_LogFile, "In connectsock socket, errno[%d]\n", errno);
return(-4);
}
//len = sizeof(int);
//buflen = 1024*60;
//ret = setsockopt(s, SOL_SOCKET, SO_RCVBUF, &buflen, len);
//if (ret < 0)
//{
// Tcpvwf(LogFile, "in setsockopt errno[%d]\n", errno);
// return(-1);
//}
//Tcpvwf(LogFile, "in setsockopt buflen[%d]\n", buflen);
//Connect the socket
pSkAddr = (struct sockaddr *)&sin;
if(connect(s, pSkAddr, sizeof(sin))<0)
{
Tcpvwf(gd_LogFile, "In connectsock connect, errno[%d]\n", errno);
close(s);
return(-5);
}
return(s);
}
//Function:启动服务端TCP应用
//Argument:
// service--服务端应用使用的端口号
// qlen--允许在排队使用套接字的客户端进程数
int passiveTCP(const char *service, int qlen)
{
return passivesock(service, "tcp", qlen);
}
//Function:启动服务端应用
// -1--service参数错误
// -2--transport--参数错误
// -3--socket()函数调用失败
// -4--bind()函数调用失败
// -5--listen()函数调用失败
//Arguments:
// service--服务端应用使用的端口号
// transport--transport protocol to use("tcp" or "udp")
// qlen--允许在排队使用套接字的客户端进程数
int passivesock(const char *service, const char *transport, int qlen)
{
int len, ret, type, sock ; /*socket descriptor and socket type */
struct servent *pse; /*pointer to service informattion entry*/
struct protoent *ppe; /*pointer to protocol information entry*/
struct sockaddr_in sin; /*an internet endpoint address */
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
struct linger optlinger;
//Map service name to port number
if(pse = getservbyname(service, transport))
sin.sin_port = htons(ntohs((u_short)pse->s_port) + gd_tcpportbase);
else if((sin.sin_port = htons((u_short)atoi(service))) == 0)
{
Tcpvwf(gd_LogFile, "in passivesock, errno[%d]\n", errno);
return(-1);
}
//Map transport protocol name to protocol number
ppe = getprotobyname(transport);
if(ppe == 0)
{
Tcpvwf(gd_LogFile, "in passivesock getprotobyname, errno[%d]\n", errno);
return(-2);
}
//Use protocol to choose a socket type
if(strcmp(transport, "udp") == 0)
type = SOCK_DGRAM;
else
type = SOCK_STREAM;
//Allocate a socket
sock = socket(PF_INET, type, ppe->p_proto);
if(sock < 0)
{
Tcpvwf(gd_LogFile, "in passivesock socket, errno[%d]\n", errno);
return(-3);
}
//struct linger optlinger;
//optlinger.l_onoff = 1;
//optlinger.l_linger = 0;
//len = sizeof(struct linger);
//ret = setsockopt(sock, SOL_SOCKET, SO_LINGER, &optlinger, len);
//if (ret < 0)
//{
// Tcpvwf(gd_LogFile, "in setsockopt SO_LINGER errno[%d]\n", errno);
// return(-1);
//}
//Bind the socket
if(bind(sock, (struct sockaddr *)&sin, sizeof(sin))<0)
{
Tcpvwf(gd_LogFile, "in passivesock bind, errno[%d]\n", errno);
close(sock);
return(-4);
}
if((type == SOCK_STREAM) && (listen(sock, qlen) < 0))
{
Tcpvwf(gd_LogFile, "in passivesock listen, errno[%d]\n", errno);
close(sock);
return(-5);
}
return(sock);
}
//Function:清理退出的子进程占用的系统资源
//Arguments:
//sig--信号SIGCHLD
void reaper(int sig)
{
int status, i;
while(wait3(&status, WNOHANG, (struct rusage *)0) >= 0)
{
i ++;
}
tcp_signal(SIGCHLD, reaper);
}
//交易报文头:ASC码0x01 + 报文头长度(3bytes,右对齐不足左补零)+
// 是否携带文件标志('0'-不带文件, '1'-携带文件) + 文件名长度('00'--'99') +
// 文件名称 + 交易报文体长度('00000001'-'99999999')
//readtxnmsghead--读交易报文头
//Argument:
// withfileflag--是否携带文件标志, 0-不带文件, 1-携带文件
// filename--携带的文件名称
// msglen--交易报文体长度
int readtxnmsghead(int sock, int *withfileflag, char *filename, int *msglen, int *filesize)
{
int i, j, rsize, ret;
int n; /*n-返回字节数 count-'read'执行次数*/
int pos;
char buf[512], head[512], str[128];
//交易报文头当前位置指针
pos = 0;
//读交易报文头第一个字节,以确定报文种类
n = read(sock, buf, 1);
if (n < 0) //超时,或网络异常
{
Tcpvwf(gd_LogFile, "In readtxnmsghead() read, ret[%d] errno[%d]\n", n, errno);
return -1;
}
//发来FIN信号
if (n == 0) return -1;
//head缓冲区用于存放报文头
head[pos] = buf[0];
pos ++;
i = 0;
if (buf[0] != 0x01) //交易报文
{
Tcpvwf(gd_LogFile, "In readtxnmsghead(), message type error buf[0]=[%d]\n", buf[0]);
return -1;
}
//读取报文头总长度
n = read(sock, buf, 3);
if (n <= 0) //超时,或网络异常或发来FIN信号
{
Tcpvwf(gd_LogFile, "In readtxnmsghead read, ret[%d] errno[%d]\n", n, errno);
return -1;
}
memcpy(head+pos, buf, n);
pos += n;
j = 3-n;
if (j > 0)
{
for (i=0; i msgbodylen)
rsize = msgbodylen-pos;
else
rsize = k;
n = read(sock, buf, rsize);
if (n <= 0) //超时,或网络异常, 发来FIN信号
{
Tcpvwf(gd_LogFile, "In readtxnmsgbody() read, ret[%d] errno[%d]\n", n, errno);
return -2;
}
memcat(buf, n, msgbody, pos);
pos += n;
//已读完报文体
if (pos == msgbodylen) break;
}
return 0;
}
//readtxnmsgfile--读交易报文携带文件
//Argument:
// sock--
// msgfilename--携带的文件名
// msgfilesize--携带文件大小
int readtxnmsgfile(int sock, char *msgfilename, int msgfilesize)
{
char path[512], fullfn[640], buf[1024];
int fd, pos, ret, n, i, j, k, c, rsize, pid, pid1;
strcpy(path, getenv("PRINTDIR"));
umask(0);
if (strlen(path) == 0)
sprintf(fullfn, "%s", msgfilename);
else
sprintf(fullfn, "%s/%s", path, msgfilename);
fd = creat(fullfn, 0644);
if (fd < 0)
{
Tcpvwf(gd_LogFile, "In readtxnmsgfile() creat, errno[%d]\n", errno);
return -1;
}
k = sizeof(buf);
//i=可将报文分成若干块
//i = msgfilesize / sizeof(buf);
//j=将报文分成若干块余数字节
//j = msgfilesize % sizeof(buf);
//c=报文总长-余数
//c = msgfilesize - j;
pos = 0;
for (;;)
{
if (pos+k > msgfilesize)
rsize = msgfilesize-pos;
else
rsize = k;
n = read(sock, buf, rsize);
if (n <= 0) //超时,或网络异常, 发来FIN信号
{
Tcpvwf(gd_LogFile, "In readtxnmsgfile read, ret[%d] errno[%d]\n", n, errno);
close(fd);
return -1;
}
ret = write(fd, buf, n);
if (ret != n)
{
Tcpvwf(gd_LogFile, "In readtxnmsgfile writefile, ret[%d] n[%d] errno[%d]\n", ret, n, errno);
close(fd);
return -1;
}
pos += n;
if (pos == msgfilesize) break;
}
close(fd);
return 0;
}
//交易报文头:ASC码0x01 + 报文头长度(3bytes,右对齐不足左补零)+
// 是否携带文件标志('0'-不带文件, '1'-携带文件) + 文件名长度('00'--'99') +
// 文件名称 + 交易报文体长度('00000001'-'99999999') +
// 携带文件长度('0000000000'-'9999999999')
//genmsghead-生成报文头
//Argument:
// srbufsize--报文主体长度
// msgfilename--交易报文后携带的文件, 若无msgfilename为空串
// msgbufhead--生成的交易报文头
// msgfilesize--交易携带文件大小
int genmsghead(int srbufsize, char *msgfilename, char *msgbufhead, int *msgfilesize)
{
int pos, slen, fd, ret;
char path[512], fullfn[640], buf[1024];
struct stat fbuf;
pos = 0;
//交易报文开始标志0x01
msgbufhead[0] = 0x01;
pos ++;
slen = strlen(msgfilename);
//传输的文件文件名不准超过99个字符
if (slen > 99)
{
Tcpvwf(gd_LogFile, "In genmsghead filename is too long, len[%d]\n", slen);
return -2;
}
//报文头长度
sprintf(msgbufhead+pos, "%03d", 25+slen);
//是否携带文件标志
pos += 3;
if (slen == 0)
msgbufhead[pos] = '0';
else
msgbufhead[pos] = '1';
//文件名长度
pos += 1;
sprintf(msgbufhead+pos, "%02d", slen);
//文件名称
pos += 2;
if (slen > 0)
sprintf(msgbufhead+pos, "%s", msgfilename);
//被发送报文体长度在1-99999999之间
if ((srbufsize < 1) || (srbufsize > 99999999))
{
Tcpvwf(gd_LogFile, "In genmsghead source buf is too large, [%d]\n", srbufsize);
return -2;
}
//报文体长度
pos += slen;
sprintf(msgbufhead+pos, "%08d", srbufsize);
//默认携带文件长度为0
*msgfilesize = 0;
//携带文件长度
pos += 8;
if (slen == 0)
sprintf(msgbufhead+pos, "%010d", 0);
else
{
strcpy(path, getenv("PRINTDIR"));
if (strlen(path) == 0)
sprintf(fullfn, "%s", msgfilename);
else
sprintf(fullfn, "%s/%s", path, msgfilename);
memset(&fbuf, 0, sizeof(struct stat));
ret = stat(fullfn, &fbuf);
if (ret != 0)
{
Tcpvwf(gd_LogFile, "In genmsghead stat, errno[%d]\n", errno);
return -1;
}
sprintf(msgbufhead+pos, "%010d", fbuf.st_size);
*msgfilesize = fbuf.st_size;
}
pos += 10;
msgbufhead[pos] = 0;
return 0;
}
//wrmsgfilebysock--写报文中携带文件
//Argument:
// msgfilename--报文中携带文件名
// msgfilesize--报文中携带文件长度
int wrmsgfilebysock(int sock, char *msgfilename, int msgfilesize)
{
char path[512], fullfn[640], buf[10240];
int fd, pos, n, ret, pid, pid1, i;
memset(path, 0, sizeof(path));
strcpy(path, getenv("PRINTDIR"));
if (strlen(path) == 0)
sprintf(fullfn, "%s", msgfilename);
else
sprintf(fullfn, "%s/%s", path, msgfilename);
fd = open(fullfn, O_RDONLY);
if (fd < 0)
{
Tcpvwf(gd_LogFile, "In wrmsgfilebysock open, errno[%d]\n", errno);
return -1;
}
pos = 0;
i = 0;
for (;;)
{
n = read(fd, buf, sizeof(buf));
i ++;
if (n < 0)
{
close(fd);
Tcpvwf(gd_LogFile, "In wrmsgfilebysock 被传送文件在exception now[%d] ori[%d]\n", pos, msgfilesize);
return -1;
}
if (n == 0)
{
if (pos != msgfilesize)
{
close(fd);
Tcpvwf(gd_LogFile, "In wrmsgfilebysock 被传送文件在exception now[%d] ori[%d]\n", pos, msgfilesize);
return -1;
}
else
return 0;
}
pos += n;
if (pos > msgfilesize)
{
close(fd);
Tcpvwf(gd_LogFile, "In wrmsgfilebysock 被传送文件在增长 now[%d] ori[%d]\n", pos, msgfilesize);
return -1;
}
ret = writesock(sock, buf, n);
if (ret < 0)
{
close(fd);
Tcpvwf(gd_LogFile, "In wrmsgfilebysock writesock errno[%d]\n", errno);
return -1;
}
if (pos == msgfilesize) break;
}
close(fd);
return 0;
}
//getpeerip:取得对方的IP地址和断口号
// return 0--Normal
// <0--Fail
//Argument:
// sock--插口
// PeerIP--对方IP
// PeerPort--对方端口号
int getpeerip(int sock, char *PeerIP, char *PeerPort)
{
int i,ret;
struct sockaddr addr;
int addrlen;
unsigned char ch;
char tmp[4];
struct sockaddr_in sin;
addrlen = sizeof(struct sockaddr);
ret = getpeername(sock, (struct sockaddr *)&addr, &addrlen);
if (ret < 0) //超时,或网络异常
{
Tcpvwf(gd_LogFile, "In sever getpeername, ret[%d] errno[%d]\n", ret, errno);
return -1;
}
memcpy(&sin, (struct sockaddr_in *)&addr, sizeof(struct sockaddr_in));
sprintf(PeerPort, "%d", sin.sin_port);
PeerIP[0] = 0;
for (i=0; i<4; i++)
{
ch = ((unsigned char *)(addr.sa_data))[i+2];
if (i < 3)
sprintf(tmp, "%d.", ch);
else
sprintf(tmp, "%d", ch);
strcat(PeerIP, tmp);
}
return 0;
}
//Function:内存连接
//Argument:
// sr--源指针
// slen--源数据长度
// dest--目标数据指针
// pos--源数据连接到目标数据的开始位置
int memcat(char *sr, int slen, char *dest, int pos)
{
int i, j;
memcpy(dest+pos, sr, slen);
return(0);
}
//Tcpvwf--记日志工具
//Argument:
// fn--被追加的日志文件名
// args--变参形式
int Tcpvwf(char *fn, char *args, ...)
{
va_list ap;
char *arr[128];
int argno = 0;
FILE *fp;
fp = fopen(fn, "a");
va_start(ap, args);
vfprintf(fp, args, ap);
fclose(fp);
va_end(ap);
return 0;
}
//cli_write--客户端发交易请求
//Argument:
// sock--
// hdata--客户端请求报文
// hsize--请求报文长度,可包含空字符
// hfile--携带的文件
int cli_write(int sock, char *hdata, int hsize, char *hfile)
{
int ret, withsfileflag, fd, n;
int hfilesize, sfilesize;
char msgbufhead[256], buf[1024];
//生成交易报文头msgbufhead
ret = genmsghead(hsize, hfile, msgbufhead, &hfilesize);
if (ret < 0)
{
close(sock);
return(-1);
}
//写报文头
ret = writesock(sock, msgbufhead, strlen(msgbufhead));
if (ret < 0)
{
close(sock);
return(-1);
}
//写报文主体
ret = writesock(sock, hdata, hsize);
if (ret < 0)
{
close(sock);
return(-1);
}
//若有携带文件
if (hfilesize > 0)
{
ret = wrmsgfilebysock(sock, hfile, hfilesize);
if (ret < 0)
{
close(sock);
return(-1);
}
}
return(0);
}
//Function:客户端向服务器发送交易,并接收回应结果
// 0--Normal
// <0--Fail
//Arguments:
// sock--插口
// hdata--被发送的数据
// hsize--被发送的数据长度
// hfile--发送携带的文件,strlen(hfile)==0表示不携带文件; 必须为该参数分配空间
// sdata--接收的服务端的回应报文
// ssize--回应报文长度
// sfile--若服务端有文件返回,它表示文件名称;strlen(file)==0表示不携带文件;
// 必须为该参数分配足够空间
int client_request(char *host, char *sevice, char *hdata, int hsize, char *hfile,
char *sdata, int *ssize, char *sfile)
{
int ret, withsfileflag;
int sockfd, hfilesize, sfilesize;
char msgbufhead[256];
//与服务端建立连接
sockfd = connectTCP(host, sevice);
if(sockfd < 0) return(-1);
//生成交易报文头msgbufhead
ret = genmsghead(hsize, hfile, msgbufhead, &hfilesize);
if (ret < 0)
{
close(sockfd);
return(-1);
}
//写报文头
ret = writesock(sockfd, msgbufhead, strlen(msgbufhead));
if (ret < 0)
{
close(sockfd);
return(-1);
}
//写报文主体
ret = writesock(sockfd, hdata, hsize);
if (ret < 0)
{
close(sockfd);
return(-1);
}
//若有携带文件
if (hfilesize > 0)
{
//发送携带文件
ret = wrmsgfilebysock(sockfd, hfile, hfilesize);
if (ret < 0)
{
close(sockfd);
return(-1);
}
}
//以下为读取服务端回应数据过程
//读取报文头
ret = readtxnmsghead(sockfd, &withsfileflag, sfile, ssize, &sfilesize);
if (ret < 0)
{
close(sockfd);
return -1;
}
//读交易报文体
ret = readtxnmsgbody(sockfd, *ssize, sdata);
if (ret < 0)
{
close(sockfd);
return -1;
}
//回应数据中若携带文件,读取携带文件
if (withsfileflag == 1)
{
ret = readtxnmsgfile(sockfd, sfile, sfilesize);
if (ret < 0)
{
close(sockfd);
return -1;
}
}
else
sfile[0] = 0;
close(sockfd);
return(0);
}
//Function:接收客户端发送来的数据
// 0--Normal
// -1--客户端发来断链请求
//Arguments:
// sock--插口
// hdata--接收到数据的存放地址
// hsize--接收到数据长度
int serv_read(int sock, char *hdata, int *hsize, char *hfile)
{
int ret, withhfileflag, hfilesize;
ret = readtxnmsghead(sock, &withhfileflag, hfile, hsize, &hfilesize);
if (ret < 0) return -1;
ret = readtxnmsgbody(sock, *hsize, hdata);
if (ret < 0) return -1;
if (withhfileflag == 1)
{
ret = readtxnmsgfile(sock, hfile, hfilesize);
if (ret < 0) return -1;
}
else
hfile[0] = 0;
return(0);
}
//Function:发送回应数据给客户端
// 0--Normal
// <0--Fail
//Arguments:
// sock--插口
// sdata--被发送数据
// ssize--数据长度
int serv_write(int sock, char *sdata, int ssize, char *sfile)
{
int ret, sfilesize;
char msgbufhead[256];
//生成交易报文头msgbufhead
ret = genmsghead(ssize, sfile, msgbufhead, &sfilesize);
if (ret < 0) return(-1);
//写报文头
ret = writesock(sock, msgbufhead, strlen(msgbufhead));
if (ret < 0) return(-1);
//写报文主体
ret = writesock(sock, sdata, ssize);
if (ret < 0) return(-1);
//若有携带文件
if (sfilesize > 0)
{
ret = wrmsgfilebysock(sock, sfile, sfilesize);
if (ret < 0) return(-1);
}
return(0);
}
//服务端应用SIGTERM信号的处理
void onquitsvrchild(int sig)
{
int i, ret;
for (i=0; i 0) i ++;
if (i == gd_tcpworksvrchildpidarrdim) break;
}
//父进程结束
exit(0);
}
//start_tcp_serv:起动面向连接的TCP服务器
// 1-- fail passivesock
// 2--accept函数调用失败
//Arguments:
// service--服务端口号
// qlen--等待队列长度
// fun--Server 收到请求时所执行的函数, 不可为NULL
// fconndb--外部应用程序提供的连接数据库函数, 可为NULL
// fdisconndb--外部应用程序提供的断开数据库函数, 可为NULL
// pnum--服务端进程数
//注:实参中fun, fconndb, fdisconndb三个函数不能重名
int start_tcp_serv(char *service, int qlen, int (*fun)(int sock),
int (*fconndb)(), int (*fdisconndb)(), int pnum)
{
int msock, ssock, hsize;
int n, i, j, ret, pid, pid1;
int alen;
struct sockaddr_in fsin;
fd_set infds;
int maxfd;
char asctm[7], ascday[9];
memset(gd_tcpworksvrchildpidarr, 0, sizeof(gd_tcpworksvrchildpidarr));
gd_tcpworksvrchildpidarrdim = pnum;
tcp_signal(SIGINT, SIG_IGN);
tcp_signal(SIGHUP, SIG_IGN);
//父进程收到终止信号后,结束所有服务端进程
tcp_signal(SIGTERM, onquitsvrchild);
sprintf(gd_LogFile, "%s/%s", getenv("TCPLOGDIR"), TCPLOGFILE);
//初始化服务端插口
msock = passivesock(service, "tcp", qlen);
if(msock < 0) return(1);
//启动若干服务端子进程
for (i=0; i 0)
{
gd_tcpworksvrchildpidarr[i] = pid;
printf("Child process %d is started.\n", pid);
}
else
{
Tcpvwf(gd_LogFile, "in start_tcp_serv(), fork() errno[%d] \n", errno);
return 1; //父进程收到退出码1,也不再重新创建进程
}
}
//父进程监控子进程状态,若子进程终止,父进程再重新创建一个子进程.
printf("Parent process %d is started.\n", pid);
i = 0;
for (;;)
{
ret = 0;
pid = wait(&ret);
//pid<0表示wait()操作被信号中断,这时再执行wait()操作,便会返回
//终止子进程进程号
if (pid < 0) continue;
ret >>= 8;
if (ret < 9) //应用退出码>=9,系统错退出码1--8
{
tcpdtime(asctm, ascday);
Tcpvwf(gd_LogFile, "pid %d is died exit[%d] time[%s]\n", pid, ret, asctm);
}
if (ret == 3) //若子进程连接数据库失败,应用将终止.
{
tcpdtime(asctm, ascday);
Tcpvwf(gd_LogFile, "pid %d is died for conn db fail time[%s]\n", pid, asctm);
//终止应用
onquitsvrchild(SIGTERM);
}
pid1 = fork();
if (pid1 == 0)
{
//连接数据库函数若不为NULL,则执行连接数据库操作.
if (fconndb != NULL)
{
ret = fconndb();
//若连接数据库失败,则子进程退出码约定为3
if (ret != 0) exit(3);
}
ret = TcpInWorkChild(msock, fun);
//若断开数据库函数不为空,则断开数据库
if (fdisconndb != NULL) fdisconndb();
exit(ret);
}
else if (pid1 < 0)
{
Tcpvwf(gd_LogFile, "in start_tcp_serv(), fork() errno[%d] \n", errno);
return 1; /*父进程收到退出码1,也不再重新创建进程*/
}
else
{
//更新父进程中进程号数组
for (i=0;i0--Normal
//Arguments:
// sock--插口
// hdata--宿主机数据流
// hsize--宿主机数据流长度
int writesock(int sock, char *hdata, int hsize)
{
int ret;
//Write to sock
ret = write(sock, hdata, hsize);
if(ret != hsize)
{
Tcpvwf(gd_LogFile, "In writesock(), ret != hsize ret[%d] hsize[%d] errno[%d]\n", ret, hsize, errno);
return -1;
}
return(0);
}
//ReadWait--检测插口描述符是否已经读就绪
// 0--Ready
// <0--Not Ready
//Argument:
// sockfds--插口描述符
// blocktime--若当时未就绪,检测过程等待的时间.
int ReadWait(int sockfds, int blocktime)
{
int n,i,tmp,maxsock = 0;
fd_set rdfd;
int readysocknum = 0;
struct timeval abc;
struct timeval timeout;
timeout.tv_sec = blocktime/1000;
timeout.tv_usec = blocktime%1000;
FD_ZERO(&rdfd);
FD_SET(sockfds, &rdfd);
maxsock = sockfds;
if (select(maxsock+1, &rdfd, (fd_set *)0, (fd_set *)0, &timeout) <0)
return -1;
if (FD_ISSET(sockfds, &rdfd)!=0)
return 0;
else
return -1;
}
int TcpRandNum()
{
int i, iseed;
char sec[20], tmp[8];
TcpMilSecond(sec);
memcpy(tmp, sec+12, 7);
tmp[7] = 0;
iseed = atol(tmp) + getpid();
srand(iseed);
i = rand();
i /= 100;
return i;
}
//TcpSleep一阻塞方式睡眠,可被超时信号中断
//stime--睡眠时间(单位:毫秒)
int TcpSleep(long stime)
{
struct timeval tv;
int tmp;
if (stime <= 0)
return 0;
tmp = stime%1000;
tv.tv_sec = stime / 1000;
tv.tv_usec = tmp*1000;
tmp = select(0,NULL,NULL,NULL,&tv);
if (tmp < 0) return -1;
return 0;
}
int TcpMilSecond(char *sec)
{
struct timeval first;
struct timezone tzp;
int ret;
ret = gettimeofday (&first, &tzp);
sprintf(sec, "%012d%07d", first.tv_sec, first.tv_usec);
return 0;
}
void *tcp_signal(int signo, void (*func)(int))
{
struct sigaction act, oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if (signo == SIGALRM)
{
#ifdef SA_INTERUPT
act.sa_flags |= SA_INTERUPT; //SunOS
#endif
}
else
{
#ifdef SA_RESTART
act.sa_flags |= SA_RESTART; //SVR4, 4.3+BSD
#endif
}
if (sigaction(signo, &act, &oact) < 0)
return (NULL);
return (void *)(oact.sa_handler);
}