Linux系统下实现多线程客户/服务器(3)
来源:优易学  2011-12-29 17:04:09   【优易学:中国教育考试门户网】   资料下载   IT书店

线程或者是可汇合的(joinable)或者是脱离的(detached)。当可汇合的线程终止时,其线程ID和退出状态将保留,直到另外一个线程调用pthread_join。脱离的线程则像守护进程:当它终止时,所有的资源都释放,我们不能等待它终止。如果一个线程需要知道另一个线程什么时候终止,最好保留第二个线程的可汇合性。Pthread_detach函数将指定的线程变为脱离的。该函数通常被想脱离自己的线程调用,如:pthread_detach (pthread_self ( ));

第五个函数:

void pthread_exit(void *status);

该函数终止线程。如果线程未脱离,其线程ID和退出状态将一直保留到调用进程中的某个其他线程调用pthread_join函数。指针status不能指向局部于调用线程的对象,因为线程终止时这些对象也消失。有两种其他方法可使线程终止:

1. 启动线程的函数(pthread_creat的第3个参数)返回。既然该函数必须说明为返回一个void指针,该返回值便是线程的终止状态。

2. 如果进程的main函数返回或者任何线程调用了exit,进程将终止,线程将随之终止。

以下给出一个使用线程的TCP回射客户/服务器的例子,完成的功能是客户端使用线程给服务器发从标准输入得到的字符,并在主线程中将从服务器端返回的字符显示到标准输出,服务器端将客户端发来的数据原样返回给客户端,每一个客户在服务器上对应一个线程。利用该程序框架,通过扩展客户端和服务器端的处理功能,可以完成多种基于多线程的客户机/服务器程序。该程序在RedHat 6.0和TurboLinux4.02下调试通过。 共用头文件如下:(head.h)

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define MAXLINE 1024 
#define SERV_PORT 8000 
#define LISTENQ 1024 
static int sockfd; 
static FILE *fp;

公用函数如下(common.c):

/* 从一个描述字读文本行 */ 
ssize_t readline(int fd, void *vptr, size_t maxlen) 
{ 
ssize_t n, rc; 
char c, *ptr; 
for (n=1; n0) 
{ 
if ( (nwritten=write (fd, ptr, nleft ) )<=0 ) 
{ 
if (errno==EINTR ) 
nwritten=0; 
else 
return (-1); 
} 
nleft-=nwritten; 
ptr++=nwritten; 
}

 

客户端主程序如下:(client.c)

#include “head.h"; 
#include “common.c"; 
/* 在str_cli中定义的要被线程执行的函数 */ 
void *copyto (void *arg) 
{ 
char sendline[MAXLINE]; 
while (fgets (sendline,MAXLINE,fp) !=NULL ) 
writen(sockfd,sendline,strlen(sendline)); 
shutdown(sockfd,SHUT_WR); 
return(NULL); 
} 

void str_cli(FILE *fp_arg, int sockfd_arg) 
{ 
char recvline[MAXLINE]; 
pthread_t tid; 
sockfd=sockfd_arg; 
fp=fp_arg; 
pthread_creat(&tid, NULL, copyto, NULL); 
while (readline (sockfd,recvline,MAXLINE) >0) 
---- fputs(recvline,stdout); 
} 

int main ( int argc, char **argv ) 
{ 
int sockfd; 
struct sockaddr_in servaddr; 
if (argc!=2 ) 
printf ( “ usage: tcpcli " ); 
exit(0); 
bzero(&servaddr, sizeof (servaddr)) ; 
servaddr.sin_family=AF_INET; 
servaddr.sinport=htons(SERV_PORT); 
inet_pton (AF_INET, argv[1], &servaddr.sin_addr ); 
connect (sockfd, (struct sockaddr *)&servaddr, 
siziof (servaddr ) ); 
str_cli (stdin, sockfd ); 
exit (0 ); 
}

服务器端主程序如下:

#include “head.h"; 
#include “common.c"; 
void str_echo (int sockfd ) 
{ 
ssize_t n; 
char line[MAXLINE]; 
for (; ; ) 
{ 
if ( (n=readline (sockfd, line, MAXLINE) )==0) 
return; 
writen (sockfd, line, n); 
} 
} 

static void *doit ( void *arg) 
{ 
pthread_detach(pthread_self ( ) ); 
str_echo ( (int ) arg ); 
close ( (int ) arg ); 
return ( NULL ) ; 
} 

int main ( int argc, char **argv ) 
{ 
int listenfd, connfd; 
socklen_t addrlen,len; 
struct sockaddr_in cliaddr, servaddr; 
pthread_t tid; 
listenfd=socket (AF_INET, SOCK_STREAM, 0 ); 
bzero (&servaddr, sizeof (servaddr ) ); 
servaddr.sin_family=AF_INET; 
servaddr.sin_addr.s_addr=htonl (INADDR_ANY ); 
servaddr.sin_port=SERV_PORT; 
bind (listenfd, ( struct sockaddr * )&servaddr, sizeof 
(servaddr ) ); 
listen (listenfd, LISTENQ ); 
addrlen=sizeof ( cliaddr ); 
cliaddr=malloc(addrlen ); 
for ( ; ; ) 
{ 
len=addrlen; 
connfd=accept(listenfd, (struct sockaddr * )&cliaddr, &len ); 
pthread_creat ( &tid, NULL, &doit, ( void * )connfd ); 
} 
}

责任编辑:小草

文章搜索:
 相关文章
热点资讯
热门课程培训