网络通信--多种方式实现并发

下面我们使用 Python 来实现并发的 Web Server,其中采用了多进程、多线程、协程、单进程单线程非阻塞、selectepoll的方式。

一、使用子进程来实

import socket
import re
import multiprocessing

#  注意: 不同的实现方式,但是对请求的处理方式相同,只是主函数中对客户端请求的接收方式不同 
def handle_request(new_socket):
    while True:
        # 接收请求
        recv_msg = new_socket.recv(1024).decode("utf-8")
        if recv_msg == "":
            print("recv null")
            new_socket.close()
            return

        # 从请求中解析出URI
        recv_lines = recv_msg.splitlines()
        print(recv_lines)
        # 使用正则表达式提取出URI
        ret = re.match(r"[^/]+(/[^ ]*)", recv_lines[0])
        if ret:
            # 获取URI字符串
            file_name = ret.group(1)
            # 如果URI是/,则默认返回index.html的内容
            if file_name == "/":
                file_name = "/index.html"

        try:
            # 根据请求的URI,读取相应的文件
            fp = open("." + file_name, "rb")
        except:
            # 找不到文件,响应404
            response_msg = "HTTP/1.1 404 NOT FOUND\r\n"
            response_msg += "\r\n"
            response_msg += "<h1>----file not found----</h1>"
            new_socket.send(response_msg.encode("utf-8"))
        else:
            html_content = fp.read()
            fp.close()
            response_body = html_content

            # 响应正确 200 OK
            response_header = "HTTP/1.1 200 OK\r\n"
            response_header += "Content-Length:%d\r\n" % len(response_body)
            response_header += "\r\n"

            response = response_header.encode("utf-8") + response_body

            # 返回响应数据
            new_socket.send(response)


def main():
    # 创建TCP SOCKET实例
    tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # # 设置重用地址
    # tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    # 绑定地址(默认本机IP)和端口
    tcp_server_socket.bind(("", 7890))
    # 监听
    tcp_server_socket.listen(128)
    # 循环接收客户端连接
    while True:
        new_socket, client_addr = tcp_server_socket.accept()
        # 启动一个子进程来处理客户端的请求
        sub_p = multiprocessing.Process(target=handle_request, args=(new_socket,))
        sub_p.start()
        # 这里要关闭父进程中的new_socket,因为创建子进程会复制一份new_socket给子进程
        new_socket.close()

    # 关闭整个SOCKET
    tcp_server_socket.close()


if __name__ == "__main__":
    main()

我们使用进程来实现并发的 Web Server,也就是将 accept 到 new_socket 传递给子进程去处理,处理函数还是 handle_request

但是这里注意,子进程会从父进程中将所有的变量进行拷贝,也就是说父进程和子进程中各有一份 new_socket,而在 Linux 下,socket 对应的也是一个文件描述符,而这两个 new_socket 实际上是指向同一个 fd 的。所以我们将 new_socket 交给子进程后,父进程就可以马上关闭自己的 new_socket 了,当子进程服务完毕后,关闭子进程中的 new_socket,这样对应的 FD 才会正真关闭,此时才会触发四次挥手。所以父进程代码中的 new_socket.close() 非常重要。

二、使用线程来实现并发 Web Server

在第一节中,我们使用进程来实现并发,但是进程对资源消耗很大&#x

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值