HTTP服务器,就是一个运行在主机上的程序。程序启动了之后,会一直在等待其他所有客户端的请求,接收到请求之后,处理请求,然后发送响应给客户端。客户端和服务器之间使用HTTP协议进行通信,所有遵循HTTP协议的程序都可以作为客户端。 先直接上代码,然后再详细说明实现细节。
HTTP服务器,就是一个运行在主机上的程序。程序启动了之后,会一直在等待其他所有客户端的请求,接收到请求之后,处理请求,然后发送响应给客户端。客户端和服务器之间使用HTTP协议进行通信,所有遵循HTTP协议的程序都可以作为客户端。
< div> 先直接上代码,然后再详细说明实现细节。 测试运行 代码写好之后,运行测试一下,将上面代码保存到server.c,然后编译程序: ./server运行 服务器运行,监听9001端口。再用netstat命令查看: server程序在监听9001端口,运行正确。接着用浏览器访问,成功输出了Hello World,再尝试用telnet去模拟HTTP请求: 1、成功连接 2、发送HTTP请求 3、HTTP响应结果 上面是一个最简单的server程序,代码比较简单,省去一些细节,下面通过代码来学习一下socket的编程细节。 启动server的流程 socket 函数 创建一个套接字,通过各参数指定套接字的类型。 套接字地址结构 在socket编程中,大部分函数都用到一个指向套接字地址结构的指针作为参数。针对不同的协议类型,会有不同的结构体定义格式,对于 ipv4,结构如下所示: 注:sockaddr_in是**Internet socket address structure**的缩写。 ip地址结构 套接字地址结构的作用是为了将ip地址和端口号传递到socket函数,写成结构体的方式是为了抽象。当作为一个参数传递进任何套接字函数时,套接字地址结构总是以引用方式传递。然而,协议族有很多,因此以这样的指针作为参数之一的任何套接字函数必须处理来自所有支持的任何协议族的套接字地址结构。使用void *作为通用的指针类型,因此,套接字函数被定义为以指向某个通用套接字结构的一个指针作为其参数之一,正如下面的bind函数原型一样。 这就要求,对这些函数的任何调用都必须要将指向特定于协议的套接字地址结构的指针进行强制类型转换,变成某个通用套接字地址结构的指针。例如: 对于所有socket函数而言,sockaddr的唯一用途就是对指向特定协议的套接字地址结构的指针执行强制类型转换,指向要绑定给sockfd的协议地址。 bind函数 将套接字地址结构绑定到套接字 地址的长度 绑定了socket之后,就可以使用该socket开始监听请求了。 listen函数 将sockfd从未连接的套接字转换成一个被动套接字,指示内核应接受指向该套接字的连接请求。 listen函数会将套接字从CLOSED状态转换到LISTEN状态,第二个参数规定内核应该为相应套接字排队的最大连接个数。 关于backlog参数,内核为任何一个给定的监听套接字维护两个队列: 1、未完成连接队列,在队列里面的套接字处于SYN_RCVD状态 2、已完成队列,处于ESTABLISHED状态 两个队列之和不超过backlog的大小。 listen完成之后,socket就处于LISTEN状态,此时的socket调用accept函数就可以接受客户端发来的请求了。