赶在死线之前!

嘿嘿,之前说是尽量每天更新关于JZHTTPD的编写,但每次不是因为数学作业太多就没有写,就是因为写的太投入,一写写好久导致最后没时间来写Blog。

今天下午是交作业的Deadline,我赶在中午的时候把JZHTTPD的雏形终于写好了,现在来Blog上填坑。

首先代码都可以在Github 上看到

因为在写的时候有不少参考了github上的tinyhttpd ,所以和它有点神似之处。。

先从serverStartup这个函数讲起,要能达到和用户机(client)建立连接的目的,我们首先要在服务器上开创一个套接字socket,所有的数据传输都通过socket完成,新建socket,需要用到函数socket(AF_INET,SOCK_STREAM, 0);在这里AF_INET表示使用的是iPv4协议,SOCK_STREAM表示是数据流传输,其他参数可通过man(Linux 中)查看(接下来要讲到的函数也一样)。这个函数返回一个整形作为我们新建的socket的标识符,之后每次在其他函数中调用这个socket,传入这个返回值就可以(因此我们需要声明一个int来接收这个返回值)。

2017/12/26


接下来,我们通过sockaddr_in 这个struct 来对我们的建立好的socket进行一些设置,比如说,设置端口,其中设置端口的时候我们需要使用htons()这个宏函数将我们的端口号改成网络字节顺序(因为不同的计算机对数据的存储方式不同,有的是高位在低位的左边,有的是高位在低位的右边)。接着用setsockopt 这个函数对socket进行一些设置,具体参数可以参见man手册或去Google,然后分别调用bind 和 listen绑定与建立监听,其中listen函数的第二个参数指明的是允许等待的连接数。这样,我们启动服务的过程就完成了,我们将这个socket的表示符作为返回值返回,并正在主函数中接受它。

接下来我们使用accept函数来接受用户的连接请求,因为我们的服务需要允许(不同用户)用户的多次连接,所以将accept放在while循环里面,该函数返回值为一个socket处理代码,之后每次数据传输由该socket处理。

建立连接后,通过recv函数读取用户的http request。并调用acceptRequest函数来处理它。因为我们需要对特定socket进行操作,该函数应该要接收两个参数,一个是int型的,用来指明数据往哪传,一个是char* 型,用来存放用户的请求信息。

一个http 请求的开始两个单词分别是请求的method 和 请求的路径。作为一个最简单的httpd服务器,我们也最(只)关心这两个东西。所以我们在处理请求的时候分别将它俩读入method字符串和url字符串中,对后面的请求信息就直接无视了。

读入后,我们首先要判断请求的方法是否为get,如果不是,那么就要告诉用户你请求的方法我们没有实现,具体是直接调用unimplemented()这个函数实现的,这个函数仿照了tinyhttpd中的方法,新建了一个字符串, 直接在程序中向它写入html代码,并通过write函数写给用户。

如果方法是get,那么我们就要从服务器上找到用户请求的文件返回给用户,如果用户请求的末位是”/”,也就是说用户没有指明请求什么文件(这种情况很常见,比如你在访问本Blog的时候,你访问的是www.jerry.com 而不是www.jerrypoi.com/index.php),因此,如果用户的访问最后结尾的是/,我们就要给它加上(默认)index.html,加上后,我们用sprintf这个函数,将默认html代码存储路径+url字符串 赋给path,并调用fopen打开path,如果打开失败,那么就是404 notfound,这时调用notfound函数告诉用户notfound,notfound实现方法和unimplemented()函数实现方法相同。

如果打开成功,调用header 来写http response的头,这时的状态码应该是200,然后调用sendFile将打开的文件发给用户。这就是整个JZHTTPD的运行原理了,如果你喜欢我的讲解,欢迎移步Github 点赞:)

问一个问题

