APR-服务器端编程

一个典型的服务器进程打开一个监听端口,并且监听这个端口等待任意客户端进程的链接,然后接受这个客户端的链接,然后使用一种网络协议进行通信。虽然网络协议依赖于你的应用程序,但是以一个基本的服务器结构的代码大体上相同。

一、APR_DECLARE(apr_status_t) apr_sockaddr_info_get(apr_sockaddr_t **sa, const char *hostname, apr_int32_t family, apr_port_t port, apr_int32_t flags, apr_pool_t *p);


首先,我们需要创建一个socket地址对象,apr_sockaddr_t。在传统的socket编程中,socket地址结构会引起一些混乱。形成鲜明对比,APR的socket地址结构非常简单。在不同的平台和IPv4/IPv6两个协议栈中它能够隐藏一些混乱。我们可以通过apr_sockaddr_info_get()创建这个对象


第一个参数是结构参数(result argument),第二个参数是主机名或者IP地址。第三个参数是地址类型(address family),它通常是APR_INET,如果你使用的是IPv6,请将他设定为APR_INET6,第四个参数是端口号。服务器端编程应该指定一个监听的端口号,例如如果你创建的是一个Web服务器,你应该指定这号码是80。正如你所预料的客户端编程指定的是远程服务器的的端口号,所以如果你正在编写以一个Web浏览器,你也该指定这个号码为80。注意你可以设置端口号为0,如果这样系统则选择一个可用的端口,第五个参数是一个标志位,大多数情况下为0,最后一个参数是所使用的内存池。


当你在进行客户端编程时候,客户端程序通常指定是服务器的主机名或者IP地址,相比客户端编程,服务器编程应该指定他为本地地址,并且通过apr_socket_bind()绑定Socket地址对象。


什么值可以作为本地地址?一种选择就是使用真实的地址或主机名称

第二种选择是选用环路地址(loopback address)或者“localhost”。使用这些都是可行的

还有一种选择是将本地址设置为NULL或者是APR_ANYADDR(="0.0.0.0")。这样设置暗含表示将全部的网络接口绑定到这socket,因此在这样情况下,服务器通过设置真实的地址或者环路地址任何客户端都可以链接他。从内部实现角度来看NULL要比APR_ANYADDR更好,因此我们通常选择NUL作为apr_sockaddr_info_get()的第二个参数。这里会有一种异常情况,当服务具有多个IP地址时,而你不希望全部的IP地址对远程可用,你就不能指定为NULL,你必须为这个监听socket指定一个实际的IP地址。


二、APR_DECLARE(apr_status_t) apr_socket_create(apr_socket_t **new_sock, int family, int type, int protocol, apr_pool_t *cont);


接下来,创建一个socket对象apr_socket_t。在传统的soket编程中,socket类型是一个整形,并且扮演这一个文件描述符的角色。apr_socket_t是一个不透明的类型它依赖于具体的操作系统,我们可以使用apr_socket_create()创建一个socket对象


第一个参数是一个结果参数(result argument)第二个参数是地址类型,他和apr_sockaddr_info_get()中的第三个参数一样,稍后我们将说明socket地址对象和socket对象的关系。如果他们使用不一样的地址类型,apr_socket_create将会失败。第三个和第四个参数是socket类型和协议类型。总而言之,他们一共有两种组合,一种是SOCK_STREAM作为socket类型,APR_PROTO_TCP作为协议类型,另一种是SOCK_DGRAM作为socket类型,APR_PROTO_UDP作为协议类型。最后一个参数是内存池。



apr_sockaddr_t *sa;
apr_socket_t *s;

apr_sockaddr_info_get(&sa, NULL, APR_INET, DEF_LISTEN_PORT, 0, mp);
apr_socket_create(&s, sa->family, SOCK_STREAM, mp);
apr_socket_bind(s, sa);
apr_socket_listen(s, DEF_SOCKET_BACKLOG);

你能发两个新的API,apr_socket_bind()和apr_socket_listen()。通过调用apr_socket_bind(),我们能够在socket对象(apr_socket_t)和socket地址对象(apr_sockaddr_t)间建立对应关系。我们称之为讲一个地址绑定到一个socket。然后,通过调用apr_socket_listen()我们将socket的状态改成监听状态。也就是说我们允许这个socket接受一个远程客户端的链接。apr_socket_listen()的第二个参数是内部队列的长度,这个队列是客户端的等待队列。这个队列由内核负责,直到应用程序接受为止。这个长度出于历史原因被称之为backlog。如果你不能确信一个合适的值,我建议你使用'SOMAXCONN',这是系统默认的最大值。


三、apr_socket_t *ns;/* accepted socket */
apr_socket_accept(&ns, s, mp);

apr_socket_accept()的第二个参数是我们之前创建的监听socket对象。这里我们还得到另一个socket对象,名为’ns’的接收socket。从socket对象创建方面看,apr_socket_accept()和apr_socket_create()非常相似。也就是说apr_socket_accept()也创建了一个新的socket对象,他的第一个参数是一个结果参数。注意新创建出来的socket对象和通过第二个参数传入apr_socket_accept()的监听socket对像完全不一样,在apr_socket_accept()返回后,监听socket仍然还是监听socket。也就我们可以在有客户端链接服务器时候继续调用apr_socket_accept(),我们将从apr_socket_accept()得到另外一个socket对象。在调用apr_socket_accept()后,我需要处理两个独立的socket,具体来说我们有一个socket继续保持静听状态,而我们使用已接受的socket通过指定网络协议和客户端进行交互。在server-sample.c中,我们发送了一个简单的HTTP请求并且得到相应的应答信息


四、APR_DECLARE(apr_status_t) apr_socket_send(apr_socket_t *sock, const char *buf, apr_size_t *len);

       APR_DECLARE(apr_status_t) apr_socket_recv(apr_socket_t *sock, char *buf, apr_size_t *len);



  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值