码迷,mamicode.com
首页 > 系统相关 > 详细

linux程序设计——数据报(第十五章)

时间:2015-07-27 00:19:51      阅读:170      评论:0      收藏:0      [点我收藏+]

标签:

15.5    数据报

在本章中,重点介绍了如何编写与客户之间维持连接的应用程序.使用面向连接的TCP套接字来完成这一工作.但在某些情况下,在程序中花费时间来建立和维持一个套接字连接是不必要的.
早先,在程序getdate.c中所使用的daytime服务就是一个很好的例子,首先创建一个套接字,然后建立连接,读取一个响应,读取一个响应,最后关闭连接.在这一过程中,使用了很多操作步骤,仅仅为了获取一个日期.
daytime服务还可以用数据报通过UUDP来访问.为了访问它,发送一个数据报给该服务,然后在响应中获取一个包含日期和时间的数据报,这一过程非常简单.
当客户需要发送一个短小的查询请求给服务器,并且期望接收到一个短小的响应时,一般就使用由UDP提供的服务.如果服务器处理客户请求的时间足够短,服务器就可以通过一次处理一个客户请求的方式来提供服务,从而允许操作系统将客户进入的请求放入队列.这简化了服务器程序的编写.
因为UDP提供的是不可靠服务,所以可能发现数据报或响应会丢失.如果数据非常重要,就需要小心编写UDP客户程序,以检查错误并在必要时重传.实际上,UDP数据报在局域网中是非常可靠的.
为了访问由UDP提供的服务,需要像以前一样使用套接字和close系统调用,但需要用两个数据报专用的系统调用sendto和recvfrom来代替原来使用在套接字上的read和write调用.
下面是一个修改过的getdate.c版本,它通过UDP数据报服务来获取数据.
编写程序getdate2.c
/*************************************************************************
 > File Name:    getdate2.c
 > Description:  getdate2.c
 > Author:       Liubingbing
 > Created Time: 2015年07月26日 星期日 15时37分05秒
 > Other:        getdate2.c
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

int main(int argc, char *argv[])
{
	char *host;
	int sockfd;
	int len, result;
	struct sockaddr_in address;
	struct hostent *hostinfo;
	struct servent *servinfo;
	char buffer[128];

	if (argc == 1)
		host = "localhost";
	else
		host = argv[1];

	/* 找到主机地址,如果没有找到则报错 */
	hostinfo = gethostbyname(host);
	if (!hostinfo) {
		fprintf(stderr, "no host: %s\n", host);
		exit(1);
	}

	/* 检查主机上是否存在daytime服务 */
	servinfo = getservbyname("daytime", "udp");
	if (!servinfo) {
		fprintf(stderr, "no daytime service\n");
		exit(1);
	}
	printf("daytime port is %d\n", ntohs(servinfo->s_port));

	/* socket创建一个UDP套接字 */
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);

	/* 创建地址 */
	address.sin_family = AF_INET;
	address.sin_port = servinfo->s_port;
	address.sin_addr = *(struct in_addr *)*hostinfo->h_addr_list;
	len = sizeof(address);

	/* sendto(int sockfd, void *buffer, size_t len, int flags, struct sockaddr *, socklen_t tolen); 
	 * sendto系统调用从buffer缓存区中给使用指定套接字地址的目标服务器发送一个数据报 */
	result = sendto(sockfd, buffer, 1, 0, (struct sockaddr *)&address, len);

	/* recvfrom(int sockfd, void *buffer, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
	 * recvfrom系统调用在套接字上等待从特定地址到来的数据报,并将它放入buffer缓存区 */
	result = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&address, &len);

	buffer[result] = '\0';
	printf("read %d bytes: %s", result, buffer);

	close(sockfd);
	exit(0);
}

运行程序,如果显示:Connection refused,说明linux没有启用daytime服务,对于ubunu而言,一般需要如下安装xinetd:
技术分享
然后cd /etc/xinetd.d/
然后sudo vim daytime
技术分享技术分享
需要用getservbyname来查找daytime服务,但通过请求UDP协议来指定数据报服务,使用带有SOCK_DGRAM参数的socket调用来创建一个数据报套接字,还是采用与以前一样的方式来构建目标地址,但现在需要发送一个数据报而不是仅仅从套接字上读取数据.
因为没有明确地建立一条指定UDP服务的连接,所有必须用某些方式让服务器直到需要接收一个响应.在本例中,给服务器发送一个数据报(在这里,从准备接收响应的缓存区中发送一个字节的数据),它返回包含日期和时间的响应.
sendto系统调用从buffer缓存区中给使用指定套接字地址的目标服务器发送一个数据报.它的原型如下所示:
int sendto(int sockfd, viod *buffer, size_t len, int flags, struct sockaddr *to, socklen_t tolen);
在正常应用中,flags参数一般被设置为0.
recvfrom系统调用在套接字上等待从特定地址到来的数据报,并将它放入buffer缓存区,它的原型如下所示:
int recvfrom(int sockfd, void *buffer, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
同样,在正常应用中,flags参数一般被设置为0.
除非用fcntl将套接字设置为非阻塞方式,否则recvfrom调用将一直阻塞,可以用与前面的面向连接服务器一样的方式,通过select调用和超时设置来判断是否有数据到达套接字.此外,还可以用alarm时钟信号来中断一个接收操作.

15.6    小结

本章中,介绍了另一种进程间通信的方法:套接字.通过它可以开发出真正跨网络运行的分布式客户/服务器应用程序.还简要介绍了一些主机数据库信息函数.开发了几个客户/服务器示例程序来演示网络和多客户处理方法.
最后,介绍了select系统调用,它允许一个程序同时在多个打开的文件描述符和套接字上等待输入和输出活动的发生.

版权声明:本文为博主原创文章,未经博主允许不得转载。

linux程序设计——数据报(第十五章)

标签:

原文地址:http://blog.csdn.net/yiranant/article/details/47074661

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!