linux下服务器例子,linux下http服务器经典例子2

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define _GNU_SOURCE

#include

#define

SERVER_NAME "tmhttpd/1.0.0_alpha"

#define

VERSION "1.0.0

alpha"

#define

BUFFER_SIZE 8192

#define

REQUEST_MAX_SIZE 10240

#define

IS_DEBUG 0 #define

IS_DAEMON 0 #define IS_BROWSE 0 #define

IS_LOG 0 #define

DEFAULT_HTTP_PORT 80 #define

DEFAULT_MAX_CLIENT 100 #define

DEFAULT_DOCUMENT_ROOT "./" #define

DEFAULT_DIRECTORY_INDEX "index.html" #define

DEFAULT_LOG_PATH "/tmp/tmhttpd.log"

struct st_request_info {

char *method;

char *pathinfo;

char *query;

char *protocal;

char *path;

char *file;

char *physical_path;

};

static unsigned short g_is_debug = IS_DEBUG;

static unsigned short g_is_daemon =

IS_DAEMON;

static unsigned short g_is_browse =

IS_BROWSE;

static unsigned short g_is_log =

IS_LOG;

static unsigned int

g_port =

DEFAULT_HTTP_PORT;

static unsigned int g_max_client =

DEFAULT_MAX_CLIENT;

static char

g_dir_index[32] =

DEFAULT_DIRECTORY_INDEX;

static char

g_doc_root[256] =

DEFAULT_DOCUMENT_ROOT;

static char

g_log_path[256] =

DEFAULT_LOG_PATH;

static int

g_log_fd =

0;

void die(char *mess){

perror(mess);

exit(1);

}

static char *substr( const char *s, int start_pos, int length, char

*ret ){

char

buf[length+1];

int i, j,

end_pos;

int str_len = strlen(s);

if

(str_len <= 0 || length < 0){

return

""; }

if (length == 0){

length = str_len -

start_pos;

}

start_pos = ( start_pos < 0 ?

(str_len + start_pos) : ( start_pos==0 ? start_pos : start_pos-- )

);

end_pos = start_pos + length;

for(i=start_pos, j=0; i<=length; i++, j++){

buf[j] =

s[i]; }

buf[length]

= '\0';

strcpy(ret,

buf);

return(ret);

}

static void explode(char *from, char delim, char ***to, int

*item_num){

int i, j, k,

n, temp_len;

int max_len

= strlen(from) + 1;

char

buf[max_len], **ret;

for(i=0,

n=1; from[i]!='\0'; i++){

if (from[i] == delim) n++;

}

ret = (char

**)malloc(n*sizeof(char *));

for (i=0,

k=0; k

memset(buf, 0,

max_len); for(j=0; from[i]!='\0' &&

from[i]!=delim; i++, j++) buf[j] = from[i];

i++;

temp_len = strlen(buf)+1;

ret[k] = malloc(temp_len);

memcpy(ret[k], buf, temp_len);

}

*to =

ret;

*item_num =

n;

}

static char *strtolower( char *s ){

int i, len = sizeof(s);

for( i = 0; i < len; i++ ){

s[i] = ( s[i] >=

'A' && s[i] <= 'Z' ?

s[i] + 'a' - 'A' : s[i] );

}

return(s);

}

static char *strtoupper( char *s ){

int i, len = sizeof(s);

for( i = 0; i < len; i++ ){

s[i] = ( s[i] >=

'a' && s[i] <= 'z' ?

s[i] + 'A' - 'a' : s[i] );

}

return(s);

}

static int strpos (const char *s, char c){

int i, len;

if (!s || !c) return -1;

len = strlen(s);

for (i=0; i

if (s[i] == c) return i;

}

return -1; }

static int strrpos (const char *s, char c){

int i, len;

if (!s || !c) return -1;

len = strlen(s);

for (i=len; i>=0; i--){

if (s[i] == c) return i;

}

return -1;

}

static char *trim( char *s

){ int

l; for(

l=strlen(s); l>0 &&

isspace((u_char)s[l-1]); l-- ){

s[l-1] =

'\0'; }

return(s); }

static char *ltrim( char *s

){ char

*p; for(p=s;

isspace((u_char)*p); p++

); if( p!=s )

strcpy(s, p); return(s); }

static long filesize(const char *filename){

struct stat

buf;

if

(!stat(filename, &buf)){

return buf.st_size;

}

return

0;

}

