UNIX TCP回射服务器/客户端(7)

程序简介:这是一个基本的线程池服务器模型。服务器启动时,先启动N个用于处理与客户端通信的子线程。当一个客户端连接上服务器时(accept),各个空闲的子线程都会去accept这个连接,但因为互斥锁的关系,总能保证有且只有一个线程会accept成功。然后这个子线程就会与客户端进行通信。

上代码:

#include "my_unp.h"

typedef struct
{
 pthread_t thread_tid; //线程ID
 long thread_count;  //线程处理的条数
} Thread;

Thread *tptr;
int    listenfd, nthreads;
socklen_t  addrlen;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

//接受来自客户端字符串,然后再原样返回
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"); 
}

void *thread_main(void *arg)
{
 int    connfd;
 socklen_t  clilen;
 struct sockaddr *cliaddr;

cliaddr = Malloc(addrlen);

printf("thread %d starting\n", (int) arg);
 while(1)
 {
  //当请求到达时,加锁,接收,解锁,处理数据
  //这样就保证了每个请求只能被一个随机线程所处理
  clilen = addrlen;
  Pthread_mutex_lock(&lock);
  connfd = Accept(listenfd, cliaddr, &clilen);
  Pthread_mutex_unlock(&lock);
  tptr[ (int)arg ].thread_count++;
  str_echo(connfd);
  Close(connfd);
 }
}

int main(int argc, char **argv)
{
 int  i;
 struct sockaddr_in servaddr;
 if( argc != 2 )
  error_quit("Using: server <#thread num>");

//创建用于TCP协议的套接字 
 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); 

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

nthreads = atoi(argv[1]);
 tptr = Calloc(nthreads, sizeof(Thread));

//创建处理线程,并让主线程挂起
 for (i = 0; i < nthreads; i++)
 {
  Pthread_create(&tptr[i].thread_tid, NULL,
   &thread_main, (void *)i);
 }
 pause();

return 0;
}

与其配套的客户端在这里:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/705b6d211bf1cc988c7ad0b9b8966423.html