您好,欢迎访问三七文档
当前位置:首页 > 电子/通信 > 综合/其它 > TCPIP 实验指导书
1.Linux文件IO基础API的使用1.1文件IO基础APIopenclosereadwritelseek1.2基础文件IO操作流程1.2.1打开将要进行读或写的磁盘文件如果要对一个文件进行操作,不管是读或者是写,首先需要将一个保存于磁盘的文件打开,并将文件数据装入内存中。在Linux中,使用open系统调用完成对一个磁盘文件的打开工作。文件定位在Linux系统中,用户通过文件路径告知操作系统所需要操作文件在文件目录树中的位置。例如:”/etc/passwd”这个文件路径,其是一个绝对路径,也就是从文件目录树的根开始的。对于该路径中包含了以下4个部分:[1].“/”:表示文件目录树的根目录;[2].“etc”:表示根目录下的一个名为etc的子目录;[3].“/”:用来分隔不同层次的目录或文件名的分隔符号;[4].“passwd”:表示etc子目录中的一个文件passwd;应当注意的是,这个文件路径只是用户层次的路径,要真正找到并打开磁盘中对应的文件数据,Linux操作系统还需要做很多工作。但这些工作对于用户而言是透明的,用户只需通过调用系统提供的系统调用open时,为open提供所要操作的文件的路径字符串即可。即为open提供第一个参数的具体值。操作方式设定在提供了要操作文件的文件路径给open系统调用之外,还需要告知系统,用户将要如何操作该文件;如果文件路径不存在,系统应该如何处理;如果创建一个文件,是否用户有特殊的权限设定;如果文件存在,那么向该文件写数据是覆盖还是追加等等。保存文件描述符利用open成功打开一个文件后,open系统调用会返回系统生成的一个该文件的文件描述符,而该文件描述符是之后操作给文件最重要的一个依据,所以在编写程序时,应该声明一个变量保存该文件描述符,以便之后对该文件的操作。1.2.2读取文件中的数据对已打开的文件进行读操作,可以调用read系统调用。在使用read系统调用时,需要首先准备足够大的缓冲区,特别是要读取完整的文件数据时。例如,我们希望读取路径/etc/passwd所指定的文件内容时,可以编写以下程序段来保证该文件数据最终被读入到应用程序内存空间中。...//此处处理读出的文件数据...1.2.3向文件中写入数据在上一节中给出的代码完成了打开文件/etc/passwd,并将该文件中的数据读入到缓冲区buffer_read中的工作。而在本节中,下面给出的代码将打开文件/tmp/passwd,如果该文件不存在就创建该文件,如果该文件存在,那么就以覆盖的方式向文件中写入新数据。然后,将前面读取出来/etc/passwd文件的内容写入到/tmp/passwd文件中。...//关闭文件...1.2.4关闭文件前面程序完成了读取/etc/passwd文件的内容,并将其写入到/tmp/passwd文件中。在完成了对文件的操作后,需要将打开的文件进行关闭。...2基于TCP的客户端与服务器设计流程2.1基于TCP的服务器TCP是面向连接的传输层协议,因此服务器通常情况下是被动等待客户程序的连接请求的到来,然后与该客户程序建立连接,并为客户程序提供相应服务。2.1.1设计流程基本描述1.建立服务器端本地套接字对象;2.为本地套接字绑定套接字地址;3.利用本地套接字监听网络,换句话来讲就是被动等待服务请求的到来;4.接受一个客户的连接请求,建立连接;5.响应客户请求,为客户提供服务;6.完成服务后,客户无需继续服务时断开连接,并返回3。2.1.2所涉及的函数与数据结构2.1.2.1socket函数domain参数:type参数:protocol参数:IPPROTO_TCP:TCP传输协议IPPROTO_UDP:UDP传输协议IPPROTO_SCTP:SCTP传输协议返回值:执行成功,函数返回一个非负整数值,该值作为所创建的套接字对象的描述符sockfd,类似于文件间描述符;执行出错,函数返回-1;简要说明domain和type两个一般就可以确定一种协议:AF_INET和SOCK_STREAM可以确定IPv4和TCP协议AF_INET6和SOCK_STREAM可以确定IPv6和TCP协议AF_INET和SOCK_DGRAM可以确定IPv4和UDP协议AF_INET6和SOCK_DGRAM可以确定IPv6和UDP协议如果默认使用由domain和type共同决定的协议时,protocol参数取值可以为0。2.1.2.2IPv4套接字地址#includenetinet/in.hstructin_addr{in_addr_ts_addr;/*32-bitIPv4address*//*networkbyteordered*/};structsockaddr_in{uint8_tsin_len;/*lengthofstructure(16)*/sa_family_tsin_family;/*AF_INET*/in_port_tsin_port;/*16-bitTCPorUDPportnumber*//*networkbyteordered*/structin_addrsin_addr;/*32-bitIPv4address*//*networkbyteordered*/charsin_zero[8];/*unused*/};以上套接字地址数据结构,主要用于构造基于IPv4协议族的套接字地址。在网络通信C/S模式系统中,客户程序进行connect以及服务器进行bind之前,都需要构造该套接字地址数据结构的实例。构造IPv4套接字地址下面的伪码显示了构造一个IPv4套接字地址的基本方法:structsockaddr_insockaddr;memset(&sockaddr,0,sizeof(sockaddr));sockaddr.sin_family=AF_INET;sockaddr.sin_addr.s_addr=IPv4地址数值形式,且是网络字节序形式;sockaddr.sin_port=端口号,且是网络字节序形式;IPv4地址的多种形式1.点分四组:192.168.0.1002.32bits二进制数:0xC0A80064(H)=3232235620(D)而其实IP地址的本质应该就是一个数值类型,就IPv4而言,地址就是一个32bits的二进制数。而点分四组是对于IP地址助记的方式。也就是说实际中,人们使用点分四组方式,来表达要使用的地址,而最终传给计算机系统时,都会被转换成其最本质的形式。不同形式的IPv4地址间转换点分四组字符串--数值inet_addr函数:(不推荐使用)#includearpa/inet.hin_addr_tinet_addr(constchar*cp);inet_addr函数完成将一个点分四组形式的地址字符串转换为一个32位网络字节序保存的数值型地址,并返回该数值型地址。例如:inet_addr(“192.168.0.100”);inet_aton函数:(仅用于IPv4)#includearpa/inet.hintinet_aton(constchar*cp,structin_addr*inp);inet_aton函数完成将一个点分四组形式的地址字符串转换为一个32位网络字节序保存的数字型地址,并将其保存到参数inp指定的in_addr结构示例中。例如:inet_aton(“192.168.0.100”,&sockaddr.sin_addr);数值--点分四组字符串inet_ntoa函数:(仅用于IPv4)#includearpa/inet.hchar*inet_ntoa(structin_addrin);inet_ntoa函数完成将一个数值型IP地址转换为点分四组字符串形式,并返回该字符串。这个方法主要用于通过系统调用获取的IP地址数值形式转换为易读形式显示。大端字节序(big-edian):即将数值数据的高位存放于所分配内存的首地址字节中的方式成为大端字节序;小端字节序(little-edian):即将数值数据的低位存放于所分配内存的首地址字节中的方式称为小端字节序;字节序转换由于使用遵循Intel体系结构的CPU的计算机系统中,对于多字节数值型数据保存于内存中采用小端字节序,而Internet中对于数值型数据采用大端字节序,因此在这种系统中的网络应用与网络进行多字节数值数据传输时就需要进行字节序间的转换。htons&htonl函数#includenetinet/in.huint16_thtons(uint16_thostshort);uint32_thtonl(uint32_thostlong);以上两个函数都是将一个主机字节序(小端字节序)数值数据转换为网络字节序(大端字节序)数值数据。只不过,htons转换2个字节的短整型数据,而htonl转换4个字节的长整型数据。ntohs&ntohl函数#includenetinet/in.huint16_tntohs(uint16_tnetshort);uint32_tntohl(uint32_tnetlong);以上两个函数都是将一个网络字节序(大端字节序)数值数据转换为主机字节序(小端字节序)数值数据。只不过,ntohs转换2个字节的短整型数据,而ntohl转换4个字节的长整型数据。较为完整的套接字地址构造代码structsockaddr_insockaddr;memset(&sockaddr,0,sizeof(sockaddr));sockaddr.sin_family=AF_INET;sockaddr.sin_addr.s_addr=inet_addr(“192.168.0.100”);sockaddr.sin_port=htons(“5000”);或structsockaddr_insockaddr;memset(&sockaddr,0,sizeof(sockaddr));sockaddr.sin_family=AF_INET;inet_aton(“192.168.0.100”,&sockaddr.sin_addr);sockaddr.sin_port=htons(“5000”);2.1.2.3通用套接字地址#includesys/socket.hstructsockaddr{uint8_tsa_len;sa_family_tsa_family;/*addressfamily:AF_xxxvalue*/charsa_data[14];/*protocol-specificaddress*/};由于套接字API可以用于多种协议,因此可以接受的地址也是多种多样的。所以大部分需要接受协议地址的API系统调用中地址形式参数都使用的是sockaddr这个通用地址结构类型。2.1.2.4bind函数服务器端通常是被动等待客户程序的TCP连接,因此要给定提供给客户端程序连接时可以使用的套接字地址。服务器端套接字地址的设定,主要是端口号,而服务器进程所运行计算机的IP地址可以不明确指定为某个IP地址,而通常使用的是INADDR_ANY这个系统提供的通配地址。使用该地址的目的在于,如果服务器进程所在计算机系统具有多个IP地址时,无论客户软件通过其中的那个IP地址来连接服务器,只要端口号是该服务器所监听的端口号,该服务器都要能够处理客户软件的请求。bind函数声明sockfd参数:套接字描述符,用于指明bind函数要操作的套接字。addr参数:套接字将要绑定的套接字地址所保存的地址结构变量的首地址。addrlen参数:保存套接字地址的结构所占字节数返回值:成功返回0;失败返回-1。函数说明该函数一般用于服务器,不过客户软件也可以使用。当一个套接字已经绑定了一个套接字地址,那么再次对该套接字调用bind函数时会出错。即不允许对一个套接字多次调用bind函数。函数使用服务器程序在完成了套接字创建以及套接字地址的构建后,就需要调用bind函数将构建的套接字与创建的套接字关联起来。下面的代码显示从套接字创建开始到bi
本文标题:TCPIP 实验指导书
链接地址:https://www.777doc.com/doc-4376585 .html