面向连接的协议 [1]

在进一步学习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时指定套接口的地址结构和长度。



你可能感兴趣的:(struct,tcp,Stream,socket,服务器,internet)