Linux 서버 디자인 (1)

여기 서 말 하 는 것 은 단지 간단 한 server 모델 입 니 다!작은 링크 요청 을 처리 하기 위해 서 (설명: 요청 이 간단 하고 지속 시간 이 짧 습 니 다. 그러면 if  server 가 요청 할 때 fork 에서 처리 합 니 다. 요청 에 응답 하 는 것 보다 fork 시간 이 적 을 수 있 습 니 다. 그러면 불합리한 서비스 디자인 입 니 다) 그래서 저 희 는 'prefork' 와 'prethread' 모델 을 사용 합 니 다!
      유 닉 스 네트워크 프로 그래 밍 의 4 가지 모델 은: prefork: 메 인 프로 세 스 accept
                                                                                하위 프로 세 스 accept
                                                                prethread:
                                                                                 주 루틴 accept
                                                                                 서브 스 레 드 accept   (우선 메 인 스 레 드 와 하위 스 레 드 로 설명 합 니 다)
       첫 번 째 부분 은 '프 리 젠 테 이 션 프로 세 스' 로 처리 합 니 다.
       CODE_1: server 는: 주 프로 세 스 accept 입 니 다. 그러면 이것 은 네 가지 방법 중 가장 복잡 합 니 다. 프로 세 스 간 에 socket 설명 자 를 전달 하 는 문제 와 관련 되 기 때 문 입 니 다!(프로 세 스 간 전달 설명 자 는 이전 bolg 에서 있 었 습 니 다!) server 는 폴 링 방식 으로 socket 을 하위 프로 세 스에 전달 합 니 다!
       말 이 많 지 않 으 니 코드 를 붙 여 라.
 Server:
/*
	    :
	server         ,       server     pipe socket    ,
	server  accept,       , connfd  pipe      !
	                      !  server         !!!
	  :      select  epoll,  server       listen msg,  child
	           !  
*/

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <fcntl.h>

#define	PORT			6000
#define	MAXBACK	100
#define	MAXLINE		1024
#define	CHILD_NUM	10

typedef struct child_process
{
	pid_t		s_pid;			//!>     pid
	int		s_pipe_fd;		//!>        pipe 
	int		s_status;		//!>       !0:  1: 
}child_process;

child_process  child[CHILD_NUM];	//!>   10    (    10    )

static	int	n_child_use = 0;        //!>   child   ( if         )


//!>   socket   (              )
//!>
int send_fd( int fd_send_to, void * data, size_t len, int sock_fd )
{
	struct msghdr 	msghdr_send;		//!> the info struct
	struct iovec		iov[1];		//!> io vector
	size_t				n;      //!>
	
	union
	{
		struct cmsghdr	cm;		//!> control msg
		char 	ctl[CMSG_SPACE(sizeof( int ))];	//!> the pointer of char
	}ctl_un;
	
	struct cmsghdr * pCmsghdr = NULL;	//!> the pointer of control
	
	msghdr_send.msg_control = ctl_un.ctl;	
	msghdr_send.msg_controllen = sizeof( ctl_un.ctl );
	
	//!> design : the first info
	pCmsghdr = CMSG_FIRSTHDR( &msghdr_send );       //!> the info of head
	pCmsghdr->cmsg_len = CMSG_LEN(sizeof(int));     //!> the msg len
	pCmsghdr->cmsg_level = SOL_SOCKET; 		//!> -> stream mode           	
	pCmsghdr->cmsg_type = SCM_RIGHTS;  		//!> -> file descriptor
	*((int *)CMSG_DATA( pCmsghdr )) = sock_fd;	//!> data: the file fd 
	
	//!> these infos are nosignification
	msghdr_send.msg_name = NULL;			//!> the name	
	msghdr_send.msg_namelen = 0;			//!> len of name
	
	iov[0].iov_base = data;				//!> no data here
	iov[0].iov_len = len;				//!> the len of data
	
	msghdr_send.msg_iov = iov;			//!> the io/vector info
	msghdr_send.msg_iovlen = 1;			//!> the num of iov
	
	return ( sendmsg( fd_send_to, &msghdr_send, 0 ) );	//!> send msg now
}

