Source code analysis for http://tuoxie174.blog.51cto.com/1446064/413189
# Include <iostream>
# Include <sys/types. h>
# Include <sys/socket. h>
# Include <sys/stat. h>
# Include <netinet/in. h>
# Include <unistd. h>
# Include <pthread. h>
# Include <stdio. h>
# Include <string. h>
# Include <arpa/inet. h>
# Include <stdlib. h>
Using namespace std;
# Define PORT 8848 // Port
# Define BACKLOG 5 // Max Link num
# Define MAXDATASIZE 1000 // Max data buf
# Define DEBUG 1
// 1. Func Decalare
Void process_cli (int connectfd, sockaddr_in client );
Int sendobj (int connectfd, char * serverfilepath );
Int isDIR (char * path );
Int fileordirExist (char * fpath );
Char * gettextname (char *);
Int writehead (FILE * cfp, char * extname );
Void * start_routing (void * arg );
Void msg404 (int connectfd );
// 2. Structure Decalare
Struct ARG
{
Int connfd;
Sockaddr_in client;
};
Int main ()
{
// Cout <"Hello world! "<Endl;
Int listenfd, connectfd;
//! 1. thread id
Pthread_t thread;
//! 2. pass this var to the thread
ARG * arg;
Struct sockaddr_in server;
Struct sockaddr_in client;
Int sin_size;
//! 3. create tcp socket
# Ifdef DEBUG
Printf ("socket... \ n ");
# Endif
If (listenfd = socket (AF_INET, SOCK_STREAM, 0) =-1)
{
Perror ("creating socket failed! \ N ");
Exit (1 );
}
//! 4. set the socket -- close, timeout
Int opt = SO_REUSEADDR;
Setsockopt (listenfd, SOL_SOCKET, SO_REUSEADDR, & opt, sizeof (opt ));
Bzero (& server, sizeof (server ));
Server. sin_family = AF_INET;
Server. sin_port = htons (PORT );
Server. sin_addr.s_addr = htonl (INADDR_ANY );
Printf ("bind... \ n ");
//! 5. bind a ip and port to the socket
If (bind (listenfd, (struct sockaddr *) & server, sizeof (struct sockaddr )))
{
Perror ("bind error! ");
Exit (1 );
}
Printf ("listen... \ n ");
//! 6. listen the socket
If (listen (listenfd, BACKLOG) =-1)
{
Perror ("listen error! \ N ");
Exit (1 );
}
// A datastructure for programmer to use struct sockaddr
Sin_size = sizeof (struct sockaddr_in );
While (1)
{
// Begin to process the client's connect
//! 7. accept using main thread
Printf ("accepting... \ n ");
If (connectfd = accept (listenfd, (struct sockaddr *) & client, (socklen_t *) & sin_size) =-1)
{
Printf ("accept error! \ N ");
}
// Connectfd is a socket
Arg = new ARG;
Arg-> connfd = connectfd;
Memcpy (void *) & arg-> client, & client, sizeof (client ));
# Ifdef DEBUG
Printf ("thread creating... \ n ");
# Endif
//! 8. invoke start_routing to handle this thread. -- start_routing is a callback func
If (pthread_create (& thread, NULL, start_routing, (void *) arg ))
{
Perror ("pthread_create error! \ N ");
Exit (1 );
}
}
Close (listenfd );
Return 0;
}
//! 1.1 handle the request
Void process_cli (int connectfd, sockaddr_in client)
{
Int num;
Char requestline [MAXDATASIZE];
Char filepath [MAXDATASIZE];
Char cmd [MAXDATASIZE];
Char extname [MAXDATASIZE];
Int c;
FILE * fp;
//! Because everything is file in UNIX
//! 1.1.1 open the client socket
Fp = fdopen (connectfd, "r ");
# Ifdef DEBUG
Printf ("the host is: % s \ n", inet_ntoa (client. sin_addr ));
# Endif
Fgets (requestline, MAXDATASIZE, fp );
# Ifdef DEBUG
Printf ("The request is: % s \ n", requestline );
# Endif
Strcpy (filepath ,"./");
Sscanf (requestline, "% s \ n", cmd, filepath + 2 );
//! Use func gettextname
Strcpy (extname, gettextname (filepath ));
# Ifdef DEBUG
Printf ("cmd: % s \ n filepath: % s \ n extname: % s \ n", cmd, filepath, extname );
Printf ("string comparing \ n :::::: start ::::::::\ n ");
# Endif
If (strcmp (cmd, "GET") = 0)
{
# Ifdef DEBUG
Printf ("cmd (% s) = GET \ n", cmd );
# Endif
If (fileordirExist (filepath ))
{
If (isDIR (filepath ))
{
//! Is a DIR
# Ifdef DEBUG
Printf ("% s is a DIR \ n", filepath );
# Endif
If (fileordirExist (strcat (filepath, "index.html ")))
{
//! Send
Sendobj (connectfd, "index.html ");
}
Else
{
Msg404 (connectfd );
}
}
Else
{
//! Is a file
# Ifdef DEBUG
Printf ("% s is a file \ n", filepath );
# Endif
//! Send
Sendobj (connectfd, filepath );
}
}
Else
{
# Ifdef DEBUG
Printf ("404 \ n ");
# Endif
Msg404 (connectfd );
}
}
Else
{
# Ifdef DEBUG
Printf ("cmd (% s )! = GET \ n ", cmd );
# Endif
}
# Ifdef DEBUG
Printf ("::::::::::::::::::: end ::::::::::::::::: \ n ");
Close (connectfd );
# Endif
}
//! 1.2
Void msg404 (int connectfd)
{
Char * msg;
Msg = "HTTP/1.0 404 Not Found Content-Type: text/plain 404 not found by Manio \ n ";
Send (connectfd, msg, strlen (msg), 0 );
}
//! 1.3 is the filepath a file or direatory
Int fileordirExist (char * fpath)
{
Struct stat filestat;
Return (stat (fpath, & filestat )! =-1 );
}
//! 1.4 is the filepath a directory
Int isDIR (char * fpath)
{
# Ifdef DEBUG
Printf ("IN IsDir \ ns ");
# Endif
Struct stat filestat;
Return (stat (fpath, & filestat )! =-1 & S_ISDIR (filestat. st_mode ));
}
//! 1.5 send the data of the file which the client want
Int sendobj (int connectfd, char * serverfilepath)
{
// Printf ("server: % s \ n", serverfilepath)
FILE * sfp = NULL, * cfp = NULL;
Char c;
Sfp = fopen (serverfilepath, "r ");
Cfp = fdopen (connectfd, "w ");
If (sfp = NULL)
Printf ("can't open the file !... \ N ");
If (cfp = NULL)
Printf ("can't open the link file ...! \ N ");
Writehead (cfp, gettextname (serverfilepath ));
While (c = getc (sfp ))! = EOF ){
Putc (c, cfp );
// Putchar (c );
}
Fflush (cfp );
Return 0;
}
//! 1.6 write the packet header to the client
Int writehead (FILE * cfp, char * extname)
{
# Ifdef DEBUG
Printf ("INWRITEHEAD ::::: extname is % s ::::::\ n", extname );
# Endif
Char * content = "text/plain ";
If (strcmp (extname, "html") = 0 | strcmp (extname, "htm") = 0)
Content = "text/html ";
Else if (strcmp (extname, "css") = 0)
Content = "text/css ";
Else if (strcmp (extname, "gif") = 0)
Content = "image/gif ";
Else if (strcmp (extname, "jpeg") = 0 | strcmp (extname, "jpg") = 0)
Content = "image/jpeg ";
Else if (strcmp (extname, "png") = 0)
Content = "image/png ";
# Ifdef DEBUG
Printf ("HTTP/1.1 200 OK \ n ");
Printf ("Content-Type: % s \ n", content );
# Endif
Fprintf (cfp, "HTTP/1.1 200 OK ");
Fprintf (cfp, "Content-Type: % s \ n", content );
Return 0;
}
//! 1.7 get the extent name of the file
Char * gettextname (char * filepath)
{
Char * p;
If (p = strrchr (filepath ,'.'))! = NULL)
Return p + 1;
Return NULL;
}
//! 1.8 invoked by pthread_create
Void * start_routing (void * arg)
{
ARG * info;
Info = (ARG *) arg;
// Handle client's requirement
Process_cli (info-> connfd, info-> client );
Delete arg;
Pthread_exit (NULL );
}
// 1. As long as g ++-g-o execname filename-lpthread
// 2. enter 127.0.0.1: 8848 in the browser
// 3. There is an index.html extension in the same directory as the program. The extension must be determined in the program)
Problem: Garbled characters may occur in Chinese. Check the source code and find that a large part of the
This article is from the coffee time blog, please be sure to keep this source http://tuoxie174.blog.51cto.com/1446064/413683