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);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当你尝试运行一个名为`startup.sh`的脚本时,遇到`bash: ./startup.sh: Permission denied`错误,这意味着操作系统没有给你执行这个脚本所需的权限。通常,这可能是因为以下几个原因: 1. 文件权限不足:`startup.sh`文件可能不是可执行文件(例如,所有者没有设置`x`权限),或者你当前用户没有执行该文件的权限。 2. 文件不在预期位置:如果脚本位于目录中,且你需要使用相对路径或路径中的某个父目录具有执行权限,那么路径可能存在问题。 3. 系统限制:在某些安全环境下,如学校、公司网络,系统可能会限制用户的某些操作权限。 要解决这个问题,你可以尝试以下方法: 1. **更改文件权限**:使用`chmod`命令给文件添加执行权限,例如 `chmod +x startup.sh`。 2. **以root或sudo运行**:如果你有管理员权限,可以通过`sudo ./startup.sh`来执行,但请确保你明白这样做可能带来的风险。 3. **检查路径**:确保你使用的路径正确,并且所有父目录都有执行权限。 4. **重新设置文件所有权**:如果是由于权限配置问题,可能需要将文件所有者更改为你自己或赋予你执行权限的用户。 5. **检查系统防火墙或安全策略**:如果是系统级别的限制,可能需要联系管理员解除限制。 如果你能提供更多的上下文信息,我可以给出更具体的建议。接下来的三个相关问题是: 1. 怎么查看和更改文件的权限? 2. 如何确定文件的执行权限是被哪个用户设置的? 3. 如果我想永久地修改一个文件的权限,应该怎么做?

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值