//!>   socket   
//!> 
int recv_sock_fd( int fd, void * data, size_t len, int * recv_fd )
{
	struct msghdr 	msghdr_recv;		//!> the info struct
	struct iovec		iov[1];		//!> io vector
	size_t				n;	//!>
	
	union
	{
		struct cmsghdr	cm;		//!> control msg
		char 	ctl[CMSG_SPACE(sizeof( int ))];	//!> the pointer of char
	}ctl_un;
	
	struct cmsghdr * pCmsghdr = NULL;       //!> the pointer of control
	
	msghdr_recv.msg_control = ctl_un.ctl;	
	msghdr_recv.msg_controllen = sizeof( ctl_un.ctl );
	
	//!> these infos are nosignification
	msghdr_recv.msg_name = NULL;		//!> the name	
	msghdr_recv.msg_namelen = 0;		//!> len of name
	
	iov[0].iov_base = data;			//!> no data here
	iov[0].iov_len = len;			//!> the len of data
	
	msghdr_recv.msg_iov = iov;		//!> the io/vector info
	msghdr_recv.msg_iovlen = 1;		//!> the num of iov
	
	if( ( n = recvmsg( fd, &msghdr_recv, 0 ) ) < 0 )	//!> recv msg
	{						//!> the msg is recv by msghdr_recv
		printf("recv error : %d
", errno); exit(EXIT_FAILURE); } //!> now, we not use 'for' just because only one test_data_ if( ( pCmsghdr = CMSG_FIRSTHDR( &msghdr_recv ) ) != NULL //!> now we need only one, && pCmsghdr->cmsg_len == CMSG_LEN( sizeof( int ) ) //!> we should use 'for' when ) //!> there are many fds { if( pCmsghdr->cmsg_level != SOL_SOCKET ) { printf("Ctl level should be SOL_SOCKET :%d
", errno); exit(EXIT_FAILURE); } if( pCmsghdr->cmsg_type != SCM_RIGHTS ) { printf("Ctl type should be SCM_RIGHTS : %d
", errno); exit(EXIT_FAILURE); } *recv_fd =*((int*)CMSG_DATA(pCmsghdr)); //!> get the data : the file des* } else { *recv_fd = -1; } return n; } //!> //!> void web_child( int con_fd ) { char buf[MAXLINE]; int n_read; int i = 0; while( strcmp( buf, "Q" ) != 0 && strcmp( buf, "q" ) != 0 ) { memset( buf, 0, sizeof( buf ) ); if( ( n_read = read( conn_fd, buf, MAXLINE ) ) < 0 ) { printf( "Read errnr! :%d
", errno ); exit( EXIT_FAILURE ); } else if( n_read == 0 ) { continue; } else { while( buf[i] ) { buf[i] = toupper( buf[i] ); i++; } buf[i] = '\0'; printf("Child %d done!
", ( unsigned int )pthread_self()); printf("Child %d send %s
", ( unsigned int )pthread_self(), buf); write( conn_fd, buf, strlen( buf ) ); //!> client } } printf("Child %d : Dating end!
", ( unsigned int )pthread_self()); } //!> child process //!> void child_main( int i ) { char data; //!> socket, data ” “ int con_fd; //!> con_fd int n_read; //!> printf( "Child %d starting ...
", i ); while( 1 ) { if( ( n_read = recv_sock_fd( STDERR_FILENO, &data, 1, &con_fd ) ) == 0 ) { continue; //!> , //printf( " Child process %d read errnr! : %d
", i, errno ); //exit( EXIT_FAILURE ); } if( con_fd < 0 ) { printf("Child %d read connfd errnr! : %d
", i, errno); exit( EXIT_FAILURE ); } web_child( con_fd ); //!> child write( STDERR_FILENO, " ", 1 ); //!> server , 0 } } //!> //!> void child_make( int i, int listen_fd ) { int sock_fd[2]; //!> socket pair pid_t pid; //!> socketpair if( socketpair( AF_LOCAL, SOCK_STREAM, 0, sock_fd ) == -1 ) { printf( "create socketpair error : %d
", errno ); exit( EXIT_FAILURE ); } if( ( pid = fork() ) > 0 ) //!> { close( sock_fd[1] ); child[i].s_pid = pid; child[i].s_pipe_fd = sock_fd[0]; child[i].s_status = 0; return; } if( dup2( sock_fd[0], STDERR_FILENO ) == -1 ) //!> STDERR_FILENO sock { //!> child STDERR_FILENO ! printf("socket pair errnr! : %d
", errno); exit( EXIT_FAILURE ); } close( sock_fd[0] ); //!> bu ! close( sock_fd[1] ); close( listen_fd ); child_main( i ); //!> child } //!> MAIN PROCESS //!> int main( int argc, char ** argv ) { int i; int listen_fd; int conn_fd; int max_fd; int n_select; int n_read; char buf[5]; fd_set all_set, now_set; struct sockaddr_in servaddr; struct sockaddr_in cliaddr; int len = sizeof( struct sockaddr_in ); //!> server //!> bzero( &servaddr, sizeof( servaddr ) ); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl( INADDR_ANY ); servaddr.sin_port = htons( PORT ); //!> if( ( listen_fd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 ) { printf("Socket Error...
" , errno ); exit( EXIT_FAILURE ); } //!> //!> if( bind( listen_fd, ( struct sockaddr *)&servaddr, sizeof( servaddr ) ) == -1 ) { printf("Bind Error : %d
", errno); exit( EXIT_FAILURE ); } //!> //!> if( listen( listen_fd, MAXBACK ) == -1 ) { printf("Listen Error : %d
", errno); exit( EXIT_FAILURE ); } FD_ZERO( &all_set ); FD_SET( listen_fd, &all_set ); //!> listenfd select max_fd = listen_fd; for( i = 0; i < CHILD_NUM; i++ ) { child_make( i, listen_fd ); FD_SET( child[i].s_pipe_fd, &all_set ); //!> socket max_fd = max_fd > child[i].s_pipe_fd ? max_fd : child[i].s_pipe_fd; } while( 1 ) //!> { now_set = all_set; if( n_child_use >= CHILD_NUM ) //!> child { //!> listenfd , listen , child FD_CLR( listen_fd, &now_set ); } if( (n_select = select( max_fd + 1, &now_set, NULL, NULL, NULL )) == -1) { printf(" Main process select errnr~ :%d
", errno); exit( EXIT_FAILURE ); } if( FD_ISSET( listen_fd, &now_set ) ) //!> if { if( ( conn_fd = accept( listen_fd, ( struct sockaddr *)&cliaddr , &len ) ) == -1 ) { printf("Server accept errnr! : %d
", errno); exit( EXIT_FAILURE ); } for( i = 0; i < CHILD_NUM; i++ ) { if( child[i].s_status == 0 ) //!> child { break; } } if( i == CHILD_NUM ) //!> child { printf("All childs are busy!
"); exit( EXIT_FAILURE ); //!> , } child[i].s_status = 1; //!> busy n_child_use++; //!> busy child ++ send_fd( child[i].s_pipe_fd, " ", 1, conn_fd ); //!> socket close( conn_fd ); //!> server if( --n_select == 0 ) //!> { continue; } } for( i = 0; i < CHILD_NUM; i++ ) //!> child msg, server child { if( FD_ISSET( child[i].s_pipe_fd, &now_set ) ) { if( ( n_read = read( child[i].s_pipe_fd, buf, 5 ) ) == 0 ) //!> buf data , child server { printf("Child %d exit error! : %d
", i, errno); exit( EXIT_FAILURE ); } child[i].s_status = 0; //!> if( --n_select == 0 ) //!> if child for { break; } } } } return 0; }

Client:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include  <arpa/inet.h>
#include <sys/select.h>

#define MAXLINE 1024
#define SERV_PORT 6000

//!>       stdin,    server    
//!>    client     select     
void send_and_recv( int connfd )
{
	FILE * fp = stdin;
	int   lens;
	char send[MAXLINE];
	char recv[MAXLINE];
	fd_set rset;
	FD_ZERO( &rset );
	int maxfd = ( fileno( fp ) > connfd ? fileno( fp ) : connfd  + 1 );	
								//!>          
	int n;
	
	while( 1 )
	{
		FD_SET( fileno( fp ), &rset );
		FD_SET( connfd, &rset );			//!>      rset          
								//!>                  ,
								//!>          !        !
		
		if( select( maxfd, &rset, NULL, NULL, NULL ) == -1 )
		{
			printf("Client Select Error..
"); exit(EXIT_FAILURE ); } //!> if if( FD_ISSET( connfd, &rset ) ) //!> if { printf( "client get from server ...
" ); memset( recv, 0, sizeof( recv ) ); n = read( connfd, recv, MAXLINE ); if( n == 0 ) { printf("Recv ok...
"); break; } else if( n == -1 ) { printf("Recv error...
"); break; } else { lens = strlen( recv ); recv[lens] = '\0'; //!> stdout write( STDOUT_FILENO, recv, MAXLINE ); printf("
"); } } //!> if stdin if( FD_ISSET( fileno( fp ), &rset ) ) //!> if { //!> printf("client stdin ...
"); memset( send, 0, sizeof( send ) ); if( fgets( send, MAXLINE, fp ) == NULL ) { printf("End...
"); exit( EXIT_FAILURE ); } else { //!>if( str ) lens = strlen( send ); send[lens-1] = '\0'; //!> //!> : !!!!!!!! if( strcmp( send, "q" ) == 0 ) { printf( "Bye..
" ); return; } printf("Client send : %s
", send); write( connfd, send, strlen( send ) ); } } } } int main( int argc, char ** argv ) { //!> char * SERV_IP = "10.30.97.188"; char buf[MAXLINE]; int connfd; struct sockaddr_in servaddr; if( argc != 2 ) { printf("Input server ip !
"); exit( EXIT_FAILURE ); } //!> if( ( connfd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 ) { printf("Socket Error...
" , errno ); exit( EXIT_FAILURE ); } //!> bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(SERV_PORT); inet_pton(AF_INET, argv[1], &servaddr.sin_addr); //!> server if( connect( connfd, ( struct sockaddr * )&servaddr, sizeof( servaddr ) ) < 0 ) { printf("Connect error..
"); exit(EXIT_FAILURE); } /*else { printf("Connet ok..
"); }*/ //!> //!> send and recv send_and_recv( connfd ); //!> close( connfd ); printf("Exit
"); return 0; }

CODE_2: server 는 "하위 프로 세 스 accept" 입 니 다. 그러면 첫 번 째 보다 간단 합 니 다. 그러나 새로운 문 제 는 하위 프로 세 스 가 "accept" 를 빼 앗 으 려 면 반드시 "상호 배척" accept 문제 가 존재 합 니 다. 물론 저 희 는 파일 자 물 쇠 를 사용 할 수 있 지만 효율 이 낮 습 니 다. 그리고 여기 서 는 하나의 실험 일 뿐 이 므 로 "스 레 드 상호 배척 량" 을 사용 합 니 다.어 울 리 지 않 는 것 같 아, 흐흐 흐! ~
Server:
/*
	    :
	server         ,        accept,
	                ,        
	  !
	        ,        !
*/

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/select.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <fcntl.h>

#define	PORT			6000
#define	MAXBACK	100
#define	MAXLINE		1024
#define	CHILD_NUM	10

pthread_mutex_t		g_mutex;		//!>    
pthread_mutexattr_t 	g_mattr ;		//!>   

//!>           
//!> 
void child_make( int i_num, int listen_fd )
{
	int 			i = 0;
	pid_t		pid;
	int			conn_fd;
	int			n_read;
	char		buf[MAXLINE];
	struct sockaddr_in cliaddr;
	int		len = sizeof( struct sockaddr_in );
	
	if( ( pid = fork() ) > 0 )
	{
		return;
	}
	
	while( 1 )
	{
		pthread_mutex_lock( &g_mutex );		//!>   
		
		if( ( conn_fd = accept( listen_fd, ( struct sockaddr *)&cliaddr , &len ) ) == -1 )
		{
			printf("Accept errnr! :%d
", errno); exit( EXIT_FAILURE ); } pthread_mutex_unlock( &g_mutex ); //!> if( ( n_read = read( conn_fd, buf, MAXLINE ) ) < 0 ) { printf( "Read errnr! :%d
", errno ); exit( EXIT_FAILURE ); } else if( n_read == 0 ) { continue; } else { while( buf[i] ) { buf[i] = toupper( buf[i] ); i++; } printf("Child %d done!
", i_num); printf("Child %d send %s
", i_num, buf); write( conn_fd, buf, strlen( buf ) ); //!> client } } } //!> MAIN PROCESS //!> int main( int argc, char ** argv ) { int i; int listen_fd; int conn_fd; int n_read; char buf[5]; struct sockaddr_in servaddr; //!> //!> pthread_mutexattr_init( &g_mattr ); pthread_mutexattr_setpshared( &g_mattr, PTHREAD_PROCESS_SHARED ); pthread_mutex_init( &g_mutex, &g_mattr ); //!> //!> server //!> bzero( &servaddr, sizeof( servaddr ) ); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl( INADDR_ANY ); servaddr.sin_port = htons( PORT ); //!> if( ( listen_fd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 ) { printf("Socket Error...
" , errno ); exit( EXIT_FAILURE ); } //!> //!> if( bind( listen_fd, ( struct sockaddr *)&servaddr, sizeof( servaddr ) ) == -1 ) { printf("Bind Error : %d
", errno); exit( EXIT_FAILURE ); } //!> //!> if( listen( listen_fd, MAXBACK ) == -1 ) { printf("Listen Error : %d
", errno); exit( EXIT_FAILURE ); } for( i = 0; i < CHILD_NUM; i++ ) { child_make( i, listen_fd ); } waitpid( 0 ); //!> pthread_mutex_destroy( &g_mutex ); //!> return 0; }

Client: 위 에 거 랑 똑 같 아!!!
여기까지 프로 세 스 의 간단 한 처리 로 끝 났 습 니 다. 다음 편 은 스 레 드 처리 입 니 다 ~ ~
Bye~

좋은 웹페이지 즐겨찾기