您的位置:首页 > 其它

面向连接的协议 [1]

2010-08-29 13:31 351 查看
在进一步学习TCP/IP之前,我们要先了解两个文件,和相关的函数。

/etc/services

这个文件将某个特定的Internet服务名映射到协议的端口。

例如: ssh 22/sctp # SSH

相关函数有:getservent,setservent,endservent//操作services文件

getservbyname,getservbyport//查询服务

注意:getservent会在后台自动打开 /etc/services文件,最后一定要调用endservent关闭打开的文件。

/etc/protocols

这个文件已经定义的Internet协议值的文件。

例如:tcp 6 TCP # transmission control protocol

相关函数:getprotoent,setprotoent,endprotoent

getprotobyname,getprotobynumber//查询协议

下面是一个使用 getservent 打印出 services中条目的例子,

//servent.c
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
int main (int argc, char** argv)
{
struct servent * sv = NULL;
int i;
if ( argc == 2) {
i = atoi (argv[1]);//indicate how many lines to print
} else {
i = 1;
}
//print info
for (; i > 0 ; i --) {
sv = getservent ();
if (sv != NULL) {
printf ("name:%s/tport:%d/tproto:%s/n",
sv->s_name, sv->s_port, sv->s_proto);
} else {
fprintf(stderr, "getservent():%s", strerror(errno));
exit (1);
}
}
return 0;
}
//$make servent
//$ ./servent 10


@编写TCP/IP 客户程序

*使用TCP/IP的步骤:

1 生成一个套接口

2 对套接口地址绑定(限制所使用的套接口,或者明确指出使用统配套接口)

3 连接至远程套接口(客户连接到服务器)

4 半关闭或者全关闭套接口

 使用UDP协议时,我们无需做步骤3,因为UDP协议是面向非连接的。

 我们要使用 connect() 建立连接。 在面向连接的协议中,我们只需对目的地址建立一次。

** man connect 了解怎么使用

***准备工作

我们的客户例程将连接到本地Linux系统的daytime服务以获取当前的日期和时间。

首先,确定Linux系统已经提供了daytime服务。

$ grep daytime /etc/services

daytime 13/tcp

daytime 13/udp

这表明 tcp的13号端口提供 daytime 服务。

第二,我们确定daytime 服务正在运行。

#telnet 127.0.0.1 13

Trying 127.0.0.1...

telnet: connect to address 127.0.0.1: Connection refused

如上结果表明服务没有运行。

在Fedora下你可以使用

$yum install xinetd

之后,你可以 

$ls /etc/xinetd.d/

chargen-dgram daytime-dgram discard-stream rsync time-stream

chargen-stream daytime-stream echo-dgram tcpmux-server

cvs discard-dgram echo-stream time-dgram

我们要用的是 daytime-stream

$vi /etc/xinetd.d/daytime-stream

修改: disable = no #yes

重启 xinetd

$ service xinetd restart

#telnet 127.0.0.1 13

Trying 127.0.0.1...

Connected to 127.0.0.1.

Escape character is '^]'.

28 AUG 2010 16:59:27 CST

Connection closed by foreign host.

这表明成功的运行了daytime服务,可以进行后续工作。

更多关于 xinetd.d 服务的问题见补充A.

补充A:

在Linux系统中有一个终极服务程式inetd,大部分的网络服务都是由他启动的,如chargen、echo、finger、talk、telnet、wu-ftpd等…,在旧版本他的配置是在/etc/inetd.conf中配置的。

在新版本,他就改成了一个xinetd.d目录。

在xinetd.d目录中,每一个服务都有一个相应的配置文档,我们以telnet为例,说明一下各个配置行的含义:

service telnet

{

socket_type=stream

wait=no

user=root

server=/usr/sbin/in.telnetd

log_on_failure+=USERID

disable=yes

}

第一行,说明该配置用来配置telnet服务。

第二行,说明Socket连接类型是stream,也就是TCP

第三行,是指不等待到启动完成

第四行,是指以root用户启动服务进程

第五行,是指服务进程是/usr/sbin/in.telnetd

第六行,是用于做一些出错日志

第七行,是指禁止远方telnet,假如需要开放则将该配置改为:disable=no

修改了xinetd的配置,需要重启xinetd才能够生效,执行如下命令:

/etc/rc.d/init.d/xinetd restart

//daytime.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
static void bail (const char* on_what)
{
fprintf (stderr, "%s error: %s", on_what, strerror (errno));
exit(1);
}
int main (int argc, char** argv)
{
int z;
char* srvr_addr = NULL;
struct sockaddr_in adr_srvr;//AF_INET
int len_inet;
int s;//socket
struct servent* sp;//服务项
char buf[128]; /* 存放日期/时间 */
if (argc == 2) {
srvr_addr = argv[1];
} else {
printf("/tFormat: datatime server_ip/n");
exit(1);
}
/* 查询daytime tcp 服务 */
sp = getservbyname ("daytime", "tcp");
if (!sp ) {
bail ("getservbyname()");
}
/* 建立服务器套接口地址 */
memset (&adr_srvr, 0, sizeof(adr_srvr));
adr_srvr.sin_family = PF_INET;
adr_srvr.sin_port = sp->s_port;
adr_srvr.sin_addr.s_addr = inet_addr(srvr_addr);
if (adr_srvr.sin_addr.s_addr == 0) {
bail ("inet_addr");
}
len_inet = sizeof(adr_srvr);
/* 生成TCP/IP套接口*/
s = socket (PF_INET, SOCK_STREAM, 0);
if (s == -1) {
bail ("socket error:");
}
/* 连接到服务器 */
z = connect (s, (const struct sockaddr*)&adr_srvr, len_inet);
if (z == -1) {
bail ("connect error:");
}
/* 读取日期/时间信息 */
z = read (s, buf, sizeof(buf)-1 );
if (z == -1) {
bail ("read");
}
buf[z] = '/0';//NULL终止符
printf ("Datetime is %s/n",buf);
/*  关闭套接口并退出 */
close (s);
return 0;
}
# make daytime
#./daytime 192.168.1.230
Datetime is 28 AUG 2010 20:10:23 CST


扩展:

connect 函数用于面向连接的协议,但也有例外。在UDP套接口中也可以使用connect,但这并没有建立连接,只是在UDP套接口上加上了

一些限制。这样所有的数据都将被发往connect第二个参数所指定的地址,套接口也只能接收从那个地址发送来的数据。内核自动排除了

我们不想接收的数据报。

另外一个好处就是允许调用者不再使用 sendto,和 recvfrom 函数,转而使用 read,write 系统调用。这样就不必在每次

I/O时指定套接口的地址结构和长度。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: