Client-Server模式的TCP/IP网络编程中,当客户端与服务器端建立起TCP连接时,我们会
遇到连接中断的情况,此时怎样处理呢?
首先,我们应使两端的通讯进程尽量"健壮"些,以避免一些干扰。为此,我们可以调用S
ignal (SIGINT, SIG_IGN)、singnal (SIGHUP,
SIG_IGN)、signal (SIGQUIT, SGI_IGN),
来屏蔽掉一些可以导致进程终止的信号。
其次,当一TCP连接中断时,对基于该连接的socket的系统调用read的返回值为0,由此,
我们可以设计服务器端的代码如下:
# include
# include
# include
# include
# include
# include
struct msgdata {
long msgtype;
char msgdata [1024];
}
main (argc, argv)
int argc;
char **argv;
{
int forkid;
if (argc !=2
{
printf (:usages:%s localport/n", argv[0]);
exit(2);
}
signal (SIGINT, SIG_IGN)
signal (SIGHUP, SIG_IGN)
signal (SIGQUIT, SIG_IGN)
signal (SIGTERM, SIG_IGN)
for (;;) {
if((forkid=fork())==0) lmsgl(atoi (argv[1]);
else
{
wait (( int*)0); /* here this process is waiting for
the creat
ed
sleep(5)
} /*process to be dead
}
}
lmsgl (localport)
int localport;
{
long forkid;
int namelen, newsock, sock, i, datalen;
int goback ();
struct msgdata td, rd;
struct sockaddr-in sin={AF_INET};
sin. sin-prort=localport;
datalen=sizeof (struct msgdata);
namelen=sizeof (sin);
if((sock=socket (AF-INET, DOCK-STREAM,
IPPROTO-TCP))<=0)
{
perror ("socket");
exit (1);
}
if(bind (sock, &sin, sizeof (sin))<0)
{ perror ("bind");
exit(2);
}
if (getsockname (sock, &sin,
&namelen)<0)
{
perror ("getsockname");
exit(2);
}
printf ("Server bound to port %u 0x%x/n", ntohs
(sin, sin-port), sin.s
in-port);
if (listen (sock, 5)<0)
{ perror ("listen");
exit (4);
}
if ((newsock=accept (sock, &sin,
&namelen))<0)
{ perror ("accept");
exit (5);
}
switch (forkid=fork()) {
case-1;
/*error number returned!
printf ("fork error/n:);
perror ("fork");
exit (5);
case
close (sock);
for (;;)
{
i=read (newsock, &rd, datalen);
if (i==0)
{
printf("/nthe connection is terminated!/n");
close (newsock);
exit (6);
}
/*Bere we kill the child process and
/*send SIGHLD to the parent process
do something we are interesting.....
}
default: /*the parent process
close (sock);
signal (SIGHLD, goback (newsock));
/*catching the SIGCHLD signal, jump to the
beginning
for (;;)
//do something we are interesting.....
{
i=write (newsock, &td, datalen);
if (i=-1)
{
printf ("TCP/IP write error!/n");
perror ("write");
continue;
} /*end of switch
} /*end of lmsge
goback (newsock)
int newsock;
{
signal (SIGINT, SIG_IGN);
close (newsock);
printf ("Go Back to Beginning/n");
exit (7);
}
以上代码中,一祖父进程调用fork ()创建一父进程,然后挂起父进程,等待客户端的连
接请求,一旦TCP连接建立起来,父进程又创造一子进程;此时父进程负责向已建立连接的ne
wsock中写入信息,子进程负责从newsock中读取信息。当TCP连接中断时,子进程的read返回
值为0,那么它便终止运行;同时向父进程发送SIGCHLD信号。在父进程中,我们设置signal
(SIGCHLD,
goback),当捕捉到SIGCHLD信号时,提示中断信息,然后终止进程。由于我们在祖
父进程中,用wait ( (int *)
0)来实现进程同步,这时祖父进程便被激活,它启动另外一父
进程,等待客户端的连接请求,当请求到来时,新的TCP连接便能建立起来。
另外,在某些情况下,我们可以把Client-Server模式做得对等起来,也就是说一端既可
以等待连接要求,也可以主动地请求连接。这样当TCP连接中断时,通信系统的两端便能智能
地在server、Client之间随机转换,直到TCP连接建立,此时的通讯系统便很少需要人为的干
预,这样的模式做起来需要些技巧,留作以后讨论。