首先放作者上传项目的地址https://sourceforge.net/projects/tinyhttpd/
本篇博客主要记录一下在学习这个项目时,通过查资料、看博客或看源码掌握的知识。
函数声明
//每次收到一个请求,创建一个线程来处理该请求 //把client_sock转成地址作为参数传入pthread_create void accept_request(void *); //错误请求,HTTP状态码400 void bad_request(int); //读取文件 void cat(int ,FILE*); //得到一行数据,读到\n就认为一行结束;读到\r就用MSG_PEEK的方式读入下一个字符 //若下个字符为'\n'则用recv读,否则将c设为'\n' void get_line(int, char* , int); //开启TCP连接,绑定端口 int startup(ushort *); //如果不是GET或者POST,就报错方法没有实现 void unimplemented(int);
Http请求
GET / HTTP/1.1 Host: 192.168.0.103:5000 Connection: keep-alive
startup()函数
setsockopt()
#include <sys/types.h>
#include <sys/socket.h>
int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen);
/*******************************************************************
* 目的:获取或设置与某个套接字关联的选项
* sock:将要被设置或者获取选项的套接字
* level:选项所在的协议层。为了操作套接字层的选项,将其指定为SOL_SOCKET
* optname:需要访问的选项名
* optval:对于setsockopt(),指向包含新选项值的缓冲
* optlen:现选项的长度
返回值:
* 成功执行返回0,失败返回-1
********************************************************************/
//项目httpd.c中实际写法,参照理解
if((setsockopt(httpd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
error_die("setsockopt failed");bind()给套接字命名
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr* addr, socklen_t* addrlen);
/***********************************************************************
* 当用socket()函数创建套接字后,套接字在网络地址族中存在,但没有任何地址给它
* 赋值。bind()函数把用addr指定的地址赋给用文件描述符代表的套接字sockfd。
* 这个操作一般被称作bind()函数用本地地址给套接字命名。
* 返回值:0,成功;-1,失败。
************************************************************************/
//项目实际写法
if (bind(httpd, (struct sockaddr *)&name, sizeof(name)) < 0)
error_die("bind");动态分配一个端口
if(*port==0)
{
socklen_t namelen=sizeof(name);
if(getsockname(httpd, (struct sockaddr*) &name, &namelen) == -1)
error_die("getsockname");
*port = ntohs(name.sin_port);
}main()
accept函数
接受套接字中已经建立的连接
#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t addrlen);
//accept函数提取所监听套接字的等待队列中第一个连接请求,创建一个新的套接字。新建立的套接字不在监听状态
//原来监听的套接字也不受accept的影响。
//项目实际写法
client_sock = accept(sever_sock, (struct sockaddr *)&client_name, &client_name_len);
if(client_sock==-1)
error_die("accept");pthread_create函数
创建线程,也就是确定调用该线程函数的入口点
#include <pthread.h>
pthread_t newthread; //pthread_t在linux中被定义为"unsigned long int"
int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine) (void*), void *arg)
//参数说明
//thread:线程标识符
//attr:线程属性设置
//项目实际写法
if(pthread_create(&newthread, NULL, (void *)accept_request, (void*) (intptr_t)client_sock)!=0)
perror("pthread_create");accept_request函数
处理从套接字上监听到的一个http请求
get_line函数
用处:从缓冲区中读取字符存入字符数组buf中
//中止条件为换行符
//例如读取 GET / HTTP/1.1
int get_line(int sock, char *buf, int size)
{
int i = 0;
char c='\0';
int n;
while((i<size-1) && c!='\n')
{
n = recv(sock, &c, 1, 0);
if(n>0)
{
if(c=='\r')
{
n = recv(sock, &c, 1, MSG_PEEK);
if(n>0 && c=='\n')
recv(sock, &c, 1, 0);
else
c=='\n';
}
buf[i]==c;
i++;
}
else
c='\n';
}
buf[i]='\0';
return i;
}unemplemented函数
用处:通知客户端请求的web方法没有实现
参数:客户端套接字(client socket)
void unemplemented(int client)
{
char buf[1024];
sprintf(buf, "HTTP/1.0 501 Method Not Implemented");
send(client, buf, strlen(buf), 0);
sprintf(buf, SERVER_STRING); //#define SERVER_STRING "Server: jdbhttpd/0.1.0\r\n"
send(client, buf, strlen(buf), 0);
}


京公网安备 11010502036488号