static int file_exists(const char *filename){

struct stat

buf;

if

(stat(filename, &buf) < 0){

if (errno == ENOENT){

return 0;

}

}

return

1;

}

static int file_get_contents( const char *filename, size_t

filesize, char *ret, off_t length ){

if ( !file_exists(filename) || access(filename,

R_OK)!=0 ) return -1;

int fd;

char buf[filesize];

if ( (fd = open(filename, O_RDONLY)) == -1)

return -1;

length = ( length > 0 ? length :

filesize);

read(fd, buf, length);

strcpy(ret, buf);

close(fd);

return 0;

}

static int is_dir(const char *filename){

struct stat buf;

if ( stat(filename, &buf)

< 0 ){

return -1;

}

if (S_ISDIR(buf.st_mode)){

return 1;

}

return 0;

}

static int is_file(const char *filename){

struct stat buf;

if ( stat(filename, &buf)

< 0 ){

return -1;

}

if (S_ISREG(buf.st_mode)){

return 1;

}

return 0;

}

static void getdate(char

*s){ //获得日期时间函数

char

*wday[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};

time_t timep;

struct tm *p;

time(&timep);

p = localtime(&timep);

sprintf(s, "%d-%d-%d

%d:%d:%d",(1900+p->tm_year),

(1+p->tm_mon), p->tm_mday,

p->tm_hour, p->tm_min,

p->tm_sec);

}

static void mime_content_type( const char *name, char *ret

){ //根据文件名获取mime类型

char *dot,

*buf;

dot =

strrchr(name, '.'); //取得name字符串中'.'后的子字符串dot

if (

strcmp(dot, ".txt") == 0

){ //如果是.txt类型

buf = "text/plain";

} else if (

strcmp( dot, ".css" ) == 0 ){

buf = "text/css";

} else if (

strcmp( dot, ".js" ) == 0 ){

buf = "text/javascript";

} else if (

strcmp(dot, ".xml") == 0 || strcmp(dot, ".xsl") == 0 ){

buf = "text/xml";

} else if (

strcmp(dot, ".xhtm") == 0 || strcmp(dot, ".xhtml") == 0 ||

strcmp(dot, ".xht") == 0 ){

buf = "application/xhtml+xml";

} else if (

strcmp(dot, ".html") == 0 || strcmp(dot, ".htm") == 0 ||

strcmp(dot, ".shtml") == 0 || strcmp(dot, ".hts") == 0 ){

buf = "text/html";

} else if (

strcmp( dot, ".gif" ) == 0 ){

buf = "image/gif";

} else if (

strcmp( dot, ".png" ) == 0 ){

buf = "image/png";

} else if (

strcmp( dot, ".bmp" ) == 0 ){

buf = "application/x-MS-bmp";

} else if (

strcmp( dot, ".jpg" ) == 0 || strcmp( dot, ".jpeg" ) == 0 ||

strcmp( dot, ".jpe" ) == 0 || strcmp( dot, ".jpz" ) == 0 ){

buf = "image/jpeg";

} else if (

strcmp( dot, ".wav" ) == 0 ){

buf = "audio/wav";

} else if (

strcmp( dot, ".wma" ) == 0 ){

buf = "audio/x-ms-wma";

} else if (

strcmp( dot, ".wmv" ) == 0 ){

buf = "audio/x-ms-wmv";

} else if (

strcmp( dot, ".au" ) == 0 || strcmp( dot, ".snd" ) == 0 ){

buf = "audio/basic";

} else if (

strcmp( dot, ".midi" ) == 0 || strcmp( dot, ".mid" ) == 0 ){

buf = "audio/midi";

} else if (

strcmp( dot, ".mp3" ) == 0 || strcmp( dot, ".mp2" ) == 0 ){

buf = "audio/x-mpeg";

} else if ( strcmp( dot, ".rm" ) ==

0 || strcmp( dot, ".rmvb" ) == 0 || strcmp( dot,

".rmm" ) == 0 ){

buf = "audio/x-pn-realaudio";

} else if (

strcmp( dot, ".avi" ) == 0 ){

buf = "video/x-msvideo";

} else if (

strcmp( dot, ".3gp" ) == 0 ){

buf = "video/3gpp";

} else if (

strcmp( dot, ".mov" ) == 0 ){

buf = "video/quicktime";

} else if (

strcmp( dot, ".wmx" ) == 0 ){

buf = "video/x-ms-wmx";

} else if ( strcmp( dot, ".asf" ) ==

0 || strcmp( dot, ".asx" ) == 0 ){

buf = "video/x-ms-asf";

} else if (

strcmp( dot, ".mp4" ) == 0 || strcmp( dot, ".mpg4" ) == 0 ){

buf = "video/mp4";

} else if ( strcmp( dot, ".mpe" ) ==

0 || strcmp( dot, ".mpeg" ) == 0 || strcmp( dot,

".mpg" ) == 0 || strcmp( dot, ".mpga" ) == 0 ){

buf = "video/mpeg";

} else if (

strcmp( dot, ".pdf" ) == 0 ){

buf = "application/pdf";

} else if (

strcmp( dot, ".rtf" ) == 0 ){

buf = "application/rtf";

} else if ( strcmp( dot, ".doc" ) ==

0 || strcmp( dot, ".dot" ) == 0 ){

buf = "application/msword";

} else if ( strcmp( dot, ".xls" ) ==

0 || strcmp( dot, ".xla" ) == 0 ){

buf = "application/msexcel";

} else if ( strcmp( dot, ".hlp" ) ==

0 || strcmp( dot, ".chm" ) == 0 ){

buf = "application/mshelp";

} else if ( strcmp( dot, ".swf" ) ==

0 || strcmp( dot, ".swfl" ) == 0 || strcmp( dot,

".cab" ) == 0 ){

buf = "application/x-shockwave-flash";

} else if ( strcmp( dot, ".ppt" ) ==

0 || strcmp( dot, ".ppz" ) == 0 || strcmp( dot,

".pps" ) == 0 || strcmp( dot, ".pot" ) == 0 ){

buf = "application/mspowerpoint";

} else if (

strcmp( dot, ".zip" ) == 0 ){

buf = "application/zip";

} else if (

strcmp( dot, ".rar" ) == 0 ){

buf = "application/x-rar-compressed";

} else if (

strcmp( dot, ".gz" ) == 0 ){

buf = "application/x-gzip";

} else if (

strcmp( dot, ".jar" ) == 0 ){

buf = "application/java-archive";

} else if ( strcmp( dot, ".tgz" ) ==

0 || strcmp( dot, ".tar" ) == 0 ){

buf = "application/x-tar";

} else {

buf =

"application/octet-stream";

}

strcpy(ret, buf);

}

