初学 python 写一个简单的 http 服务器 实记

初学 python 写一个简单的 HTTP 服务器 实记

下面,说一说简单实现过程以及 期间发生的 现阶段自己解决不了的问题

总体来说,这个 HTTP 服务器源码没有问题的,现在分享一下

import socket
import re


def server_c(new_socket):
	# 接收客户端发来的数据
	request_message = new_socket.recv(1024).decode("gbk")
	if request_message:
		request_content1 = request_message.splitlines()
		request_content2 = re.match(r"[^/]+/([^ ]*)", request_content1[0])
		try:
			request_content3 = request_content2.group(1)
			print("------------------请求的页面为!!!", request_content3)
			f = open("./" + request_content3, "rb")
			content = f.read()
			f.close()
			response = "HTTP/1.1 200 OK\r\n"
			response += "\r\n"
			new_socket.send(response.encode("gbk"))
			new_socket.send(content)
		except Exception as aaa:
			print("")
			print("-----------请求的页面发生错误-------------")
			print(aaa)
			print("-----------------------------------------")
			print("")
	else:
		print("")
		print("------------为客户端服务完成-------------")
		print("")
		new_socket.close()


def main():
	# 创建一个套接字
	tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	# 绑定 IP port
	tcp_socket.bind(("192.168.8.126", 7788))
	# 设置侦听套接字
	tcp_socket.listen(128)
	while True:
		# 等待客户端的连接
		new_socket, user_addr = tcp_socket.accept()
		# 客户端连接完成,为客户端服务
		print("----------客户端已连接--------------")
		server_c(new_socket)

	tcp_socket.close()


if __name__ == '__main__':
	main()

下面,我简单介绍一下 这个 HTTP 服务器怎么实现的:

# 第一步,首先需要创建一个套接字,套接字是全双工的,可同时进行收发数据
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 第二步,绑定 IP 和 PORT ,因为作为服务器来说,你需要一个固定的 IP 和PORT,服务器这两个东西都是固定的,不可能说变就变,要不然 今天访问了一个网站,明天他就改变的 IP ,你有可能就访问不到了,所以这里需要绑定
tcp_socket.bind(("192.168.8.126", 7788))

# 第三步,设置侦听套接字,就像是你的电话,需要设置成响铃一样,一般来说,这里是 listen(128),最多要求可同时连接的客户端的数量为 128 个
tcp_socket.listen(128)

# 第四步,等待客户端的连接,默认会堵塞,当客户端连接的时候 才会 解堵塞
new_socket, user_addr = tcp_socket.accept()

#第五步,为客户端服务
def server_c(new_socket):     //首先这是一个独立的功能,需要定义一个函数
	# 接收客户端发来的数据 
	request_message = new_socket.recv(1024).decode("gbk")
	//接收客户端发来的数据,这里接收的数据需要解码才能 显示你可以看得懂的 内容,这里我用的是 windows 做测试,所以用的 “gbk” 解码,Linux 中,一般用 “UTF-8”
	
	if request_message:    //这一步,是判断而客户端有没有 关闭,如果客户端关闭了,去执行 else 中的代码
		request_content1 = request_message.splitlines()  
    //  这一步,因为你收到的 请求是 一行一行的,你需要提取出 第一行中有用的东西,所以先要进行分行,也就是生成一个列表,把 每一行作为 列表中的元素存放在列表中

		request_content2 = re.match(r"[^/]+/([^ ]*)", request_content1[0])
    //这一步,把客户端发送的请求中 第一行提取出来,然后用正则表达式 进一步提取出 第一行中有用的东西

		try:
			request_content3 = request_content2.group(1)   //进一步,需要用正则表达式提取出 第一行中有用的东西 里面的 ——客户端需要的页面
			print("------------------请求的页面为!!!", request_content3)
			f = open("./" + request_content3, "rb")     //去本地找到用户请求的页面,打开,读取到 content 中
			content = f.read()
			f.close()
			response = "HTTP/1.1 200 OK\r\n"   
   //这里,是response 的头部信息,200 ok 表示 ”200 代表 ok“,正常的服务器,换行是需要 \r\n  ,表示适合 windows  和  Linux

			response += "\r\n"   //这是因为,response 头部信息和 内容之间,需要一行的间距 用来区分
			new_socket.send(response.encode("gbk"))  //发送 response 头部信息
			new_socket.send(content)  //发送 response 主体内容
		except Exception as aaa:  // 异常检测
			print("")
			print("-----------请求的页面发生错误-------------")
			print(aaa)
			print("-----------------------------------------")
			print("")
	else:
		print("")
		print("------------为客户端服务完成-------------")
		print("")
		new_socket.close()

