LAB 6 网络驱动

本实验的主要内容:

  1. 网卡初始化以及发送数据包。
  2. 接收数据包以及 web 服务器。

1、启动网络服务器

简述启动网络服务器的过程。

网络服务器在系统启动时初始化,

--> i386_init(void)
    ...
    // hardware initialization functions
    // 发现 PCI 设备并初始化。
    --> pci_init()
        // 遍历 PCI 总线寻找设备。当它找到一个设备时,它会读取它的供应商 ID 和设备 ID,并使用这两个值作为        // 一个键来搜索 `pci_attach_vendor` 数组。
        // 如果发现的设备的供应商 ID 和设备 ID 与数组中的某个条目匹配,PCI 代码将调用该条目的                  // `attachfn` 来执行设备初始化。
        --> pci_scan_bus(&root_bus)
            --> bhlc = pci_conf_read(&df, PCI_BHLC_REG)
                --> pci_conf1_set_addr(f->bus->busno, f->dev, f->func, off)
                --> inl(pci_conf1_data_ioport)
            --> pci_attach(&af)
                --> pci_attach_match()
    ...
    // Start ns.
    --> ENV_CREATE(net_ns, ENV_TYPE_NS)
        // net/serv.c
        --> umain(int argc, char **argv)
            --> ns_envid = sys_getenvid()
    
            // fork off the timer thread which will send us periodic messages
            --> timer_envid = fork() // 创建计时器线程
            // 计时器进程定期向核心网络服务器发送`NSREQ_TIMER`类型的消息,通知它计时器已过期。
            --> timer(ns_envid, TIMER_INTERVAL)
    
            // fork off the input thread which will poll the NIC driver for input
            // packets
            --> input_envid = fork() // 创建输入辅助线程
            // - 从设备驱动程序读取数据包
            // - 发送到网络服务器
            --> input(ns_envid)
    
            // fork off the output thread that will send the packets to the NIC
            // driver
            --> output_envid = fork() // 创建输出辅助线程
            // - 从网络服务器读取数据包
            // - 发送到设备驱动程序
            --> output(ns_envid)
    
            // lwIP requires a user threading library; start the library and jump
            // into a thread to continue initialization.
            --> thread_init()
            --> thread_create(0, "main", tmain, 0)
                --> tmain(uint32_t arg)
                    // 初始化网络服务器
                    // 主要是 TCP/IP 协议的一些内容
                    --> serve_init(inet_addr(IP),inet_addr(MASK),inet_addr(DEFAULT))
                    // 运行网络服务器
                    --> serve()
            --> thread_yield()

2、发送数据包

testoutput.c 为例。

// net/testoutput.c
--> umain(int argc, char **argv)
    --> ns_envid = sys_getenvid()
    // 创建输出辅助线程
    --> output_envid = fork()
    // 运行输出辅助线程
    --> output(ns_envid)
    // 为将要发送的数据分配内存
    --> r = sys_page_alloc(0, pkt, PTE_P|PTE_U|PTE_W)
    // 从 ns 发送消息给 输出线程
    --> ipc_send(output_envid, NSREQ_OUTPUT, pkt, PTE_P|PTE_W|PTE_U)
    // 回收内存
    --> sys_page_unmap(0, pkt)
    // 调度等待数据包发送完毕
    --> sys_yield()
    
--> output(envid_t ns_envid)
    // 接收到来自 ns 的数据包
    --> ipc_recv()
    // 发送数据包给 e1000 网卡
    --> sys_pkt_try_send()
    // 执行完毕
    --> sys_yield()

3、接收数据包

testinput.c 为例。

// net/testinput.c
--> umain(int argc, char **argv)
    --> ns_envid = sys_getenvid()
    // 创建输出辅助线程
    --> output_envid = fork()
    // 运行输出辅助线程
    --> output(ns_envid)
    // 创建输入辅助线程
    --> input_envid = fork()
    // 运行输入辅助线程
    --> input(ns_envid)
    // 声明本机 IP
    --> announce()
    // 从输入进程得到数据
    --> ipc_recv((int32_t *)&whom, pkt, &perm)
    // 以十六进制打印
    --> hexdump("input: ", pkt->jp_data, pkt->jp_len)
    
--> input(envid_t ns_envid)
    // 从 e1000 网卡接收数据包
    --> sys_pkt_try_receive()
    // 将接收到数据包宝贝到目的地址
    --> memcpy()
    // 发送数据包给 ns
    --> ipc_send()
    // 等待 50 ms (ns 读取 IPC 数据),再接收下一个数据包
    --> sleep(50)

4、Web 服务器

user/httpd.c 所示。

// user/httpd.c
--> umain(int argc, char **argv)
    // Create the TCP socket.
    --> serversock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)
    // Construct the server sockaddr_in structure.
    --> memset(&server, 0, sizeof(server));     // Clear struct
    --> server.sin_family = AF_INET;            // Internet/IP
    --> server.sin_addr.s_addr = htonl(INADDR_ANY); // IP address
    --> server.sin_port = htons(PORT);          // server port = 80
    // Bind the server socket.
    --> bind(serversock, (struct sockaddr *) &server, sizeof(server)
    // Listen on the server socket.
    --> listen(serversock, MAXPENDING)
    // Wait for client connection.
    --> clientsock = accept(serversock, (struct sockaddr *) &client, &clientlen)
    // 处理来自客户端请求。
    --> handle_client(clientsock)
         // Receive message.
         // 从 sock 套接字处读取信息。
         --> received = read(sock, buffer, BUFFSIZE)
         // given a request, this function creates a struct http_request.
         // - 将 request 的前4个字节与 ‘GET’ 比较。
         // - 第五个字节到下一个空格之间的内容为 url。
         // - 接着是 http 版本。
         // - 即 GET url version,无 entity,构造一个结构体 req。
         --> r = http_request_parse(struct http_request *req, char *request)
         // 发送 struct http_request *req, 即返回的 HTTP 报文结构。
         // open the requested url for reading.
         // if the file does not exist, send a 404 error using send_error.
         // if the file is a directory, send a 404 error using send_error.
         // set file_size to the size of the file.
         --> send_file(req)
             // Open a file (or directory).
             // Send a file-open request to the file server.
             --> r = open(req->url, O_RDONLY)
             // http 头.
             --> r = send_header(req, 200)
             // Content-Length.
             --> r = send_size(req, file_size)
             // Content-Type.
             --> r = send_content_type(req)
             // 终止符。
             --> r = send_header_fin(req)
             // 从 fd 中读 size 大小数据,并发送。
             --> r = send_data(req, fd)
             // 关闭文件描述符。
             --> close(fd)
         // 回收 req 结构体。
         --> req_free(req)
         // 关闭客户端 socket
         --> close(sock)
    // 关闭服务器 socket
    --> close(serversock)
C/S 通信过程到此结束。
  1. PCI 设备在使用之前需要被发现和初始化。发现是在 PCI 总线上寻找连接设备的过程。初始化是分配 I/O 和内存空间以及协商 IRQ 线以供设备使用的过程。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,744评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,505评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,105评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,242评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,269评论 6 389
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,215评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,096评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,939评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,354评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,573评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,745评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,448评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,048评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,683评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,838评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,776评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,652评论 2 354

推荐阅读更多精彩内容