《UNIX网络编程 卷1:套接字联网API(第3版)》——1.5 一个简单的时间获取服务器程序

1.5 一个简单的时间获取服务器程序

我们可以编写一个简单的TCP时间获取服务器程序,它和1.2节中的客户程序一道工作。图1-9给出了这个服务器程序,它使用了上一节中讲过的包裹函数。

创建TCP套接字
10 TCP套接字的创建与客户程序相同。

把服务器的众所周知端口捆绑到套接字
11~15 通过填写一个网际套接字地址结构并调用bind函数,服务器的众所周知端口(对于时间获取服务是13)被捆绑到所创建的套接字。我们指定IP地址为INADDR_ANY,这样要是服务器主机有多个网络接口,服务器进程就可以在任意网络接口上接受客户连接。以后我们将了解怎样限定服务器进程只在单个网络接口上接受客户连接。

把套接字转换成监听套接字
16 调用listen函数把该套接字转换成一个监听套接字,这样来自客户的外来连接就可在该套接字上由内核接受。socket、bind和listen这3个调用步骤是任何TCP服务器准备所谓的监听描述符(listening descriptor,本例中为listenfd)的正常步骤。

常值LISTENQ在我们的unp.h头文件中定义。它指定系统内核允许在这个监听描述符上排队的最大客户连接数。我们将在4.5节详细说明客户连接的排队。

接受客户连接,发送应答
17~21 通常情况下,服务器进程在accept调用中被投入睡眠,等待某个客户连接的到达并被内核接受。TCP连接使用所谓的三路握手(three-way handshake)来建立连接。握手完毕时accept返回,其返回值是一个称为已连接描述符(connected descriptor)的新描述符(本例中为connfd)。该描述符用于与新近连接的那个客户通信。accept为每个连接到本服务器的客户返回一个新描述符。

本书全文采用的无限循环采用以下风格:

for ( ; ; ) {
    . . .
}

当前时间和日期是由库函数time返回的,它实际上返回的是自Unix纪元即0点0分0秒(国际标准时间)以来的秒数。下一个库函数ctime把该整数值转换成直观可读的时间格式,例如:

Mon May 26 20:58:40 2003
snprintf函数在这个字符串末尾添加一个回车符和一个回行符,随后write函数把结果字符串写给客户。

如果你尚不习惯改用snprintf代替较早的sprintf函数,那么现在是学习的时候了。调用sprintf无法检查目的缓冲区是否溢出。相反,snprintf要求其第二个参数指定目的缓冲区的大小,因此可确保该缓冲区不溢出。

snprintf相对较晚才加到ANSI C标准中,在称为ISO C99的版本中引入。不过几乎所有厂商都把它作为标准C函数库的一部分提供,而且另有许多免费可得的版本可用。我们贯穿全书使用snprintf,也推荐你出于可靠性考虑在自己的程序中改用它来代替sprintf。

值得注意的是,许多网络入侵是由黑客通过发送数据,导致服务器对sprintf的调用使其缓冲区溢出而发生的。必须小心使用的函数还有gets、strcat和strcpy,通常应分别改为调用fgets、strncat和strncpy。更好的替代函数是后来才引入的strlcat和strlcpy,它们确保结果是正确终止的字符串。编写安全的网络程序的更多技巧参见[Garfinkel, Schwartz, and Spafford 2003]的第23章。

终止连接
22 服务器通过调用close关闭与客户的连接。该调用引发正常的TCP连接终止序列:每个方向上发送一个FIN,每个FIN又由各自的对端确认。2.6节将详细讲述TCP的三路握手和用于终止一个TCP连接的4个TCP分组。

与上节查看客户程序一样,本节查看服务器程序也非常简略,具体细节留待本书以后论述。有以下几点需要注意。

与其客户程序一样,这一服务器程序也与IPv4协议相关。我们将在图11-13中给出使用getaddrinfo函数实现的一个协议无关的版本。
本服务器一次只能处理一个客户。如果多个客户连接差不多同时到达,系统内核在某个最大数目的限制下把它们排入队列,然后每次返回一个给accept函数。本服务器只需调用time和ctime这两个库函数,运行速度很快。然而如果服务器需用较多时间(譬如说几秒钟或一分钟)服务每个客户,那么我们必须以某种方式重叠对各个客户的服务。
图1-9中所示的服务器称为迭代服务器(iterative server),因为对于每个客户它都迭代执行一次。同时能处理多个客户的并发服务器(concurrent server)有多种编写技术。最简单的技术是调用Unix的fork函数(4.7节),为每个客户创建一个子进程。其他技术包括使用线程代替fork(26.4节),或在服务器启动时预先fork一定数量的子进程(30.6节)。

如果从shell命令行启动本例这样的一个服务器,我们也许想要它运行很长时间,因为服务器往往在系统工作期间一直运行。这要求我们往服务器程序中添加代码,以便它能够作为一个Unix守护进程(daemon)——能在后台运行且不跟任何终端关联的进程——运行。我们将在13.4节讨论守护进程。

时间: 2024-10-29 22:23:31

《UNIX网络编程 卷1:套接字联网API(第3版)》——1.5 一个简单的时间获取服务器程序的相关文章

UNIX网络编程:通用套接字选项