读者朋友你觉得现在这个blog的域名:jerrypoi.xyz 和 jerrypoi.com 相比咋样,最近我的域名供应商万网给我发邮件要求我实名认证jerrypoi.xyz 这个域名,否则就会Server Hold 无法解析,因此我在考虑将域名转出万网,在godaddy浏览的时候发现.com域名只要58…这个价格在可以接受的范围内,那么要不要买呢?

Let’s Encrypt!

Let’s Encrypt! 自从今年3月份由于上一个ssl证书的免费一年试用结束了后本Blog就一直处于不被保护的状态。
直到前两天我突然发现原来有一个叫做letsencrypt的网站可以发放免费的ssl证书。
于是就折腾了一下把这个Blog恢复到了HTTPS
嘿嘿ww
and 由于刚更新https,如果访问本Blog有任何问题(如访问速度过慢,证书不被信任等问题),请联系我w

一些网络编程所需头文件/函数

建立tcp/ip连接首先需要新建一个socket

在c中,要使用socket(int,int,int)函数新建socket,该函数定义在sys/socket.h头文件下还有一直困扰我很久的在一些头文件中sin的意思终于被我搞明白了….sin不是三角函数,而是Socket INternet hhhh

然而去Google搜了一下,好像大家对那些头文件中奇怪的名字好像也不是很理解,比如说address_in 中的in….大概是只可意会不可言传吧hh

还有定义在<arpa/inet.h>中的htons(unsigned int)负责将参数转换为网络字节顺序,至于要在设么时候转换成网络字节顺序,详见这篇文章

You should generally always use them on all raw integers sent across the network…
If you’ve got a 16-bit int, you use htons() on data you’re about to send, and ntohs()
on data you’ve received; if you’ve got a 32-bit int, you use htonl()/ntohl()…  (Sadly,
there’s no standard 64-bit versions yet, so if you’ve got a 64-bit int, you kind of have
to roll your own…)  If you’ve got anything other than a raw int of some kind, you don’t
use them…  Ie: single characters or strings of multiple characters never need any
such trickery done to them…  And, you only need to do it on ints that actually are
transmitted across the network…  (This includes ones you actually send yourself, as
well as ones sent for you by the TCP/IP stack in packet headers and such…  Eg: raw
IPs, port numbers, etc…)

The reason this is necessary is due to different machines having different native ideas
about how to layout integer values in memory…  Technically, if you were sending to a
host that was the same architecture as you (or, at least the same endianness), you
wouldn’t have to bother converting to/from network order on any ints you send,
since both ends would agree on how to interpret them…  But, if you’re coding
something intended to work generically, communicating with any machine on the
Net, you have to allow for the fact that that machine may not agree with you about
how ints are stored, so you’ll both need to talk to each other in network order, and
do your own conversions to/from your native host order as necessary…

简单总结就是任何要发到网络的整形数字都应转换成网络字节顺序再用,以及任何从网络接收的整形数字都应当用ntohs转换成本机适用的整形。

 

更新说明

把blog最上面的图片换成了三张图中随机显示的,每次来blog都会有点新鲜感:)

在blog 的菜单栏里加了一些链接,主要是把JZHTTPD 这个独立出来方便以后看。

恩另外如果我的读者想友情链接欢迎来找我(逃(才不会有hhhh

啊感觉TCP/IP好复杂orz

嗯这两天的HTDG看到了第四章,在讲关于tcp 连接可能存在的问题及优化方案,看得有点不知所以hhhh

不过感觉tcp/ip 这个东西应该不是这本书这么一章就能讲完的,(看到书架上厚厚的一本TCP/IP详解,还只是几卷中的其中一卷),所以打算这部分就先略读,反正以后还会再看 那本书。

现在还有一个问题困扰我的是到底读书要不要记笔记,记笔记可以读得质量更高,但不记笔记可以读得更快,目前打算暂时不记笔记,因为如果记笔记的话这1000+页的书也许这学期都读不完:))

