网络软件设计套接字接口函数制作主讲段景山段景山2socket函数调用socket()bind()listen()accept()recv()send()closesocket()recvfrom()sendto()connect()select()setsockopt()ioctlsocket()shutdown()通信类控制类getpeername()getsockname()getsockopt()信息类htonl()htons()ntohl()ntohs()inet_addr()inet_ntoa()辅助类段景山3socket()SOCKETWSAAPIsocket(INintaf,INinttype,INintprotocol)SOCKET类型就是int类型(见winsock.h中的定义)WSAAPI:说明函数是WindowsSocketApplicationApplicationProgrammingInterface函数IN:表示参数的作用是输入OUT:表示参数作用为输出段景山4SOCKETsocket(INintaf,INinttype,INintprotocol)af:地址族类型,tcp/ip使用AF_INETsocket()type:套接字类型,SOCK_STREAMSOCK_DGRAMSOCK_RAWSOCK_RDMSOCK_SEQPAKCET默认情况下使用TCP协议默认情况下使用UDP协议数据直接封装在IP分组内功能:建立一个套接口结构,将其描述符交给调用者protocol:协议号,一般设置为0返回:套接字描述符实验:测试socket()的各个参数,如使用非常规的af,type,protocol来测试段景山5bind()intbind(INSOCKETs,INstructsockaddr*name,INintnamelen)s:套接字描述符name:本地端点(套接字)地址结构指针namelen:本地端点(套接字)地址结构大小功能:建立套接字和端点之间的关系--确定“我是谁”返回:正确建立为0,否则为SOCKET_ERROR实验:能否在一个套接字描述符上两次绑定不同端点不可以,PPT3Page5Test1工程。能否在不同的套接字上绑定同一个端点不可以,PPT3Page5Test2工程。段景山6listen()intlisten(INSOCKETs,INintbacklog)s:套接字描述符backlog:设置同时监听的连接个数,最好不设置为0,目前最大为5功能:设置套接字为监听模式。服务器模式返回:设置成功为0,否则为SOCKET_ERROR实验:如何通过backlog来限制同时接收的连接个数设计实验方案,预期的结果(-1)段景山7connect()intconnet(INSOCKETs,INstructsockaddr*name,INintnamelen)s:套接字描述符name:端点(套接字)地址结构指针namelen:端点(套接字)地址结构大小功能:与服务器建立连接返回:连接成功为0,不成功为-1实验:服务器的地址可以是INADDR_ANY吗?为什么?不可以,客户机要确定服务器是谁。连接前一定要绑定本地端点吗?不一定,如果不绑定则当connect语句执行后系统分配一个端口给客户机段景山8accept()SOCKETaccept(INSOCKETs,OUTstructsockaddr*addr,INOUTint*addrlen)addr:远端点(套接字)地址结构指针addrlen:远端点(套接字)地址结构大小指针s:套接字描述符功能:接受一个对方调用connect()请求的连接。该连接将在返回的新套接字上完成返回:连接所在的新套接字描述符,不成功则为-1输出:addr远端点地址addrlen远端点地址结构大小实验:addr在调用前是否一定要填入内容,addrlen呢?不用,当客户机请求连接后再填。思考:客户认为已建立连接是在之前还是之后????段景山9recv()intrecv(INSOCKETs,OUTchar*buf,INintlen,INintflags)s:套接字描述符buf:接收缓冲区的指针len:接收缓冲区大小思考:为什么要设置len避免客户机发过来的字符数超出buf的大小flags:接收方式,一般为0。MSG_OOB:读取带外数据MSG_PEEK:数据不从队列中取出实验:MSG_PEEK的作用功能:从套接字接收数据,数据将放在buf所指的缓冲区内。通过返回值,调用者可以获得真正接收的字节数。返回:接收的字节数输出:buf缓冲区内将填入接收的数据段景山10send()intsend(INSOCKETs,INchar*buf,INintlen,INintflags)s:套接字描述符buf:发送缓冲区的指针len:发送的字节数flags:发送方式,一般为0。功能:从套接字发送数据,用户事先准备好数据,放在buf里。返回:真正发送的字节数思考:len的作用,和recv中的len有什么区别MSG_OOB:发送带外数据MSG_DONTROUTE:数据外送时,不做路由选择段景山11recvfrom()intrecvfrom(INSOCKETs,OUTchar*buf,INintlen,INintflags,OUTstructsockaddr*from,INOUTint*fromlen)s:套接字描述符buf:接收缓冲区的指针len:接收缓冲区大小flags:接收方式,一般为0。from:远端点结构指针fromlen:远端点结构大小指针功能:在套接字接收数据,并捕获发送远端点地址。返回:接收的字节数输出:buf缓冲区内将填入接收的数据from中将填入远端点信息fromlen中将填入远端点结构大小思考:和recv有什么区别段景山12sendto()intsendto(INSOCKETs,INchar*buf,INintlen,INintflags,INstructsockaddr*to,INinttolen)s:套接字描述符buf:发送缓冲区的指针len:发送的字节数flags:发送方式,一般为0。功能:从套接字发送数据,用户事先准备好数据,放在buf里。to:远端点地址结构指针tolen:远端点地址结构大小返回:真正发送的字节数思考:与send的区别在这些函数中为什么有些时候端点地址结构大小传值而有些时候传指针?段景山13shutdown()intshutdown(INSOCKETs,INinthow)s:套接字描述符how:断开连接方式功能:可以三种方式断开连接how为0(SD_RECEIVE):套接字不再提供接收数据服务how为1(SD_SEND):套接字不再提供发送数据服务how为2(SD_BOTH):套接字不再提供接收数据和发送注意,这将发出一个FIN数据服务返回:正确执行为0,否则为-1实验:三种方式下的效果。段景山14closesocket()intclosesocket(INSOCKETs)s:套接字描述符功能:关闭套接字,如果套接字上有连接,则连接也关闭了返回:成功为0。思考:closesocket与shutdown的区别,本质区别段景山小结以套接字为主关键参数所有的通信类和控制类函数关于地址结构长度参数有时候是形参,有时是实参有时是整型变量,有时是整型指针有时是输入,有时是输出,有时是输入和输出关于套接字函数返回值的处理通信程序是需要双方配合的,如果对方没有按照预想的配合,应该有应对措施。应对措施之一,依靠函数错误返回值,避免自己的流程以错误的姿态进入15段景山16关于错误处理套接字函数的返回值中,为0多数表示为成功执行为-1表示错误(SOCKET_ERROR)在windows系统下,也可通过WSAGetLastError()来取得进一步的出错代号例:1if(bind(s,……)==SOCKET_ERROR){error_num=WSAGetLastError();}当出错以后,通过getsockopt()设置为SO_ERROR来获得进一步的出错代号if(bind(s,……)==SOCKET_ERROR){getsockopt(s,SOL_SOCKET,SO_ERROR,&error_num,sizeof(error_num));}例:2思考:获得错误代码以后,程序的处理模式段景山17关于错误处理错误代码:在winsock.h中查询if(bind(s,……)==SOCKET_ERROR){error_num=WSAGetLastError();switch(error_num){caseWSANOTINITIALISED:dealwiththeproblem;break;caseWSAEADDRINUSE:dealwiththeproblem;break;……}}配合本部分内容完成实验5