LuobingDong1/401网络应用程序设计-高级socket函数LuobingDong2/402创建网络端点-socket…//1.创建网络端点intsockfd=socket(AF_INET,SOCK_STREAM,0);if(sockfd==-1){printf(can;tcreatesocket\n);exit(1);}…LuobingDong3/403主要内容n域名访问n高级socket函数n多路复用nsocket选项LuobingDong4/404域名访问n域名系统-DNSl域名IP地址的别名,便于记忆-202.117.112.10l域名层次域名层次树l域名服务器存放域名和IP对应记录提供域名查询功能educomcneducomorgxidian……LuobingDong5/405域名访问n域名系统-DNSl域名查找过程应用程序解析器本地域名服务器其他域名服务器解析器配置文件调用函数gethostbyname函数返回UDP请求UDP响应gethostname可以参考RFC882、RFC883实现LuobingDong6/406域名访问n域名到IP的转换函数lstructhostent*gethostbyname(constchar*name)功能:查询域名对应的IPstructhostent{charh_name;/*主机正式名称*/char**h_aliases;/*别名列表,以NULL结束*/inth_addrtype;/*主机地址类型:AF_INET*/inth_length;/*主机地址长度:4字节32位*/char**h_addr_list;/*主机网络地址列表,以NULL结束*/}#defineh_addrh_addr_list[0];//主机的第一个网络地址LuobingDong7/407域名访问n域名到IP的转换函数lgethostbyname示例structhostent*he=gethostbyname(“”);if(he!=NULL){printf(h_name:%s\n,he-h_name);printf(h_length:%d\n,he-h_length);printf(h_addrtype:%d,he-h_addrtype;for(i=0;he-h_aliases[i]!=NULL;i++)printf(h_aliases%d:%s\n,i+1,he-h_aliases[i]);//列出所有地址for(i=0;he-h_addr_list[i]!=NULL;i++){structin_addr*addr;addr=(structin_addr*)he-h_addr_list[i];printf(ip%d:%s\n,(i+1),inet_ntoa(*addr));}}elseprintf(gethostbynameerror:%s\n,hstrerror(h_errno));LuobingDong9/409域名访问n域名到IP的转换函数l查询:antares.sina.com.cnh_length:4h_length:4h_addrtype:2h_addrtype:2h_aliase1::202.112.8.2ip1:202.205.3.142ip2:202.205.3.130ip2:202.205.3.143ip3:202.205.3.142ip3:202.112.8.2ip4:202.205.3.143ip4:202.205.3.130LuobingDong10/4010域名访问n域名到IP的转换函数l对同一DNS服务器两次调用gethostbyname返回的IP地址列表顺序不同l在不同的DNS服务器上查询,返回结果不同l查询失败时错误类型保存在全局变量h_errno中,函数hstrerror可以得到h_errno的描述信息gethostbyname是逐级查询,可能需要访问多个域名服务器,会消耗较多时间,建议采用多进程(线程)处理LuobingDong11/4011域名访问n同时兼容域名和IP的应用程序l客户端程序client.c…char*host=“202.112.8.2”;//””bzero(&srvaddr,sizeof(srvaddr));srvaddr.sin_family=AF_INET;srvaddr.sin_port=htons(port);//if(inet_aton(host,&srvaddr.sin_addr)!=1)if(addr_conv(host,&srvaddr.sin_addr)==-1){printf(addrconvertfail\n);return1;}LuobingDong12/4012域名访问n同时兼容域名和IP的应用程序l地址转换函数addr_convintaddr_conv(char*address,structin_addr*inaddr){structhostent*he;if(inet_aton(address,in_addr)!=0)return1;he=gethostbyname(address);if(he!=NULL){*inaddr=*((structin_addr*)he-h_addr_list[0]);return1;}return-1;}LuobingDong13/4013域名访问nIP到域名的转换函数lstructhostent*gethostbyaddr(constchar*addr,size_tlen,intfamily);功能:查询IP对应的域名structin_addraddr;inet_aton(“202.117.112.10”,&addr);structhostent*he=gethostbyaddr((char*)addr,4,AF_INET);if(he!=NULL){printf(h_name:%s\n,he-h_name);}elseprintf(gethostbyaddrerror:%s\n,hstrerror(h_errno));LuobingDong14/4014高级socket函数nrecv和sendlintrecv(intsockfd,voidbuf,intlen,intflags);lintsend(intsockfd,voidbuf,intlen,intflags);l功能:通过参数控制读写数据l参数:sockfd-socket描述符buf-发送或接收数据缓冲区len-发送或接收数据长度flags-发送或接收数据的控制参数l返回值:≥0-成功,-1失败LuobingDong15/4015高级socket函数nrecv和sendl控制参数说明flags=0,相当于read和write函数flags=MSG_DONTROUTE,发送数据不查找路由表,适用于局域网,或同一网段flags=MSG_OOB,发送和接收带外数据flags=MSG_PEEK,接收数据时不从缓冲区移走数据,其他进程调用read或recv仍然可以读到数据flags=MSG_WAITALL,数据量不够时,读操作等待,不返回,但在收到信号,连接端口时仍然会结束。LuobingDong16/4016高级socket函数nrecv和sendl控制参数说明表标志recvsendMSG_DONTROUTE√MSG_OOB√√MSG_PEEK√MSG_WAITALL√LuobingDong17/4017高级socket函数nintshutdown(intsockfd,inthowto);l功能:关闭连接l参数:sockfd-socket描述符howto-指定关闭操作的类型l返回值:0-成功,-1失败LuobingDong18/40高级socket函数nintshutdown(intsockfd,inthowto);l说明:howto=0,关闭读通道,丢弃尚未读取的数据,对后来接收到的数据返回确认后丢弃datadataackdata客户端TCP协议服务器TCP协议read返回值0shutdown(fd,0)read返回值=0write关闭读通道客户端应用程序writewriteread返回值0服务器应用程序LuobingDong19/4019高级socket函数nintshutdown(intsockfd,inthowto);l说明:howto=1,关闭写通道,继续发送发送缓冲区未发送完的数据,然后发送FIN字段关闭写通道dataFINdata服务器端TCP协议客户端TCP协议read返回值0read返回值=0write关闭写通道服务器端应用程序writeshutdown(fd,1)read返回值0客户端应用程序write返回错误LuobingDong20/4020高级socket函数nintshutdown(intsockfd,inthowto);l说明:howto=2,关闭读写通道,任何进程不能再操作这个socketshutdown和close的区别–shutdown操作连接通道,其他进程不能再使用已被关闭的通道;close操作描述符,其他进程仍然可以使用该socket描述符–close关闭应用程序与socket的接口,调用close之后进程不能再读写这个socket;shutdown可以只关闭一个通道,另一个通道仍然可以操作LuobingDong21/4021高级socket函数nreadv和writevl在一次函数调用中读、写多个非连续缓冲区。有时也将这两个函数成为散布读和聚集写nrecvmsg和sendmsgl类似于recv和send,但更强大ngetsockname和getpeernamel获取一个套接字的名字(地址)和端口LuobingDong22/4022多路复用n多路复用函数selectlintselect(intmaxfd,fd_set*rdset,fd_set*wrest,fd_set*exset,structtimeval*timeout);l功能:检查多个文件描述符(socket描述符)是否就绪,当某一个描述符就绪(可读、可写或发生异常)时函数返回。可以实现输入输出多路复用l返回值:有描述符就绪则返回就绪的描述符个数;超时时间内没有描述符就绪返回0;执行失败返回-1。LuobingDong23/4023多路复用n多路复用函数selectl参数:maxfd-需要测试的描述符的最大值,实际测试的描述符从0-maxfd-1rdset-需要测试是否可读的描述符集合(包括处于listen状态的socket接收到连接请求)wrset-需要测试是否可写的描述符集合(包括以非阻塞方式调用connect是否成功)exset-需要测试是否异常的描述符集合(包括接收带外数据的socket有带外数据到达)timeout-指定测试超时的时间LuobingDong24/4024多路复用n多路复用函数selectltimeout参数timeval结构timeout=NULL,select将永远阻塞直到有一个描述符就绪,或者出现错误(接收到信号)。timeout0,在timeout时间内如果有描述符就绪则返回,否则在timeout时间后返回0;如果将3个描述符集合都设定为NULL则select相当于sleep函数,只是时间可以精确到毫秒timeout=0,select检查完描述符集合后立即返回structtimeval{longtv_sec;//秒longtv_usec;//毫秒}LuobingDong25/4025多路复用n多路复用