编写与客户端之间维持连接的应用程序,我们用面向连接的TCP套接字来完成这一工作。但在有些情况下,在程序中花费时间来建立和维持一个套接字连接是不必要的。比如 daytime 服务,我们首先创建一个套接字,然后建立连接,读取一个响应,最后关闭连接。在这一过程中,我们使用了很多操作步骤,仅仅为了获取一个日期。
daytime 服务还可以用数据报通过UDP来访问。为了访问它,发送一个数据报给该服务,然后在响应中获取一个包含日期和时间的数据报。这一过程非常简单。当客户需要发送一个短小的查询请求给服务器,并且期望接受到一个短小的响应时,我们一般使用由UDP提供的服务。如果服务器处理客户请求的时间足够短,服务器就可以通过一次处理一个客户请求的方式来提供服务,从而允许操作系统将客户进入的请求放入队列。这简化服务器程序的编写。
为了使用UDP提供的服务,你需要像往常一样使用套接字和 close 系统调用,但你需要用两个数据报专用的系统调用 sendto 和 recvfrom 来代替使用TCP服务时的 read 和 write 调用。下面是一个简单的示范程序,如有需要可以扩展其功能:
- /* server.cc */
- #include <cstdio>
- #include <cstdlib>
- #include "sys/socket.h"
- #include "netinet/in.h"
- #include "unistd.h"
- #define SRV_PORT 6500
using namespace std;- char buffer[512];
- int main(int argc, char *argv[])
- {
- /* Create a UDP socket */
- int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
- /* Construct the address for use with sendto/recvfrom */
- struct sockaddr_in address;
- address.sin_family = AF_INET;
- address.sin_addr.s_addr = htonl(INADDR_ANY);
- address.sin_port = htons(SRV_PORT);
- int len = sizeof(address);
- /* Bind address to socket */
- bind(sockfd, (struct sockaddr *)&address, sizeof(address));
- /* serving */
- while(1) {
- /* receive */
- recvfrom(sockfd, buffer, sizeof(buffer), 0,
- (struct sockaddr *)&address, (socklen_t *)&len);
- /* handle */
- sprintf(buffer, "i am server");
- /* response */
- sendto(sockfd, buffer, sizeof(buffer), 0,
- (struct sockaddr *)&address, sizeof(address));
- }
- /* close */
- close(sockfd);
- return 0;
- }
- /* client.cc */
- #include <cstdio>
- #include <cstdlib>
- #include "arpa/inet.h"
- #include "sys/socket.h"
- #include "netinet/in.h"
- #include "unistd.h"
- #define SRV_ADDR "127.0.0.1"
- #define SRV_PORT 6500
- #include "client.h"
- using namespace std;
- char buffer[512];
- int main(int argc, char *argv[])
- {
- /* Create a UDP socket */
- int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
- /* Construct the address for use with sendto/recvfrom */
- struct sockaddr_in address;
- address.sin_family = AF_INET;
- address.sin_addr.s_addr = inet_addr(SRV_ADDR);
- address.sin_port = htons(SRV_PORT);
- int len = sizeof(address);
- /* sendto */
- sendto(sockfd, buffer, sizeof(buffer), 0,
- (struct sockaddr *)&address, sizeof(address));
- /* receive */
- recvfrom(sockfd, buffer, sizeof(buffer), 0,
- (struct sockaddr *)&address, (socklen_t *)&len);
- /* debug */
- printf("RECV: %s", buffer);
- /* close */
- close(sockfd);
- return 0;
- }