日期:2014-05-16  浏览次数:20739 次

UNIX TCP回射服务器/客户端(5):多进程服务器

    《Unix网络编程》这本书附带了许多短小精美的小程序,我在阅读此书的时候,将书上的代码按照自己的理解重写了一遍(大部分是抄书上的),加深一下自己的理解(纯看书太困了,呵呵)。此例子在Ubuntu10.04上测试通过。

    PS:程序里使用了包裹函数(首字母是大写的函数)和常量(所有字母都是大写的常量)的声明在my_unp.h文件中,定义在unp_base.c和unp_thread.c中,地址:http://blog.csdn.net/aaa20090987/article/details/8096701

    程序简介:这是一个基本的多线程服务器模型。当一个客户端连接上服务器时,服务器就产生一个子线程来与客户端进行通信。这种通信机制效率比较低,但高于一个连接产生一个子进程的多进程服务器模型,和多进程服务器模型一样,最大连接数会受到系统的最大子线程数的限制。


上代码:

#include "my_unp.h"  

void str_echo(int sockfd)    
{    
	ssize_t n;    
	char buf[MAXLINE];    

again:    
	//从套接字中读取数据,写到buffer中去    
	//再将buffer中的数据写到套接字中去    
	while( (n=read(sockfd, buf, MAXLINE)) > 0 )    
		Writen(sockfd, buf, n);    

	//由于信号中断,没写或读成功任何数据    
	if( n<0 && errno==EINTR )    
		goto again;    
	else if( n < 0 )    
		error_quit("str_echo: read error");    
}    

static void *doit(void *arg)  
{  
	int connfd;  

	connfd = *((int *) arg);  
	free(arg);  

	//子线程不阻塞父线程  
	Pthread_detach(pthread_self());  
	//处理数据  
	str_echo(connfd);  
	//关闭连接  
	Close(connfd);  

	return(NULL);  
}  

int main(int argc, char **argv)  
{  
	int  listenfd, *iptr;  
	pthread_t    tid;  
	socklen_t    addrlen, len;  
	struct sockaddr *cliaddr;
	struct sockaddr_in servaddr; 

	//开始监听  
	listenfd = Socket(AF_INET, SOCK_STREAM, 0);    
	memset(&servaddr, 0, sizeof(servaddr));    
	servaddr.sin_family = AF_INET;    
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);    
	servaddr.sin_port = htons(SERV_PORT);    

	addrlen = sizeof(struct sockaddr);
	//把socket和socket地址结构联系起来      
	Bind(listenfd, (SA*)&servaddr, sizeof(servaddr));    
	//开始监听LISTENQ端口    
	Listen(listenfd, LISTENQ);    
	cliaddr = Malloc(addrlen);  

	while(1)  
	{  
		len = addrlen;  
		iptr = Malloc(sizeof(int));  
		*iptr = Accept(listenfd, cliaddr, &len);  
		//为每个连接新建一个线程  
		Pthread_create(&tid, NULL, &doit, iptr);  
	}  
	return 0;  
}  

与其配套的客户端在这里:http://blog.csdn.net/aaa20090987/article/details/8462262