这样,基本上一个 HTTP 服务器就可以实现了

这里,实现了一个简单的 HTTP 服务器基本功能!!!
因为 现在刚上大一,自学 Python,没有任何经验,各类知识都是通过 百度搜索人家的博客来学习的。
因为之前没有接触过 python ,看到别人博客上用网页做测试,所以也就自己写了点前端页面,当我用 Dreamwaver 写的几个简单的页面来测试这个的时候,出现了这个 错误
[Errno 2] No such file or directory: './favicon.ico',现阶段我不知道到底应该怎么解决。找了很多博客,因为知识的欠缺,导致这个问题一直困扰着我。除了这样之外,还有一个让我看着很不顺的问题,就这 当我从浏览器访问的时候,它返回的是 没有CSS 样式的一篇极其LOW的页面。在这里插入图片描述
我几乎快要崩了,我不知道是不是因为[Errno 2] No such file or directory: './favicon.ico'这个错误引起的,但是现阶段,通过百度查阅,我还没有 办法解决。
实际上,这个网页是有CSS样式的,原本的页面应该是这样的:在这里插入图片描述
在这里插入图片描述我知道,这里有可能是因为我只是的缺失,我不知道什么是favicon.ico,以及 这个东西内部到底放着什么。。。。。。可能以后就知道了‘

不管怎么来说,这个HTTP服务器代码没有错误,错误出现在 我的网页源码上面!!!

这里,需要标明 HTTP 协议的三次握手,和四次挥手。

  • 三次握手:
    -(第一次)首先,客户端给服务器发送一个请求信息,为了能够让服务器识别这个请求信息,客户端对这个信息 用 syn
    标记,即这个时候客户端 堵塞在 connect 这一步。然后(第二次),服务器收到数据,如果服务器准备好了,就给
    客户端会送一个应答信息,为了让客户端可以识别这个信息,前面加上 ack 标记,这时,服务器会给这个信息附加 syn
    信息,这个信息可以判断客户端是否收到 应答信息。再然后(第三次),客户端接到服务器回复的信息,connect 解堵塞,客户端
    回复一个数据,告诉服务器 已经收到回复,这个数据用 ack 标记。然后,客户端个服务器就可以进行通信了。
    【保证双方在收发数据之前,准备好资源】

  • 四次挥手
    (第一步)首先,客户端 调用 close( ),发给服务器一个数据包,这个数据包表示客户端要关闭了。然后(第二步),服务器收到通知后,返回一个 确认收到客户端关闭通知的数据包,然后这个时候,客户端关闭发送通道 。再然后(第三步),服务器 发送一个让客户端 接受数据的通道关闭的数据包。再然后(第四步),客户端 收到通知,回复一个收到通知的数据包给服务器。。。。。。此时,客户端会等待 2MSL (数据包在网络上传输最大延迟时间),大约 2分多钟,如果由于什么原因,数据包没有发送出去,服务器没收到,此时服务器在 1MSL 的时候会重复发送 第二步 的通知数据包。这个时候客户端收到,再次发送收到通知的数据包。。。。。。这样为了保证第三步,当客户端因为网络原因发不出数据包的时候,服务器收不到消息继续发送,资源保留2分钟左右不释放。这也就是为什么。。。。客户端先关闭 通信的原因。 因为先关闭的 一方,资源会保留2分钟左右,这个时候 端口不能重复使用。
    【这里第二步和第三步没有向三次握手一样合并的原因,是因为: 第二步,服务器收到 客户端发送通道关闭消息,发送数据包为了给客户端回信,已收到消息。而第三次,是因为 客户端 发送通道关闭以后,服务器的 recv 解堵塞,往下执行 如果有new_socket.close( ),则发送关闭服务器与客户端 通信的消息,通知客户端关闭 接受消息的通道。第三步和第二步没有关联的,假如合并了,如果服务器里没有 new_socket.close( ),也就是说连第二步也发不出去了。】

发布了36 篇原创文章 · 获赞 75 · 访问量 5468

猜你喜欢

转载自blog.csdn.net/weixin_44449518/article/details/96834929