今天读了HTTP: THE DEFINITIVE GUIDE

嗯,因为宿舍晚上断网断电等种种原因,说好的每天更新从今天才开始。
今天(20171020)是JZHTTPD具有里程碑性质的一天,我在 Github 上init了JZHTTPD的代码仓库(逃。
  嗯关于JZHTTPD的一个小解释:JZ 我起的名字,HTTP 表示这是一个与HTTP这个协议有关的程序,D是Daemon 的缩写,说明这个程序是一个守护进程。
所以说,想要写好JZHTTPD,要:1、精通HTTP协议这个我打算通过读HTTP:THE DEFINITIVE GUIDE来学,此书据说是关于http的很好的书,2、掌握守护进程编程方法,这个不是这个project的主体部分,so我打算通过学好http后在网上查查守护进程该怎么写,并在github上看看开源的案例来学。3、有一个酷酷的Jerry ;)
好的关于今天的进程:今天读了HTDG(HTTP: THE DEFINITIVE GUIDE),实际上这本书并不是我今天才开始读的,而是读了将近有一周了。目前对HTTP的了解有:HTTP 程序间的通讯方式:通过request 报文和 response 报文。这两个报文均由start line, header fields, body(optional)构成,其中,header fields 紧接着start line, 而body 和header fields 中间由一空格分开。request 的start line 由 Method 目标文件 和HTTP版本号(Optional in previous version of HTTP )组成,response 的start line 由HTTP版本号, status code(indicate what happened), status phrase 组成。而header fields 中主要是一些用来使client 和server 通信更加方便的headers, header 的写法: header-name: header-value. 常见的header有 content-type:指明传输的body的文件类型,content-length,指明body的长度 Date,指明http报文创建的时间等。
关于URL:URL由绝对路径和相对路径两种,(这点和Linux 终端有点相似)。
还有写到这里突然发现关于缩进的问题。。。以前一直喜欢直接以tab为缩进单位,但最近有时从学校的电脑ssh到这个blog的服务器来写一些代码,但不知为什么在putty上一个tab的缩进实在是太长了,导致我开始使用两个空格,也导致现在在blog上写文章也喜欢用两个空格了hhhh

打算在blog 上开一新坑

嗯想在这个学期完成一个简单的http 服务器,但是现在C 只会一些基本的操作,对Linux 编程 以及网络协议方面的东西还都不是很懂,so 要快快看些书或技术blog 来了解一些这方面的东西w
然后大概每天会在blog上汇报一下进度

#也许是一个把这个blog变成tech-oriented 的好机会(逃

今天份的blog!

嗯今天酷酷的事情就是中午在宿舍睡觉睡得很久很舒服www
晚上去了图书馆,懒得穿长裤就只穿了短裤走,然后在图书馆被冷死orz
忍者寒气读了不少HTTP The definitive guide 感觉这本书写的蛮不错的,用的词汇好像也蛮基础的,没有什么因为语言不通导致的阅读上的障碍。

今天不酷的事情就是发现我的Sony 超级降噪耳机在我戴眼镜的时候戴的很不舒服😂,耳机嫁眼镜,眼镜夹耳朵,夹得好难受orz。

发现了一个超级酷的东西!

发现一了一个超级酷的功能,叫RSS。
RSS这东西很久前我就在这个基于WordPress的blog下见过,但每次点开都看起来像是未经翻译的源HTML文档,每次都是好奇的点开后发现搞不懂是什么东西就关掉了。
今天实在受不了blog上有个我不知道是什么功能的功能,本想改改代码把RSS那个连接删掉的。
但想想可以先去查查RSS到底是啥。
然后发现RSS是一种格式规范,为了能让用户在一个平台上订阅其他所有支持RSS的平台的内容!
所以说只要知道所有你想看得blog的RSS,并在一个RSS平台上订阅它们,就会在该blog有更新的时候收到通知了!
喔日RSS真的是太好用了hhh