UNIX网络编程--第一章TCP/IP简介

本文介绍了网络编程中的两种API——套接字和XTI接口,详细解析了套接字API的使用,包括创建TCP套接字、指定服务器地址和端口、连接服务器以及错误处理。通过示例代码展示了一个简单的日期/时间客户端和服务器程序的实现,阐述了网络通信的基本流程和错误处理策略。
摘要由CSDN通过智能技术生成

两种网络编程API

  1. 套接口(sockets),有时称为“Berkeley套接口”,因为它源自Berkeley Unix。
  2. XTI(X/Open传输接口),它是对AT&T开发的传输层接口(TLI)经少量修改的产物。
  3. 以后我们将遇到术语套接口(socket)的许多不同用法。首先,我们正在使用的应用程序编程接口称为套接口API(sockets API)。它是应用层到传输层的接口。

大多数的网络应用系统包括两部分:客户(client)与服务器(server),两者是通过通信链接的,其中又涉及到了网络通信协议,TCP/IP协议族(又称网际协议族
在这里插入图片描述
在这里插入图片描述
在实际生活中,客户与服务器无需处于一个局域网内通信,也可以通过路由器(router,广域网的架构设备)作为传输节点,进行局域网转接到广域网中去。最大的广域网是因特网。
在这里插入图片描述

示例代码(一个简单的时间/日期客户程序)

//这个头文件含有许多大部分网络程序都需要的系统头文件,并定义了所用到的各种常值(如MAXLINE)
include "unp.h"
//命令行参数:形参是命令行参数。ANSI(美国国家标准局)C编译器。
int main(int argcchar* *argv)
{
	int sockfd.n;
	char recvline[MAXLINE+1];
	struct sockadd_in servaddr;
	if (argc ! = 2)
		//系统输入
		err-quit("usage: a.out<IPaddess>" );
		
	//创建TCP套接口:利用socket函数创建网际(AF_INET)字节流和(SOCK_STREAM)套接口,它是TCP套接口的特色名字。
	//该函数返回一小整数描述字,在以后的其他函数调用中(如随后的connect和read调用),我们就用它来标识这个套接口。
	if ( (sockfd= socket(AF_INET,SOCK_STREAM,0))<0)
	
		//如果socket函数调用失败,我们就调用自己的err-sys放弃执行。该函数输出我们提供的出错消息和所发生系统错误的描述信息
		//(如“Protocol not supported(协议不受支持)”等)后,终止进程的执行。
		err-sys("socket error" );
		
	//指定服务器IP地址和端口:bzero函数将整个结构都清零
	bzero(&servadd,sizeof(servaddr));
	
	//置地址族为AF_INET
	servaddr.sin_family = AF_INET;
	
	//端口设置为daytime服务器的端口13
	servaddr.sin_port = htons(13);
	
	//置IP地址为命令行的第一个参数值(argv[1]),inet_pton变换命令行参数为合适的格式。
	if (inet_pton(AF_INET.argv[1],&servaddr,sin-addr)<=0)
		err_quit("inet_pton error for %s",argv[1];
		
	//connect函数用在TCP套接口上的功能是:跟由它的第二个参数所指的套接口地址结构
	//对应的服务器建立连接。connect的第三个参数说明套接口地址结构的长度,对于网
	//际套接口地址结构。
	if(connect(sockfd,(SA * )&servaddr,sizeof(servaddr))<0)
		err_sys("connect error");
	
	//SA=struct sockaddr,即通用套接口地址结构。套接口函数每次需要一个指向套接口
	//地址结构的指针时,这个指针必须转换成指向一个通用套接口地址结构的指针类型。
	while ( (n = read(sockfd,recvline,MAXLINE))>0){
		recvline[n]=0;
		
		//读入并输出服务器的应答:我们使用read函数读服务器的应答,并用标准的I/O
		//函数fputs输出结果。我们必须注意,TCP是一种无记录边界的字节流协议。
		if(fputs(recvline,stdout) == EOF)
			err_sys("fputs error" );
	}
	if(n<0)
		err_sys("read error" );
		
	//exit语句终止程序。Unix在进程终止时关闭所有描述字,其中包括TCP套接口描述字。
	exit(0);
}

错误处理:包裹函数

我们知道,使用err_quit还有err_sys可以输出出错消息并中止程序,但我们有时候只需要输错报错信息而不中止程序的运行,这就需要用到包裹函数了。
因为多数情况下程序终止于一个错误,我们可以定义包裹函数来简化我们的程序。包裹函数调用实际函数,检查返回值,发生错误时终止进程。确定包裹函数名的约定是大写实际函数名的第一个字符,如:

sockfd= Socket(AF_INET,SOCK_STREAM,0)

Socket的包裹函数为:

int Socket(int family ,int type,int protocol)
	int n;
	if( (= socket(family,type,protocol))<0)
		err_sys("socket orror" );
	return (n);

在后续,我们通常会将errno的值当成函数返回值返回,当成指示。

int n;
if((n= pthread mutex-lock(&ndone_mutex))!=0)
	errnon=n, err_sys("pthread mutex_lock error" );

Unix errno值
每当在一个Unix函数(如socket函数)中发生错误时,全局变量errno将被置成一个指示错误类型的正数﹐函数本身则通常返回一1。err.sys检查errno变量并输出其相应的出错消息(例如,当errno值等于ETIMEDOUT时,将配带着输出“Connection timed out(连接超时)”)。

errno的值只在函数发生错误时设置。如果函数不返回错误,errno的值就无定义。在Unix中,所有的错误值都是常值,具有以E打头的全大写字母名字,在头文件(sys/errno.n中定义。值0不表示任何错误。

示例代码(一个简单的时间/日期服务器程序)

include "unp.h"
include<time.h>
int main(int argc,char * * argy)
{
int listenfd,connfd;
struct sockaddr_in servaddr;
char buff[MAXLINE];
time-t  ticks;

//创建TCP套接口
Listenfd = Socket(AF_INET,SOCk_STREAM,0);
bzero(&servaddr ,sizeof(servaddr ));
servaddr.sin_family = AF_INET;

//捆绑服务器的总所周知端口到套接口:指定IP地址INADDR.ANY,允许服务器主机有多个接口
servaddr.sin_addr.s_addr = htonl(INADDR.ANY);
servaddr.sin_port=htons(13);
Bind(listenfd,(SA * ) &servaddr,sizeof(servaddr));

//把套接口变换成监听套接口:通过调用listen函数将此套接口变换成一个监听套接口,它使
//系统内核接受来自客户的连接。socket、 bind和listen是任何TCP服务器用于准备监听描述字
//(listening,descriptor)通常的三个步骤。常值LISTENQ在头文件unp.h中定义,它指定系统内
//核允许在这个监听描述字上排队的最大客户连接数。
Listen(listenfd,LISTENQ);

//接受客户连接,发送应答:服务器进程在调用Accept函数后处于睡眠状态,它等待客户的连接
//和内核对它的接受。TCP连接使用三路握手(three一way handshake)来建立,当握手完毕时, 
//accept函数返回,其返回值是一个称为已连接描述字(connected descriptor)的新描述字(connfd)。
//此描述字用于与新客户的通信。accept为每个连接到服务器的客户返回一个新的已连接描述字。
for( ; ;){
	connfd = Accept(listenfd,(SA *)NULLNULL);
	//time函数返回当前时间(自Unix纪元1970年以来的秒数),ctime可以将其转换成可读时间格式
	ticks = time(NULL);
	snprintf(buff,sizeof(buff)," %.24s\r\n" ,ctime(&ticks));
	
	//Write函数将结果返回给客户
	Write(connfd,buff,strlen(buff));
	
	//终止连接:服务器通过调用close关闭与客户的连接。它引发通常的TCP连接终止序列:
	//每个方向上发送一个FIN,每个FIN又由对方确认。
	Close(connfd);
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值