1. SO_BROADCAST 套接字选项 本选项开启或禁止进程发送广播消息的能力.只有数据报套接字支持广播,并且还必须是在支持广播消息的网络上(例如以太网,令牌环网等).我们不可能在点对点链路上进行广播,也不可能在基于连接的传输协议(例如TCP和SCTP)之上进行广播. 2. SO_DEBUG 套接字选项 本选项仅由TCP支持.当给一个TCP套接字开启本选项时,内核将为TCP在该套接字发送和接受的所有分组保留详细跟踪信息.这些信息保存在内核的某个环形缓冲区中,并可使用trpt程序进行检查. 3

《UNIX网络编程 卷1:套接字联网API(第3版)》——导读

**前言**本书面向的读者是那些希望自己编写的程序能使用称为套接字(socket)的API进行彼此通信的人.有些读者可能已经非常熟悉套接字了,因为这个模型几乎已经成了网络编程的同义词,但有些读者可能仍需要从头开始学习.本书想达到的目标是向大家提供网络编程指导.这些内容不仅适用于专业人士,也适用于初学者:不仅适用于维护已有代码,也适用于开发新的网络应用程序:此外,还适用于那些只是想了解一下自己系统中网络组件的工作原理的人. 书中的所有示例都是在Unix系统上测试通过的真实的.可运行的代码.但是,考

socket-unix网络编程环境怎么配置?我买了套接字联网api和tcp/ip详解,但是书上的代码都不能运行.

问题描述 unix网络编程环境怎么配置?我买了套接字联网api和tcp/ip详解,但是书上的代码都不能运行. 就下面这个代码,运行提示没有unp.h,找了个unp.h,但是还是提示什么各种数据类型重复定义.我到现在觉得是不是这本书写错了. #include "unp.h" int main(int argc, char **argv) { int sockfd, n; char recvline[MAXLINE + 1]; struct sockaddr_in servaddr; if

《UNIX网络编程 卷1:套接字联网API(第3版)》——1.8 BSD网络支持历史

1.8 BSD网络支持历史 套接字API起源于1983年发行的4.2BSD操作系统.图1-15展示了各种BSD发行版本的发展史,并注明了TCP/IP的主要发展历程.1990年面世的4.3BSD Reno发行版本随着OSI协议进入BSD内核而对套接字API做了少量的改动. 图1-15中从4.2BSD往下到4.4BSD的通路展示了源自Berkeley计算机系统研究组(Computer Systems Research Group,CSRG)的各个版本,它们要求获取者已拥有Unix的源代码许可权.然而

《UNIX网络编程 卷1:套接字联网API(第3版)》——8.11 UDP的connect函数

8.11 UDP的connect函数 在8.9节结尾我们提到,除非套接字已连接,否则异步错误是不会返回到UDP套接字的.我们确实可以给UDP套接字调用connect(4.3节),然而这样做的结果却与TCP连接大相径庭:没有三路握手过程.内核只是检查是否存在立即可知的错误(例如一个显然不可达的目的地),记录对端的IP地址和端口号(取自传递给connect的套接字地址结构),然后立即返回到调用进程. 给connect函数重载(overload)UDP套接字的这种能力容易让人混淆.如果使用约定,令so

《UNIX网络编程 卷1:套接字联网API(第3版)》——2.11 缓冲区大小及限制

2.11 缓冲区大小及限制 下面我们将介绍一些影响IP数据报大小的限制.我们首先介绍这些限制,然后就它们如何影响应用进程能够传送的数据进行综合分析. IPv4数据报的最大大小是65 535字节,包括IPv4首部.这是因为如图A-1所示其总长度字段占据16位.IPv6数据报的最大大小是65 575字节,包括40字节的IPv6首部.这是因为如图A-2所示其净荷长度字段占据16位.注意,IPv6的净荷长度字段不包括IPv6首部,而IPv4的总长度字段包括IPv4首部.IPv6有一个特大净荷(jumbo

《UNIX网络编程 卷1:套接字联网API(第3版)》——8.8 验证接收到的响应

8.8 验证接收到的响应 在8.6节结尾我们提到,知道客户临时端口号的任何进程都可往客户发送数据报,而且这些数据报会与正常的服务器应答混杂.我们的解决办法是修改图8-8中的recvfrom调用以返回数据报发送者的IP地址和端口号,保留来自数据报所发往服务器的应答,而忽略任何其他数据报.然而这样做照样存在一些缺陷,我们马上就会看到. 我们首先把客户程序的main函数(图8-7)改为使用标准回射服务器(图2-13).这只需把以下赋值语句 servaddr.sin_port = htons(SERV_

《UNIX网络编程 卷1:套接字联网API(第3版)》——1.10 Unix标准

1.10 Unix标准 在编写本书时,最引人注目的Unix标准化活动是由Austin公共标准修订组(The Austin Common Standards Revision Group,CSRG)主持的.他们的努力结果是涵盖1 700多个编程接口的约4 000页内容的规范[Josey 2002].这些规范既具有IEEE POSIX名字,也具有开放团体的技术标准(The Open Group's Technical Standard)名字.其结果是同一个Unix标准有多个名字来指称:ISO/IEC

《UNIX网络编程 卷1:套接字联网API(第3版)》——2.6 TCP连接的建立和终止

2.6 TCP连接的建立和终止 为帮助大家理解connect.accept和close这3个函数并使用netstat程序调试TCP应用,我们必须了解TCP连接如何建立和终止,并掌握TCP的状态转换图. 2.6.1 三路握手建立一个TCP连接时会发生下述情形. (1)服务器必须准备好接受外来的连接.这通常通过调用socket.bind和listen这3个函数来完成,我们称之为被动打开(passive open). (2)客户通过调用connect发起主动打开(active open).这导致客户T