监听本地的8888端口, 当在浏览器中访问这个地址的时候, 返回一堆HTML数据, 这种方式返回的数据不稳定,不同浏览器解析不同, 因为我们没有定义返回文件类型:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
int main() {
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_port = htons(8888);
address.sin_addr.s_addr = inet_addr("192.168.0.58");
int ret = bind(sock , (const struct sockaddr*)&address , sizeof(address));
ret = listen(sock, 100);
printf("lisening..\n");
struct sockaddr_in client_address;
socklen_t len;
int newsock = accept(sock, (struct sockaddr*)&client_address, &len);
printf("client conneting\n");
FILE *fp = fopen("./html/index.html","rb");
char buf[1024] = {0};
fread(buf, 1024, 1, fp);
printf("content is %s\n", buf);
send(newsock, buf, strlen(buf), 0);
close(newsock);
close(sock);
return 0;
}
给服务器的返回设置文件类型和文件大小信息, 避免页面出现乱码和页面的正常解析:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
int main() {
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_port = htons(8888);
address.sin_addr.s_addr = inet_addr("192.168.1.102");
int ret = bind(sock , (const struct sockaddr*)&address , sizeof(address));
ret = listen(sock, 100);
printf("lisening..\n");
struct sockaddr_in client_address;
socklen_t len;
int newsock = accept(sock, (struct sockaddr*)&client_address, &len);
printf("client conneting\n");
//char recvData[1024] ={0};
//recv(newsock, recvData, sizeof(recvData), 0);
//printf("receive data:%s", recvData);
FILE *fp = fopen("./html/index.html","rb");
if( fp == NULL ){
printf("failed to open img\n");
}
fseek(fp, 0, SEEK_END);
long fileLen = ftell(fp);
fseek(fp, 0, SEEK_SET);
char buf[1024] = {0};
strcat(buf, "HTTP/1.0 200 OK\r\n");
strcat(buf, "Content-Type: text/html;charset=UTF-8\r\n");
char contentLength[256] = {0};
sprintf(contentLength, "Content-Length: %ld\r\n\r\n", fileLen);
strcat(buf, contentLength);
fread(buf+strlen(buf), 1024, 1, fp);
send(newsock, buf, strlen(buf), 0);
close(newsock);
close(sock);
return 0;
}
打开本地的PNG图片,并返回给客户端浏览器, 和上面的代码还有一点区别就是, 服务器有返回Content-type和Content-Length :
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
int main() {
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_port = htons(8888);
address.sin_addr.s_addr = inet_addr("192.168.1.102");
int ret = bind(sock , (const struct sockaddr*)&address , sizeof(address));
ret = listen(sock, 100);
printf("lisening..\n");
struct sockaddr_in client_address;
socklen_t len;
int newsock = accept(sock, (struct sockaddr*)&client_address, &len);
printf("client conneting\n");
FILE *fp = fopen("./imgs/img.png","rb");
if( fp == NULL ){
printf("failed to open img\n");
}
fseek(fp, 0, SEEK_END);
long fileLen = ftell(fp);
fseek(fp, 0, SEEK_SET);
char buf[40960] = {0};
strcat(buf, "HTTP/1.0 200 OK\r\n");
strcat(buf, "Content-Type: image\png;charset=UTF-8\r\n");
char contentLength[256] = {0};
sprintf(contentLength, "Content-Length: %ld\r\n\r\n", fileLen);
strcat(buf, contentLength);
//strlen just string length; but sizeof return all the size;
fread(buf+strlen(buf), 40960, 1, fp);
send(newsock, buf, 40960, 0);
close(newsock);
close(sock);
return 0;
}
搭建一个服务器:
/*****************************************************************
system:kali
enviroment:g++
compile command:gcc webServer.c -g -o webServer -lpthread
*****************************************************************/
#include <stdlib.h>
#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>
#define PORT 8848
#define BACKLOG 5
#define MAXDATASIZE 1000
#define DEBUG 1
void process_cli(int connectfd, sockaddr_in client);
int sendobj(int connectfd,char* serverfilepath);
int IsDIR(char* fpath);
int fileordirExist(char* fpath);
char* getextname(char*);
void* getHead(char* extname);
void* start_routine(void* arg);
void msg404(int connectfd);
struct ARG {
int connfd;
sockaddr_in client;
};
main()
{
int listenfd, connectfd;
pthread_t thread; //id of thread
ARG *arg; //pass this var to the thread
struct sockaddr_in server; //server's address info
struct sockaddr_in client; //client's
int sin_size;
//create tcp socket
#ifdef DEBUG
printf("socket.... ");
#endif
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("creating socket failed.");
exit(1);
}
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.... ");
if(bind(listenfd,(struct sockaddr *)&server,sizeof(struct sockaddr)) == -1) {
perror("bind error.");
exit(1);
}
printf("listen.... ");
if(listen(listenfd,BACKLOG) == -1) {
perror("listen() error ");
exit(1);
}
sin_size = sizeof(struct sockaddr_in);
while(1)
{
//accept() using main thread
printf("accepting.... ");
if((connectfd = accept(listenfd,
(struct sockaddr *)&client,
(socklen_t*)&sin_size)) == -1) {
printf("accept() error ");
}
arg = new ARG;
arg->connfd = connectfd;
memcpy((void *)&arg->client, &client, sizeof(client));
//invoke start_routine to handle this thread
#ifdef DEBUG
printf("thread_creating....");
#endif
if(pthread_create(&thread, NULL, start_routine, (void*)arg)){
perror("pthread_create() error");
exit(1);
}
}
close(listenfd);
}
//handle the request of the client
void process_cli(int connectfd, sockaddr_in client)
{
int num;
//char recvbuf[MAXDATASIZE], sendbuf[MAXDATASIZE], cli_name[MAXDATASIZE];
char requestline[MAXDATASIZE], filepath[MAXDATASIZE], cmd[MAXDATASIZE],extname[MAXDATASIZE];
int c;
FILE *fp;
FILE *cfp;
fp = fdopen(connectfd,"r");
#ifdef DEBUG
printf("the host is:%s ",inet_ntoa(client.sin_addr) );
#endif
fgets(requestline,MAXDATASIZE,fp);
#ifdef DEBUG
printf(" THE REQUEST IS :%s ",requestline);
#endif
strcpy(filepath,"./");
sscanf(requestline,"%s%s",cmd,filepath+2);
strcpy(extname, getextname(filepath));
#ifdef DEBUG
printf("cmd:%s filepath:%s extname:%s ",cmd,filepath,extname);
printf("string comparing :::::::::::::start::::::::::::::: ");
#endif
if(strcmp(cmd,"GET") == 0){
//the command is get
#ifdef DEBUG
printf("cmd(%s)==GET \n",cmd);
#endif
//is this a file or dir or notexist?
printf("filepath is .... : %s\n", filepath);
if(fileordirExist(filepath)){
//is a file or dir or none
//is this a dir
if(IsDIR(filepath)){
//is a dir
#ifdef DEBUG
printf("%s is a DIR ",filepath);
#endif
if( fileordirExist( strcat(filepath,"index.htm") )){
sendobj(connectfd,"index.htm");
}else if(fileordirExist(strcat(filepath,"index.html"))){
sendobj(connectfd,"index.htm");
}else{
msg404(connectfd);
}
}else{
//is a file
#ifdef DEBUG
printf("%s is a file\n",filepath);
#endif
sendobj(connectfd, filepath);
}
}else{
#ifdef DEBUG
printf("404 ");
#endif
msg404(connectfd);
}
}else{
#ifdef DEBUG
printf("cmd(%s)!=GET \n",cmd);
#endif
}
#ifdef DEBUG
printf(":::::::::::::end::::::::::::::: \n");
#endif
close(connectfd);
}
//send the 404 error message to the client
void msg404(int connectfd)
{
char* msg;
msg = "HTTP/1.0 404 Not Found Content-Type: text/plain 404 not found by Manio";
send(connectfd,msg,strlen(msg),0);
}
//is the filepath a file or directory
int fileordirExist(char* fpath)
{
struct stat filestat;
return ( stat(fpath,&filestat) != -1);
}
// is the filepath a directory
int IsDIR(char* fpath)
{
#ifdef DEBUG
printf("IN IsDIR ");
#endif
struct stat filestat;
return ( stat(fpath,&filestat) != -1 && S_ISDIR(filestat.st_mode));
}
//send the data of the file which the client want
int sendobj(int connectfd,char* serverfilepath)
{
FILE* fp,*cfp;
char buf[40960] = {0};
int c;
fp = fopen(serverfilepath,"rb");
printf("filepath is %s \n ", serverfilepath);
if( fp == NULL ){
printf("failed to open html file\n");
}
fseek(fp, 0, SEEK_END);
long fileLen = ftell(fp);
fseek(fp, 0, SEEK_SET);
strcat(buf, "HTTP/1.0 200 OK\r\n");
strcat(buf, "Content-Type: ");
char* fileExt = getextname(serverfilepath);
strcat(buf, (char *)getHead(fileExt));
strcat(buf, ";charset=UTF-8\r\n");
char contentLength[256] = {0};
sprintf(contentLength, "Content-Length: %ld\r\n\r\n", fileLen);
strcat(buf, contentLength);
fread(buf+strlen(buf), 40960, 1, fp);
printf("buf is %s\n", buf);
send(connectfd, buf, strlen(buf), 0);
return 0;
}
//write the packet header to the client
void* getHead(char* extname)
{
#ifdef DEBUG
printf("INGETHEAD:::::::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";
return (void *)content;
}
//get the extent name of the file
char* getextname(char* filepath)
{
char* p;
if(( p = strrchr(filepath,'.')) != NULL)
return p+1;
return NULL;
}
//invoked by pthread_create
void* start_routine(void* arg)
{
ARG *info;
info = (ARG *)arg;
process_cli(info->connfd, info->client);
delete arg;
pthread_exit(NULL);
}
C语言的限制很少..类型可以随便转..系统相对于把所有的权利交给我们了, 所以C语言容易出问题
C++搭建一个web服务器:http://www.cppblog.com/cuijixin/archive/2008/07/02/55112.html
天道酬勤