tinyhttpd源码剖析(二):main() 和startup()

main函数

tinyhttp main函数源码如下:

int main(void)
{
 int server_sock = -1;
 u_short port = 0;
 int client_sock = -1;
 struct sockaddr_in client_name;
 /*
 源于sockaddr
 sockaddr_in 在netinet/in.h中定义
 struct sockaddr_in

{

short sin_family; //Address family一般来说AF_INET(地址族)PF_INET(协议族)

 unsigned short sin_port;//Port number(必须要采用网络数据格式,普通数字可以用htons()函数转换成
 网络数据格式的数字)

 struct in_addr sin_addr;// in_addr是一种结构体,可以用来表示一个32位的IPv4地址,位于 
 arpa/inet.h头文件。IP address in network byte order(Internet address)

 unsigned char sin_zero[8];//Same size as struct sockaddr没有实际意义,只是为了跟sockaddr结
 构在内存中对齐

};
 */
 socklen_t client_name_len = sizeof(client_name);
 pthread_t newthread;

 server_sock = startup(&port); //http服务建立在port端口,并返回状态描述符
 printf("httpd running on port %d\n", port);

 while (1)
 {
  client_sock = accept(server_sock,
                       (struct sockaddr *)&client_name,
                       &client_name_len);
  if (client_sock == -1)
   error_die("accept");
 /* accept_request(client_sock); */
 if (pthread_create(&newthread , NULL, accept_request,(void *) &client_sock) != 0)  //线程创建函数
   perror("pthread_create");
 }

 close(server_sock);

 return(0);
}

主要分为以下几步:

  1. 数据初始化;
  2. startup函数,传入端口参数,如果port为0动态分配一个端口;
  3. 建立一个无限循环等待请求,当请求到来时,建立一个线程处理它;
  4. 关闭。

startup函数解析

startup函数实现socket、bind以及listen。具体流程:

  1. 套接字描述符初始化、sockaddr_in声明;
  2. 建立socket;
socket原型:
#include<sys/socket.h>
int socket(int family, int type, int protocol);
返回: 成功犯规非负描述符;出错返回-1
/*其中family指明协议族,tinyhttp指定为PF_INET,即IPv4协议;
type指明套接字类型,tinyhttp指定为SOCK_STREAM,即字节流套接字;
protocol指定传输协议,设为0时,系统会根据family和type组合选择系统默认值;*/
  1. 初始化sockadrr_in;
  2. 通过bind把本地协议地址赋予一个套接字,bind可以指定IP地址或端;
bind原型:
#include<sys/socket/h>
int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);
返回: 成功为0,失败为-1.
  1. 如果端口为0,则动态分配一个端口,调用getsockname;
getsockname原型:
#include<sys/socket.h>
int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen);
返回: 成功返回0, 失败返回-1
/*使用该函数有两种原因:1. 在一个没有调用bind的TCP客户端,connect成功返回后,getsockname用于返回
由内核赋予该链接的本地IP地址和本地端口号;2. 在以端口号0调用bind(告知内核去选择本地端口号)后,
getsockname用于返回由内核赋予的本地端口号。*/
  1. listen作用:当socket创建套接字时,它被假设为一个主动套接字,也就是说,它是一个将调用connect发起连接的客户端套接字。listen函数把一个未连接的套接字转换成一个被动套接字,指示内核应接受向该套接字的连接请求。第二个参数规定了内核应该为相应套接字排队的最大连接个数。
listen原型:
#include<sys/socket.h>
int listen(int sockfd, int backlog);
返回:若成功返回0, 失败返回-1
  1. 返回套接字描述符。

startup程序

int startup(u_short *port)
{
 int httpd = 0;
 struct sockaddr_in name;

 httpd = socket(PF_INET, SOCK_STREAM, 0);  //建立socket 其原型 socket函数解析 IPPROTO_IP   
 if (httpd == -1)
  error_die("socket");
 memset(&name, 0, sizeof(name));
 name.sin_family = AF_INET;
 name.sin_port = htons(*port); //变成网络字节顺序
 name.sin_addr.s_addr = htonl(INADDR_ANY);
 if (bind(httpd, (struct sockaddr *)&name, sizeof(name)) < 0)  //bind解析
  error_die("bind");
 if (*port == 0)  /* if dynamically allocating a port */
 {
  socklen_t namelen = sizeof(name);
  if (getsockname(httpd, (struct sockaddr *)&name, &namelen) == -1)
   error_die("getsockname");
  *port = ntohs(name.sin_port);
 }
 if (listen(httpd, 5) < 0) //backlog = 5,是4.2BSD支持的最大值
  error_die("listen");
 return(httpd);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值