對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%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. 只要 g++ -g -o execname filename -lpthread
//2. 然後在浏覽器輸入: 127.0.0.1:8848
//3. 與程序同目錄下 有 index.html 注意擴展名, 程序中為判斷)
問題: 中文會出現亂碼, 查看源代碼, 發現<head> 的很大一部分沒有了, 只留下後面的, 於是乎編碼沒有設置。 英文網頁時,前半部分也沒了)。 繼續解決。
本文出自 “咖啡時間” 博客,請務必保留此出處http://tuoxie174.blog.51cto.com/1446064/413683