第 12 章 网络编程_第1页
第 12 章 网络编程_第2页
第 12 章 网络编程_第3页
第 12 章 网络编程_第4页
第 12 章 网络编程_第5页
已阅读5页,还剩60页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第12章网络编程内容提要网络编程概述互联网传输协议

Socket上的读写操作

Unix域套接字套接字选项构建并发服务器12.1网络编程概述网络套接字Socket

TCP/IP诞生于4.4BSD,随着TCP/IP在互联网的广泛应用,编程接口BSDsocket也事实上成为网络接口标准。目前,已被包括Linux在内的众多操作系统支持。

BSDsocket为一种通用网络编程接口,支持丰富的网络协议,例如,ipx/spx等。系统调用接口层VFS接口层Socket抽象层EthernetTokenRingPPPSLIP网络设备驱动接口层PF_INETPF_PACKETPF_IPXPF_UNIXiptcpudp设备驱动层协议层接口层SOCK_DGRAMSOCK_RAWSOCK_RAWSOCK_DGRAMSOCK_STREAMreadwriteclosesocketrecvsendLinux内核支持的协议客户机/服务器模型socket采用客户机/服务器模式,服务器监听客户机发送的连接请求,客户机需预先获知服务器的地址,双方连接建立后,可实现双向数据传输。

传输层通常提供两种类型的传输服务,面向连接的传输服务和无连接的传输服务,对于面向连接的传输服务,可确保双方传输数据的有序和可靠。对于无连接的传输协议,无须建立连接,可直接根据对方地址收发数据。4TCP/IP协议TCP/IP作为互联网的标准协议族,其传输层为上层提供TCP和UDP两种服务。

TCP是一种面向连接的传输协议,通信双方以字节流方式可靠地交换数据,用户无需关心内部复杂的协商逻辑,但TCP也会消耗一定的带宽资源。

UDP是一种无连接的数据报协议,以数据报为单位,数据报在传输过程中可能丢失和失序,UDP消耗相对较少的带宽资源。应用编程接口分类API功能描述socketAPIsocket创建套接字bind绑定地址listen监听绑定地址上的连接请求accept接收来自绑定地址上的连接请求connect向服务器发起连接请求recv/recvfrom/recvmsg接收数据send/sendto/sendmsg发送数据close/shutdown关闭/优雅关闭sendfile在内核空间传输文件socketpair创建互联套接字getsockopt/setsockopt获取/设置套接字选项12.2互联网传输协议内容提要面向连接的传输协议TCPsocket编程接口无连接的传输协议UDP面向连接的传输协议TCPTCP是一种面向连接基于字节流的可靠传输协议,确保通信双方数据传输的有序和正确。采用客户机/服务器模式,服务器监听客户机发起的连接请求,在双方建立连接后,便可进行数据传输。基于TCP的客户机/服务器模式服务器端请求数据socket()bind()listen()accept()socket()connect()send()recv()客户端(Blockuntilconnection)建立连接recv()send()回复数据close()关闭连接recv()close()创建套接字1.socket函数头文件

#include<sys/types.h> #include<sys/socket.h>函数原型

int

socket(intdomain,inttype,intprotocol);功能 创建套接字。参数

domain:协议族。

type:协议类型。

protocol:默认为0,通常用于原始套接字选项。返回值 成功:套接字的文件描述符,错误:返回-1。创建套接字(续)参数domain描述AF_UNIX本地通信协议AF_INETIPv4互联网协议AF_INET6IPv6互联网协议AF_IPXIPXnovellprotocolsAF_NETLINK配置协议参数type描述SOCK_STREAM面向连接的字节流服务SOCK_DGRAM无连接不可靠数据报服务SOCK_RAW底层协议访问服务socket函数中参数type的定义函数中参数domain的定义绑定地址头文件

#include<sys/types.h> #include<sys/socket.h>函数原型

int

bind(int

sockfd,struct

sockaddr*addr,socklen_t

addrlen);功能 绑定本地地址。参数

sockfd:套接字的文件描述符。

addr:ip地址。

addrlen:地址长度。返回值 成功返回0,错误:返回-1。绑定地址(续)sockaddr使用更一般的类型,其定义如下。

struct

sockaddr{

sa_family_t

sa_family;//协议族

charsa_data[14];//内容与协议族有关

}TCP/IP协议族的地址类型有ipv4和ipv两种,下面仅以ipv4未例,其地址类型sockaddr_in的定义如下。struct