static void Usage(char *exefile){

fprintf(stderr,

"#=======================================\n");

fprintf(stderr, "#

TieMa(Tiny&Mini) Http Server\n");

fprintf(stderr, "# Version %s\n", VERSION);

fprintf(stderr, "# \n");

fprintf(stderr, "# heiyeluren \n");

fprintf(stderr,

"#=======================================\n\n");

fprintf(stderr, "Usage: %s [OPTION] ... \n", exefile);

fprintf(stderr, "\nOptions: \n\

-D, --is-deubg Is open debug

mode, default No\n\

-d, --is-daemon Is daemon

running, default No\n\

-p, --port=PORT Server listen

port, default 80\n\

-m, --max-client=SIZE Max

connection requests, default 100\n\

-L,

--is-log Is write access log,

default No\n\

-l, --log-path=PATH Access log

path, default /tmp/tmhttpd.log\n\

-b, --is-browse Is allow browse

file/dir list, default No\n\

-r, --doc-root=PATH Web

document root directory, default programe current directory

./\n\

-i, --dir-index=FILE Directory

default index file name, default index.html\n\

-h,

--help Print help

information\n");

fprintf(stderr, "\nExample: \n\

%s -d -p 80 -m 128 -L -l /tmp/access.log -b -r

/var/www -i index.html\n\

%s -d -p80 -m128 -L -l/tmp/access.log -b

-r/var/www -iindex.html\n\

%s --is-daemon --port=80 --max-client=128

--is-log --log-path=/tmp/access.log --is-browse --doc-root=/var/www

--dir-index=index.html\n\n", exefile, exefile, exefile);

}

static void PrintConfig(){

fprintf(stderr,

"===================================\n");

fprintf(stderr, " tmhttpd Configure

information\n");

fprintf(stderr,

"===================================\n");

fprintf(stderr, "Is-Debug\t = %s\n", g_is_debug ?

"Yes" : "No");

fprintf(stderr, "Is-Daemon\t = %s\n", g_is_daemon

? "Yes" : "No");

fprintf(stderr, "Port\t\t = %d\n", g_port);

fprintf(stderr, "Max-Client\t = %d\n",

g_max_client);

fprintf(stderr, "Is-Log\t\t = %s\n", g_is_log ?

"Yes" : "No");

fprintf(stderr, "Log-Path\t = %s\n",

g_log_path);

fprintf(stderr, "Is-Browse\t = %s\n", g_is_browse

? "Yes" : "No");

fprintf(stderr, "Doc-Root\t = %s\n",

g_doc_root);

fprintf(stderr, "Dir-Index\t = %s\n",

g_dir_index);

fprintf(stderr,

"===================================\n\n");

}

static int WriteLog( const char *message ){

if ( !g_is_log ){

fprintf(stderr, "%s",

message);

return 0;

}

if ( g_log_fd == 0 ){

if ( (g_log_fd =

open(g_log_path, O_RDWR|O_CREAT|O_APPEND,

S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1 ){

perror("open

log file error");

return

-1;

}

}

if (write(g_log_fd, message, strlen(message)) ==

-1){

perror("write log

error");

return -1;

}

return 0;

}

static int SendHeaders(int client_sock, int status, char *title,

char *extra_header, char *mime_type, off_t length, time_t mod

){

time_t

now;

char

timebuf[100], buf[BUFFER_SIZE], buf_all[REQUEST_MAX_SIZE],

log[8];

memset(buf,

0, strlen(buf));

sprintf(buf,

"%s %d %s\r\n", "HTTP/1.0", status, title);

strcat(buf_all, buf);

memset(buf, 0, strlen(buf));

sprintf(buf,

"Server: %s\r\n", SERVER_NAME);

strcat(buf_all, buf);

now =

time( (time_t*) 0 );

strftime(

timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(

&now ) );

memset(buf,

0, strlen(buf));

sprintf(buf,

"Date: %s\r\n", timebuf);

strcat(buf_all, buf);

if

(extra_header != (char*)0){

memset(buf, 0, strlen(buf));

sprintf(buf, "%s\r\n", extra_header);

strcat(buf_all, buf);

}

if

(mime_type != (char*)0){

memset(buf, 0, strlen(buf));

sprintf(buf, "Content-Type: %s\r\n", mime_type);

strcat(buf_all, buf);

}

if (length

>= 0){

memset(buf, 0, strlen(buf));

sprintf(buf, "Content-Length: %lld\r\n",

(int64_t)length); strcat(buf_all, buf);

}

if (mod !=

(time_t) -1 ){

memset(buf, 0, strlen(buf));

strftime( timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT",

gmtime( &mod ) );

sprintf(buf, "Last-Modified: %s\r\n", timebuf );

strcat(buf_all, buf);

}

memset(buf,

0, strlen(buf));

sprintf(buf,

"Connection: close\r\n\r\n");

strcat(buf_all, buf);

if ( g_is_debug ){

fprintf(stderr, "[ Response

]\n");

fprintf(stderr, "%s",

buf_all);

}

write(client_sock, buf_all, strlen(buf_all));

return 0;

}

static int SendError(int client_sock, int status, char *title, char

*extra_header, char *text ){

char

buf[BUFFER_SIZE], buf_all[REQUEST_MAX_SIZE];

SendHeaders(

client_sock, status, title, extra_header, "text/html", -1, -1

);

memset(buf,

0, strlen(buf));

sprintf(buf,

"\n

\n\n\n\n

%d %s

\n", status, title, SERVER_NAME, status, title);

strcat(buf_all, buf);

memset(buf, 0, strlen(buf));

sprintf(buf,

"%s\n", text);

strcat(buf_all, buf);

memset(buf, 0, strlen(buf));

sprintf(buf,

"\n

\n

%s

\n\n\n", SERVER_NAME);

strcat(buf_all, buf);

write(client_sock, buf_all, strlen(buf_all));

exit(0);

}

static int SendFile( int client_sock, char *filename, char

*pathinfo ){ //发送文件函数

char

buf[128], contents[8192],

mime_type[64]; //定义字符数组buf, contents, mime_type

int

fd;

size_t

file_size;

//获得 mime 类型,发送http包头信息

mime_content_type(filename,

mime_type); //根据文件名filename获得mime 类型

SendHeaders(

client_sock, 200, "OK", "", mime_type, filesize(filename),

0); //发送http包头信息

if ( (fd =

open(filename, O_RDONLY)) == -1

){ //以只读的方式打开文件filename

memset(buf, '\0', sizeof(buf));

sprintf(buf, "Something unexpected went wrong read file %s.",

pathinfo);

SendError( client_sock, 500, "Internal Server Error", "",

buf);

}

file_size =

filesize(filename); //获得该文件的大小

if ( file_size <

8192){ //如果文件大小file_size小于8k

read(fd, contents,

8192); //将文件fd中的内容读入字符数组contents

write( client_sock, contents,

file_size ); //将该内容发送给客户端

} else

{ //如果文件大小file_size大于8k

while ( read(fd, contents,

8192) > 0

){ //进行循环读取发送,直到完成

write(

client_sock, contents, 8192 );

memset(contents,

'\0', sizeof(contents));

}

}

close( fd

);

if

(g_is_debug){

printf("request filename: %s\n", filename);

printf("request pathinfo: %s\n", pathinfo);

}

return 0;

}

static int SendDirectory( int client_sock, char *path, char

*pathinfo

){ //发送文件目录

size_t file_size;

char msg[128], buf[10240], tmp[1024],

tmp_path[1024]; //定义字符数组msg, buf,tmp,tmp_path

DIR

*dp; // 目录结构体指针

struct dirent

*node; //当前目录的节点

if ( (dp = opendir(path)) == NULL

){ //根据目录获得目录的结构体指针

memset(buf, 0,

sizeof(msg));

sprintf(msg, "Something

unexpected went wrong browse directory %s.", pathinfo);

SendError( client_sock, 500,

"Internal Server Error", "", msg);

}

memset(tmp_path, 0,

sizeof(tmp_path)); //初始化临时目录

substr(pathinfo, -1, 1,

tmp_path); //检测pathinfo中是否含有"/",如果没有,需要在tmp_path后追加'\'

if ( strcmp(tmp_path, "/") == 0){

memset(tmp_path, 0,

sizeof(tmp_path));

strcpy(tmp_path,

pathinfo);

} else {

memset(tmp_path, 0,

sizeof(tmp_path));

strcpy(tmp_path,

pathinfo); strcat(tmp_path, "/");

}

sprintf( tmp, "\n

\n\n\n

Directory %s

\n

\n

\n", pathinfo, SERVER_NAME,

pathinfo );

strcat(buf, tmp);

while ( (node = readdir(dp)) !=

NULL){ //从目录结构体指针dp中获得node结构体节点

if (

strcmp(node->d_name, ".") != 0){

memset(tmp,

0, sizeof(tmp));

sprintf(tmp,

"\t

\n", tmp_path,

node->d_name, node->d_name);

strcat(buf,

tmp);

}

}

memset(tmp,

0, sizeof(tmp));

sprintf(tmp,

"\n

\n

\n

%s

\n\n\n", SERVER_NAME);

strcat(buf,

tmp);

file_size = strlen(buf);

SendHeaders( client_sock, 200, "OK", "",

"text/html", file_size, 0 );

write( client_sock, buf, file_size );

return 0;

}

static int ProcRequest( int client_sock, struct sockaddr_in

client_addr, struct st_request_info request_info

){ //处理客户端的请求

char buf[128];

if ( !file_exists( request_info.physical_path )

){ //检测客户端请求的路径文件是否存在

memset(buf, 0,

sizeof(buf)); sprintf(buf, "File %s not

found.", request_info.pathinfo);

SendError( client_sock, 404,

"Not Found", "", buf);

}

if ( access(request_info.physical_path, R_OK) !=

0

){ //进入该路径

memset(buf, 0,

sizeof(buf));

sprintf(buf, "File %s is

protected.", request_info.pathinfo);

SendError( client_sock, 403,

"Forbidden", "", buf);

}

if ( is_file(request_info.physical_path) == 1

){ //判断是一个普通文件或者目录 SendFile(

client_sock, request_info.physical_path,

request_info.pathinfo

); //向客户端发送文件的路径和请求目录信息

} else if ( is_dir(request_info.physical_path)

== 1

){ //如果是一个目录

if ( g_is_browse ){

SendDirectory(

client_sock, request_info.physical_path, request_info.pathinfo );

//向客户端发送文件的路径和请求目录信息

} else {

memset(buf,

0, sizeof(buf));

sprintf(buf,

"File %s is protected.", request_info.pathinfo);

SendError(

client_sock, 403, "Forbidden", "", buf);

}

} else {

memset(buf, 0,

sizeof(buf));

sprintf(buf, "File %s is

protected.", request_info.pathinfo);

SendError( client_sock, 403,

"Forbidden", "", buf); }

return 0;

}

static int ParseRequest( int client_sock, struct sockaddr_in

client_addr, char *req ){ //这个就是客户端的请求消息

char **buf, **method_buf,

**query_buf, //定义字符串指针,指向常量字符串,分别为方法字符串,查询字符串

currtime[32], cwd[1024], tmp_path[1536],

pathinfo[512], //当前时间字符数组,临时目录,目录信息字符数组

path[256], file[256],

log[1024]; //目录字符串,文件字符数组,记录字符数组

int line_total, method_total, query_total,

i; //line_total所有的行,method_total所有的方法,query_total查询数

struct st_request_info

request_info; //定义一个请求信息结构体st_request_info 变量

getdate(currtime); //获得当前的信息

explode(req, '\n', &buf,

&line_total); //可能是获得请求信息的所有行数888888888888888888888888888888888888888888888888888、、、、、、、、、、、、、、、、、、、

memset(log, 0,

sizeof(log)); //初始化记录信息log,打印请求记录信息

sprintf(log, "[%s] %s %s\n", currtime,

inet_ntoa(client_addr.sin_addr),

buf[0]); WriteLog(log);

if (strcmp(buf[0], "\n") == 0 || strcmp(buf[0],

"\r\n") ==

0){ //通过对请求信息字符串的首字符串检测是否为'\n'和'\r\n'来判断是否为空

SendError( client_sock, 400,

"Bad Request", "", "Can't parse request."

); //如果为空就发送错误信息

}

explode(buf[0], ' ', &method_buf,

&method_total); //请求信息字符串数组的首字符串为 方法method_buf

if ( strcmp( strtolower(method_buf[0]), "get") !=

0 && strcmp(

strtolower(method_buf[0]), "head") != 0

){ //判断方法是不是get和head,如果不是发送错误报告

SendError( client_sock, 501,

"Not Implemented", "", "That method is not implemented." );

}

explode(method_buf[1], '?',

&query_buf,

&query_total); //请求字符串数组的第二个字符串为查询信息字符数组

getcwd(cwd,

sizeof(cwd)); strcpy(pathinfo,

query_buf[0]); //拷贝查询第一个字符串到(pathinfo

substr(query_buf[0], 0, strrpos(pathinfo, '/')+1,

path); //以'\'为分割点分割字符窜query_buf[0]

substr(query_buf[0], strrpos(pathinfo, '/')+1, 0,

file);

memset(&request_info, 0,

sizeof(request_info)); //初始化请求信息结构体

strcat(cwd, pathinfo);

request_info.method =

method_buf[0];

request_info.pathinfo =

pathinfo;

request_info.query =

(query_total == 2 ? query_buf[1] : "");

request_info.protocal =

strtolower(method_buf[2]);

request_info.path =

path;

request_info.file =

file;

request_info.physical_path =

cwd;

memset(tmp_path, 0,

sizeof(tmp_path)); //初始化临时目录

strcpy(tmp_path,

cwd); if ( is_dir(tmp_path)

){ strcat(tmp_path,

g_dir_index);

if ( file_exists(tmp_path)

){

request_info.physical_path

= tmp_path;

}

}

if ( g_is_debug ){

fprintf(stderr, "[ Request

]\n");

for(i=0; i

fprintf(stderr,

"%s\n", buf[i]);

}

}

ProcRequest( client_sock, client_addr,

request_info

); //处理该客户端的请求

return 0;

}

static void HandleClient( int client_sock, struct sockaddr_in

client_addr ){ //和客户端进行通信的函数

char

buf[REQUEST_MAX_SIZE]; //定义一个字符数组

if ( read(client_sock, buf, REQUEST_MAX_SIZE)

<

0){ //读取该客户端的消息

SendError( client_sock, 500,

"Internal Server Error", "", "Client request not success." );

die("read sock");

}

ParseRequest( client_sock, client_addr, buf

); //对读取到的请求消息进行处理

close(client_sock);

exit(0); //处理完之后安全退出进程

}

static void InitServerListen( unsigned int port, unsigned int

max_client ){ //初始化监听

int

serversock,

clientsock; //服务器套接字,客户端套接字

struct

sockaddr_in server_addr,

client_addr; //套接字地址

char

currtime[32]; //当前时间

if

((serversock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))

<

0){ //创建服务器套接字

die("Failed to create socket");

}

//设置套接字地址

memset(&server_addr, 0,

sizeof(server_addr)); server_addr.sin_family =

AF_INET; server_addr.sin_addr.s_addr =

htonl(INADDR_ANY); server_addr.sin_port =

htons(port);

if

(bind(serversock, (struct sockaddr *) &server_addr,

sizeof(server_addr)) <

0){ //绑定套接字地址

die("Failed to bind the server socket");

}

if

(listen(serversock, max_client) <

0){ //开始进行监听

die("Failed to listen on server socket");

}

getdate(currtime); //获得当前时间

fprintf(stdout, "[%s] Start server listening at

port %d ...\n", currtime, port);

fprintf(stdout, "[%s] Waiting client connection

...\n", currtime);

while

(1){ //死循环进行阻塞监听

unsigned int clientlen = sizeof(client_addr);

memset(currtime, 0,

sizeof(currtime));

getdate(currtime);

if ((clientsock = accept(serversock, (struct sockaddr *)

&client_addr, &clientlen))

<

0){ //收到客户端的连接请求,为客户端分配相应的套接字

die("Failed to accept client connection");

}

if ( fork() == 0

){ //为客户端单独创建一个进程进行通信,此处应该是用到了多进程通信

HandleClient(clientsock,

client_addr); //进入客户端通信函数

} else {

wait(NULL); //创建进程失败 等待退出

}

close(clientsock);

}

}

static int ParseOptions( int argc, char *argv[] ){

int opt;

struct option longopts[] = {

{

"is-debug", 0, NULL, 'D' },

{

"is-daemon", 0, NULL, 'd' },

{

"port", 1, NULL, 'p' },

{

"max-client", 1, NULL, 'm' },

{

"is-log", 0, NULL, 'L' },

{

"log-path", 1, NULL, 'l' },

{

"is-browse", 0, NULL, 'b' },

{

"doc-root", 1, NULL, 'r' },

{

"dir-index", 1, NULL, 'i' },

{

"help", 0, NULL, 'h' },

{

0, 0,

0, 0 }

};

while ( (opt = getopt_long(argc, argv,

":Ddp:m:Ll:br:i:h", longopts, NULL)) != -1){

switch (opt){

case

'h':

Usage(argv[0]);

return(-1);

break;

case 'D':

g_is_debug = 1; break;

case 'd':

g_is_daemon = 1; break;

case

'p':

g_port

= atoi(optarg);

if

( g_port < 1 || g_port > 65535

){

fprintf(stderr,

"Options -p,--port error: input port number %s invalid, must

between 1 - 65535.\n\n", optarg);

return(-1);

}

break;

case

'm':

g_max_client

= atoi(optarg);

if

( !isdigit(g_max_client) ){

fprintf(stderr,

"Options -m,--max-client error: input clients %s invalid, must

number, proposal between 32 - 2048.\n\n", optarg);

return(-1);

}

break;

case 'L':

g_is_log = 1; break;

case

'l':

strcpy(g_log_path,

optarg);

if

( !file_exists(g_log_path) || !is_dir(g_log_path) ){

fprintf(stderr,

"Options -l,--log-path error: input path %s not exist or not a

directory.\n\n", optarg);

return(-1); }

break;

case 'b':

g_is_browse = 1; break;

case

'r':

strcpy(g_doc_root,

optarg);

if

( !file_exists(g_doc_root) || !is_dir(g_doc_root) ){

fprintf(stderr,

"Options -l,--log-path error: input path %s not exist or not a

directory.\n\n", optarg);

return(-1); }

break;

case

'i':

strcpy(g_dir_index,

optarg);

break;

}

}

return(0);

}

int main( int argc, char *argv[] ){

if ( argc > 1 ){

if ( ParseOptions( argc, argv )

!= 0 ){

exit(-1);

}

}

chdir(g_doc_root);

if ( g_is_daemon ){

pid_t pid;

if ( (pid = fork())

< 0 ){

die("daemon

fork error");

} else if ( pid != 0){

exit(1);

}

}

if ( g_is_debug ){

PrintConfig();

}

InitServerListen( g_port, g_max_client );

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值