티스토리 뷰

노트/소스 코드

[C] Multi Thread Server Example

Jae-seong Yoo 2011. 12. 28. 09:59
/*********************************************************************************
* File Name : thread_server.c
*---------------------------------------------------------------------------------
* 간단한 쓰레드 서버
*---------------------------------------------------------------------------------
* gcc -o thread_server thread_server.c -lthread -lsocket -lnsl
*********************************************************************************/
#include <netdb.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <time.h>
#include <signal.h>
#include <thread.h>
#include <string.h>
#include <errno.h>
 
union sock
{
    struct sockaddr s;
    struct sockaddr_in i;
};
 
#define SMAX 15
 
struct scorebd
{
    time_t   tevent;
    thread_t thread;
    int sig;
} scorebd[SMAX];
 
mutex_t sb_lock;
thread_t thr_master;
 
void *handling(void *);
void handto();
void *timing(void *);
void timer();
void master();
 
void reqto(int);
int sigtype();
void thr_reg();
void thr_unreg();
 
main(int argc,char *argv[])
{
    int port;
    union sock sock,work;
    int wsd,sd;
    int addlen;
    
    struct sigaction siginfo;
    
    int i,rv,nrv;
    
    if(argc != 2) exit(1);
    else port = atoi(argv[1]);  /* 첫번째 아규먼트로 포트 설정 */
    
    sigemptyset(&(siginfo.sa_mask));
    sigaddset(&(siginfo.sa_mask),SIGHUP);
    sigaddset(&(siginfo.sa_mask),SIGALRM);
    sigprocmask(SIG_SETMASK,&(siginfo.sa_mask),NULL);
    
    if(thr_create(NULL,0,timing,NULL,0,NULL) == -1)
    {
        perror("Creating timing thread");
        exit(2);
    }
    
    thr_master = thr_self();
    
    sigemptyset(&(siginfo.sa_mask));
    sigaddset(&(siginfo.sa_mask),SIGUSR1);
    thr_sigsetmask(SIG_UNBLOCK,&(siginfo.sa_mask),NULL);
    siginfo.sa_handler = master;
    siginfo.sa_flags = 0;
    sigaction(SIGUSR1,&siginfo,NULL);
    
    if((sd = socket(AF_INET,SOCK_STREAM,0)) == -1)
    {
        perror("No socket");
        exit(1);
    }
    sock.i.sin_family = AF_INET;
    sock.i.sin_port = port;
    sock.i.sin_addr.s_addr = INADDR_ANY;
    
    if(bind(sd,&(sock.s),sizeof(struct sockaddr)) == -1)
    {
        perror("Bad Bind");
        exit(1);
    }
    if(listen(sd,5) == -1)
    {
        perror("Bad listen");
        exit(1);
    }
    
    while(1)
    { 
        wsd = accept(sd,&(work.s),&addlen);
        thr_create(NULL,0,handling,&wsd,0,NULL);
    }
}
 

void *timing(void *arg)
{
    struct sigaction siginfo;
    sigemptyset(&(siginfo.sa_mask));
    sigaddset(&(siginfo.sa_mask),SIGALRM);
    sigaddset(&(siginfo.sa_mask),SIGHUP);
    siginfo.sa_handler = timer;
    siginfo.sa_flags = 0; 
    thr_sigsetmask(SIG_UNBLOCK,&(siginfo.sa_mask),NULL);
    sigaction(SIGALRM,&siginfo,NULL);
    sigaction(SIGHUP,&siginfo,NULL);
    
    alarm(1);
    
    while(1)
    {
        pause();
        thr_yield();
    }
}
 
void timer(int sig)
{
    int i,n;
    time_t now;
    time(&now);
    mutex_lock(&sb_lock);
    
    for(i=0;i<SMAX;i++)
    {
        if(scorebd[i].thread)
        {
            if(sig == SIGHUP)
            {
                scorebd[i].sig = SIGHUP;
                thr_kill(scorebd[i].thread,SIGUSR1);
            }
            else if(sig == SIGALRM)
            {
                if(scorebd[i].tevent < now)
                {
                    scorebd[i].sig = SIGALRM;
                    thr_kill(scorebd[i].thread,SIGUSR1);
                }
            }
        }
    }
    if(sig == SIGHUP) thr_kill(thr_master,SIGUSR1);
    
    mutex_unlock(&sb_lock); 
    alarm(1);
    return;
}
 