sockaddr_in{shortint

sin_family;//取值为AF_INETunsignedshortint

sin_port;//端口号struct

in_addr

sin_addr;//IP地址...};监听套接字头文件

#include<sys/socket.h>函数原型

int

listen(int

sockfd,intbacklog);功能 监听套接字上的连接请求。参数

sockfd:套接字的文件描述符。

backlog:可容纳连接请求的数量。返回值 成功返回0,错误返回-1。接收连接头文件

#include<sys/types.h> #include<sys/socket.h>函数原型

int

accept(int

sockfd,struct

sockaddr*addr,socklen_t*addrlen);功能 接收连接。参数

sockfd:套接字的文件描述符。

addr:连接请求的地址。

addrlen:地址长度。返回值 成功返回为新连接创建的套接字,失败返回-1。发起连接请求头文件

#include<sys/types.h> #include<sys/socket.h>函数原型

int

connect(int

sockfd,struct

sockaddr*addr,socklen_t

addrlen);功能 向服务器发起连接请求。参数

sockfd:套接字的文件描述符。

addr:服务器地址。

addrlen:地址长度。返回值 成功返回0,错误返回-1。接收数据头文件

#include<sys/types.h> #include<sys/socket.h>函数原型

ssize_t

recv(int

sockfd,void*buf,size_t

len,intflags);

ssize_t

recvfrom(int

sockfd,void*buf,size_t

len,int

flags,struct

sockaddr*from,socklen_t*addrlen);

ssize_t

recvmsg(int

sockfd,struct

msghdr*msg,intflags);功能 从套接字接收数据。参数

sockfd:套接字的文件描述符。buff:缓冲区地址。

len:缓冲区大小。from:目标地址。addrlen:地址长度。

msg:接收请求地址。flags:选项。返回值 成功返回接收的字节数,失败返回-1。接收数据recv(sockfd,buf,len,flags);等价于:recvfrom(sockfd,buf,len,flags,NULL,NULL);。msg

为msghdr类型指针,可使函数参数最小化,msghdr类型封装了接收数据所需的参数,其定义如下。struct

msghdr{void*msg_name;//目标地址

socklen_t

msg_namelen;//目标地址长度

struct

iovec*msg_iov;//缓冲区

size_t

msg_iovlen;//缓冲区数量

void*msg_control;//附加数据地址

size_t

msg_controllen;//附加数据长度

int

msg_flags;//用于接收数据};发送数据头文件 #include<sys/types.h> #include<sys/socket.h>函数原型

ssize_t

send(int

sockfd,constvoid*buf,size_t

len,intflags);

ssize_t

sendto(int

sockfd,constvoid*buf,size_t

len,int

flags,const

struct

sockaddr*to,socklen_t

addrlen);

ssize_t

sendmsg(int

sockfd,conststruct

msghdr*msg,intflags);功能

向套接字发送数据。参数

sockfd:套接字的文件描述符uff:缓冲区地址。

len:缓冲区大小。to:目标地址。addrlen:地址长度。

msg:发送请求。flags:选项。返回值 成功返回发送的字节数,失败返回-1。关闭连接头文件

#include<unistd.h> #include<sys/socket.h>函数原型

int

close(int

sockfd);

int

shutdown(int

sockfd,inthow);功能 关闭/优雅关闭连接。参数

sockfd:套接字的文件描述符。

how:关闭的方式。返回值 成功返回0,失败返回-1。关闭连接

无须传输数据时,应关闭连接,当向已关闭的套接字发送数据时,将导致失败。当调用close函数关闭连接时,若套接字的内核发送缓冲尚有未发送的数据,close会一直等待,直至数据全部发送完成或超时。并非所有发生异常的一方都产生RST包,需通过其他手段获知对方的状态。优雅关闭close函数会将收发两条通道全部关闭,后续无法接收数据;若使用shutdown函数,可仅关闭写通道,但仍可继续接收数据,故称为优雅关闭。收到FIN包的一方返回0,仅表示对方已关闭了写操作,无法确定对方是否关闭了读操作。无连接的传输协议UDPUDP为无连接的传输协议,无法保证将数据有序且正确地送达对方,但并不意味着丢报现象的频繁发生,这取决于整个网络的状态。在局域网环境下,通常有很高的可靠性。相较于TCP,UDP消耗较少的带宽资源,具有较高的传输效率。

UDP在很多应用场景得到了广泛应用,例如,流媒体和网络电话等。3基于UDP的客户机/服务器模式请求数据socket()bind()recvfrom()服务器端socket()sendto()recvfrom()客户机端(Blockuntilreceivedatagram)sendto()回复数据close()12.3Socket上的读写操作内容提要socket支持文件I/O接口面向连接的I/O操作socket的异步驱动模式零拷贝技术字节序和字节对齐socket支持文件I/O接口

内核为socket提供了文件I/O接口的支持,对于新建套接字时返回的套接字描述符,也适用于文件的I/O操作,例如,read/write函数和select/poll函数等。由于标准I/O函数库建立在基本文件I/O基础上,因此,标准I/O函数库中的函数也适用于套接字,例如,fgets和fputs函数等,由于在用户空间设置了缓冲区,从而会给I/O读写操作带来一定的影响。面向连接的I/O操作

由于面向连接套接字的字节流特性,数据的流速取决于双方套接字内核缓冲区滑动窗口状态的变化,无论采用阻塞或非阻塞模式,在读写套接字时,未必能将指定大小的数据一次性操作成功。面向连接的读操作

对于读操作,造成无法一次性全部读取所需数据的因素如下。1.所需的数据未全部到达内核接收缓冲区。2.即使全部到达,在读取过程也可能被信号中断。面向连接的写操作

对于写操作,造成无法一次性全部写入指定数据的因素如下。1.写入过程被信号中断。2.在非阻塞模式下,套接字的内核发送缓冲区仅能容纳部分待写入的数据。一次性读特定大小的数据ssize_t

readn(int

fd,void*buffer,size_tn){

ssize_t

numRead;

size_t

totRead; char*buf;

buf=buffer; for(totRead=0;totRead<n;){

numRead=read(fd,buf,n-totRead); if(numRead==0) returntotRead; if((numRead==-1)&&(errno==EINTR)) continue; else return-1;

totRead+=numRead;

buf+=numRead; } returntotRead;}一次性写入特定大小的数据ssize_t

writen(int

fd,constvoid*buffer,size_tn){

ssize_t

numWritten;

size_t

totWritten; constchar*buf;

buf=buffer; for(totWritten=0;totWritten<n;){

numWritten=write(fd,buf,n-totWritten);if(numWritten<=0){ if(numWritten==-1&&errno==EINTR) continue; else return-1; }

totWritten+=numWritten;

buf+=numWritten; } returntotWritten;}socket的异步I/O模式

对处于非阻塞模式的套接字,为了获知套接字状态的变化,内核提供了两种异步I/O驱动模式。异步I/O事件驱动2.异步I/O信号驱动。异步I/O事件驱动

内核将套接字状态的改变抽象为I/O事件,例如,套接字上有新数据到达和发送缓冲区重新变得可用等,用户可通过select/poll/epoll监听套接字状态的变化,利用获取的I/O事件判断状态改变的原因,从而进行相应的处理,事件类型I/O事件I/O事件的描述readPOLLIN有数据到达readPOLLIN面向连接的请求到达readPOLLHUP对方关闭了连接readPOLLHUP向失效的套接字上写数据,同时发送SIGPIPE信号WritePOLLOUT发送缓冲区变得可用Read/WritePOLLIN|POLLOUT连接完成Read/WritePOLLERR发生了异步I/O错误Read/WritePOLLHUP对方关闭了一个方向上的通道ExceptionPOLLPRI紧急数据到达,同时发送SIGURG信号异步I/O信号驱动

若利用fcntl函数在套接字上设置了O_ASYNC标识,套接字则被设置为I/O信号驱动模式,当套接字的状态发生改变,内核会向指定的进程发送SIGIO信号或自定义的实时信号。当存在多个状态发生改变的套接字,信号处理程序可根据信号来源加以区分。零拷贝技术

对于某些应用,在数据传输时,需频繁在用户空间和内核空间复制数据,例如,web和ftp等。为了降低带来的系统开销,内核引入了称为零拷贝的技术,直接在内核完成数据复制,绕过了用户缓冲区,减少了数据拷贝次数。零拷贝接口函数sendfile函数头文件

#include<sys/sendfile.h>函数原型

ssize_t

sendfile(int

out_fd,int

in_fd,off_t*offset,size_tcount);功能 在内核空间传输文件。参数

out_fd:目标套接字的文件描述符。

in_fd:源文件描述符。

offset:偏移量。

count:数据的长度。返回值 成功返回实际拷贝的字节数,失败返回-1。字节序(1)小端模式小端模式是指将低字节存放在内存的低地址处,例如,Intel80x86处理器采用该模式。(2)大端模式大端模式正好与小端模式相反,将高字节存放在内存的低地址处,Motorola处理器采用这种模式,网络字节序采用大端模式,字节序的存储模式High-orderbyteLow-orderbyte高位16位/2字节

低位Low-orderbyteHigh-orderbyte地址增长的方向地址增长的方向AddressAAddressA+1小端模式大端模式AddressA+1AddressA字节对齐

理论上。任意类型的数据可存储于内存的任意位置,但出于效率等因素的考虑,某些处理器对数据的存储地址有一定的要求,n字节对齐是指数据的存储地址为n的整数倍,例如,对于IntelX86,简单类型和结构类型的存储地址均为4的整数倍。12.4Unix域套接字Unix域概述Unix域是一种特殊的传输协议,用于本地进程间通信,支持面向连接和无连接两种传输服务。在使用socket编写服务器和库户籍时,仅协议族和地址类型有所不同。Unix域套接字1.创建Unix域套接字Unix_socket=socket(AF_UNIX,type,0);2.Unix域的地址struct

sockaddr_un{

sa_family_t

sun_family;//取值AF_UNIX charsun_path[108];//文件路径};互联套接字

为了便于本地关联进程间通信,内核引入了socketpair接口函数用于创建一对互联套接字,通过它可实现父子进程或两子进程间通信。相较于无名管道的单向数据传输互联套接字可实现双向数据传输。创建互联套接字socketpair函数头文件

#include<sys/socket.h>函数原型

int

socketpair(intdomain,inttype,intprotocol,intsv[2]););功能 创建一对互联套接字。参数

domain:协议族。

type:协议类型。

protocol:子协议类型。

sv[2]:一对互联套接字的文件描述符。返回值 成功返回0,失败返回-1。12.5套接字选项套接字选项概述

每个套接字都有自身的行为属性,它们决定了套接字在收发数据时的行为特征。为了满足个性化需要,内核引入了getsockopt/setsockopt接口函数,用于获取/设置套接字的选项,以便套接字的行为符合用户的需求。获取/设置套接字选项getsockopt/setsockopt函数头文件

#include<sys/socket.h>函数原型

int

getsockopt(int

sockfd,int

level,int

optname,void*optval,socklen_t*optlen);

int

setsockopt(int

sockfd,int

level,int

optname,void*optval,socklen_t

optlen);功能 获取/设置套接字选项。参数

sockfd:套接字的文件描述符。

Level:协议层类型。

optname:选项名称。

optval:选项值。

optlen:optval占用的字节数。返回值 成功返回0,失败返回-1。通用选项参数optname类型定义SO_BROADCASTBOOL允许/禁止发送广播消息SO_DEBUGBOOL设置是否允许调试SO_DONTROUTEBOOL设置是否绕过正常的路由器SO_KEEPALIVEBOOL定时监测连接是否处于活动状态SO_LINGERLINGER关闭链接时的超时设置SO_OOBINLINEBOOL设置紧急数据放入普通数据流SO_RCVBUFint设置接收缓冲区的大小SO_REUSEADDRBOOL打开或关闭地址复用功能SO_RCVTIMEODWORD设置接收函数的超时时间(毫秒)SO_SNDBUFint设置发送缓冲区的大小

通用选项位于套接字接口层,是对各类协议接口的抽象,与特定的协议无关,但并非通用选项适用于所有协议。LINGER选项

该选项用于定义关闭连接时的超时设置,选项值的类型定义如下。#including<sys/socket.h> structlinger{ intl_onoff;//0表示关闭,非0表示打开 intl_linger;//超时时间(秒)};LINGER选项(续)若成员变量l_onoff置为0,内核默认设置,该选项关闭,成员变量l_linger的值被忽略,close/shutdown立即返回,残留在发送缓冲区的数据被丢弃。2.若成员变量l_onoff置为非0,l_linger设置超时时间,调用的close/shutdown函数挂起,直至内核发送缓冲区的数据全部被对方确认或超时时间到期;若到期仍有未确认的数据,则向

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论