void *handling(void *sd)
{
    int nrv,wsd;
    int i;
    char buff[BUFSIZ];
    FILE *logfp = NULL;
    struct sigaction siginfo;
    thread_t me;
    
    wsd = *(int *)sd;
    
    me = thr_self();
    
    sigemptyset(&(siginfo.sa_mask));
    sigaddset(&(siginfo.sa_mask),SIGUSR1);
    thr_sigsetmask(SIG_UNBLOCK,&(siginfo.sa_mask),NULL);
    siginfo.sa_handler = handto;
    siginfo.sa_flags = 0;
    sigaction(SIGUSR1,&siginfo,NULL);
    
    thr_reg();
    
    while(1)
    {
        reqto(20);
        nrv = read(wsd,buff+i,BUFSIZ-i);
        
        if(nrv > 0)
        {
            char *crlfp;
            int fraglen;
 
            i += nrv;
            buff[i] = '\0';
            if(crlfp=strstr(buff,"\r\n"))
            {
                *crlfp = '\0';
                if(logfp == NULL)
                {
                    logfp = fopen(buff,"w");
                    if(logfp == NULL)
                    {
                        close(wsd);
                        return;
                    }
                }
                else fprintf(logfp,"%s\n",buff);
                fraglen = (buff+i)-(crlfp+2);
                if(fraglen)
                {
                    strcpy(buff,crlfp+2);
                    i = fraglen;
                }
                else i = 0;
            } 
            
        }
        else if (nrv == 0) 
        {
            close(wsd);
            fclose(logfp);
            thr_unreg();
            return;
        }
        else if(nrv < 0)
        { 
            switch(sigtype(me))
            {
                case SIGALRM : 
                write(wsd,"Timed out - bye\r\n",17);
                break;
                case SIGHUP :
                write(wsd,"Closing down - bye\r\n",20);
                break;
            }
            close(wsd);
            fclose(logfp);
            thr_unreg();
            return;
        }
        
    } /* while */
}
 
void reqto(int dt)
{
    time_t now;
    thread_t me;
    int i;
    time(&now);
    me = thr_self();
    mutex_lock(&sb_lock);
    for(i=0;i<SMAX;i++)
    {
        if(scorebd[i].thread == me)
        {
            scorebd[i].tevent = now + dt;
            break;
        }
    }
    if(i == SMAX) abort();
    mutex_unlock(&sb_lock);
}
 
int sigtype()
{
    thread_t me;
    int i,rv = 0;
    me = thr_self();
    mutex_lock(&sb_lock);
    for(i=0;i<SMAX;i++)
    {
        if(scorebd[i].thread == me)
        {
            rv = scorebd[i].sig;
            scorebd[i].sig = 0;
            break;
        }
    }
    mutex_unlock(&sb_lock);
    return rv;
}
 

void thr_reg()
{
    thread_t me;
    int i;
    me = thr_self();
    mutex_lock(&sb_lock);
    for(i=0;i<SMAX;i++)
    {
        if(scorebd[i].thread == 0)
        {
            scorebd[i].thread = me;
            break;
        }
    }
    if(i==SMAX) abort();
    mutex_unlock(&sb_lock);
    return;
}
 
void thr_unreg()
{
    thread_t me;
    int i;
    me = thr_self();
    mutex_lock(&sb_lock);
    for(i=0;i<SMAX;i++)
    {
        if(scorebd[i].thread == me)
        {
            scorebd[i].thread = 0;
            break;
        }
    }
    if(i == SMAX) abort();
    mutex_unlock(&sb_lock);
    return;
}
 
void handto(int sig)
{
    return;
}
 
void master(int sig)
{
    int i;
    mutex_lock(&sb_lock);
    for(i=0;i<SMAX;i++)
    {
        if(scorebd[i].thread) thr_join(scorebd[i].thread,NULL,NULL);
    }
    mutex_unlock(&sb_lock);
    exit(0);
}