Socket编程技巧(一)Socket编程的重要数据结构1、网络字节顺序与主机字节顺序两种主机字节顺序:低位先存,高位先存(根据机器的不同和有区别,目前的INTER主机为低位先存方式)网络字节顺序:对于16位或32位整数TCP/IP要求高位先存相关转换函数:htons()--HosttoNetworkShort;htonl()--HosttoNetworkLong;ntohs()--NetworktoHostShort;ntohl()--NetworktoHostLong;2、地址结构(1)structsockaddr//套接字地址结构{unsignedshortsa_family;//internet协议族AF_INETcharsa_data[14];//14字节的协议地址,包括IP地址和端口};(2)structsockaddr_in//in代表internet{shortintsin_family;//internet协议族=AF_INET,IPV4;=AF_INET6,IPV6unsignedshortintsin_port;//端口号,必须是网络字节顺序调用htons()函数structin_addrsin_addr;//internet地址,必须是网络字节顺序调用htonl()函数unsignedcharsin_zero[8]//填0};(3)structin_addr//IPv4地址,4个字节{unsignedlongs_addr;};(二)Socket编程中几个重要的函数(1)socket():套接字创建—指定协议一元intsocket(intdomain,inttype,intprotocal)intdomain,//通信域AF_INET—internet域;AF_UNIX—UNIX域inttype,//指定socket的类型:SOCK_STREAM(流式套接字,TCP),SOCK_DGRAM(数据报套接字,UDP),SOCK_RAW(原始数据报套接字)intprotocol//指定网络协议,0表示由系统选择合适协议,默认TCP/IP协议返回值:成功---整型socket号sockfd,失败----1例子:socket(AF_INET,SOCK_STREAM,0)socket(AF_INET,SOCK_DGRAM,0)(2)bind():命名套接字---指定本地二元,绑定套接字号intbind(intsockfd,structsockaddr*my_addr,intaddrlen)intsockfd,//socket描述符structsockaddr*my_addr,//指向包含有本机IP地址及端口号等信息的sockaddr类型的指针intaddrlen,//sizeof(structsockaddr)返回值:成功----0;失败----0,SOCKET_ERROR错误作用:将套接字地址与套接字号关联----指点了三元组套接字标识例子:bind(18,my_addr,sizeof(structsockaddr))my_addr.sin_port=htonl(2222);//=0,系统随机设定1024~5000;自己设定,应选1024my_addr.sin_addr.s_addr=htonl(INADDR_ANY);//允许服务器应用进程侦听每个网络接口上的客户机请求.(3)listen():监听连接---服务程序监听连接请求,并进行排队,供accept进行后续处理.intlisten(intsockfd,intbacklog)intsockfd,//服务器通过该套接字侦听客户请求intbacklog//请求队列长度,超过长度,服务器拒绝连接请求返回值:0--成功,-1--失败(4)accept()允许服务器通过套接字接收一个连接请求—服务程序使用作用:从listen队列取出第一个连接请求,创建一新的套接字,准备提供并发服务.intaccept(ingsockfd,structsockaddr*addr,int*addrlen)intsockfd,//被监听的socket号,服务器从该套接字接收connect请求structsockaddr*addr,//存放提出连接请求服务的客户机套接字地址int*addrlen//客户机套接字地址addr长度,sizeof(sockaddr)返回值:若成功建立一个连接,返回的是一个新的socekt号,供新的连接使用;父进程则通过以前的套接字继续接收客户请求.-1--失败(5)connect():请求与远程套接字连接---客户程序使用intconnect(intsockfd,structsockaddr*serv_addr,intaddrlen)intsockfd,//本地套接字号structsockaddr*serv_addr,//serv_addr包含服务器IP地址和端口号地址结构的指针intaddrlen//serv_addr的长度,sizeof(sockaddr)返回:0---成功,-1---失败connect()与accept()建立一个全相关五元组(6)send():发送数据intsend(intsockfd,constvoid*msg,intlen,intflags)intsockfd,//已连接的用来传输数据的套接字号constvoid*msg,//指向要发送数据缓冲区的指针intlen,//以字节为单位的数据的长度intflags//指定传输控制方式,一般情况下置为0,MSG_OOB,(发送TCP紧急带外数据)返回值:实际发送的数据长度,可能少于len(7)接收数据(7)recv():接受数据intrecv(intsockfd,void*buf,intlen,unsignedintflags)intsockfd,//接受数据的套接字号void*buf,//存放接收数据的缓冲区指针intlen,//缓冲区的长度unsignedintflags//调用方式.一般情况下置为0,MSG_OOB:读取套接字上的紧急带外数据,MSG_PEEK:仅查看数据,不取出返回:0----连接被关闭,0接收的总字节数,0SOCKET_ERROR(8)sendto():UDP—发送数据intsendto(intsockfd,constvoid*msg,intlen,unsignedintflags,conststructsockaddr*to,inttolen)intsockfd,constvoid*msg,//指向要发送数据的指针intlen,//以字节为单位的数据的长度unsignedintflags,//flags一般情况下置为0conststructsockaddr*to,//存放目的机套接字地址inttolen//sizeof(sockaddr)返回值:实际发送的数据长度,可能少于len(9)recvfrom():UDP—接收数据intrecvfrom(intsockfd,void*buf,intlen,unsignedintflags,structsockaddr*from,int*fromlen)intsockfd,void*buf,//存放接收数据的缓冲区指针intlen,//缓冲区的长度unsignedintflags//flags一般情况下置为0structsockaddr*from,//存保发送来数据的源机的套接字地址int*fromlen//sizeof(formlen)返回值:收到的数据长度,如果=-1出错(10)关闭套接字intclose(intsockfd);//关闭指定的socket。返回:0--关闭成功,SOCKET_ERROR--错误(11)通知关闭套接字intshutdown(intsockfd,inthow)直接用close关闭套接字,可能会导致数据丢失.在close前,应调用shutdown发送给对方关闭通知,shutdown并不关闭套接字,套接字所占资源将保留到close套接字时.参数how可以设为下列值:0:不允许继续接收数据1:不允许继续发送数据2:不允许继续发送和接收数据返回值:成功---0,出错---SOCKET_ERROR(12)辅助socket函数:intgetsockname(intsockfg,structsockaddr*addr,int*addrlen)intgetpeername(intsockfd,structsockaddr*addr,int*addrlen);intgetsockopt(intsockfd,intlevel,intoptname,void*optval,int*optlen);intsetsockopt(intsockfd,intlevel,intoptname,constvoid*optval,intoptlen)unsignedlonginet_addr(constchar*strptr);intinet_aton(constchar*strptr,structin_addr*addrpt);char*inet_ntoa(structin_addrinaddr);intioctl(intfd,intrequest,…/*void*arg*/)intselect(intnumfds,fd_set*readfds,fd_set*writefds,fd_set*exceptfds,structtimeval*timeout);(13)域名与IP转换函数,服务与端口号转换函数。structhostent*gethostbyname(constchar*name);structhostent{char*h_name;//pagegrp1.sohu.comchar**h_aliases;//**h_addr_list;}structhostent*gethostbyaddr(constchar*addr,intlen,intfamily);intgethostname(char*name,intnamelen);第二部分:一个简单的客户端程序#includeiostream.h#includewinsock2.h#definePORT(u_short)1080#defineSERVER_ADDR202.96.1.144intmain(void){WSADATAData;SOCKETsServer;SOCKETsClient;charbuffer[MAXBUFLEN];intstatus;intret;SOCKADDR_INserverSockAddr;intaddrLen=sizeof(sockaddr_in);char*toSendtxt=TestString..;/*initializetheWindowsSocketDLL*/status=WSAStartup(MAKEWORD(2,2),&Data);if(status!=0){coutERROR:WSAStartupunsuccessfulendl;return1;}/*createasocket*/sClient=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);if(sClient==INVALID_SOCKET){coutERROR:socketunsuccessfulendl;status=WSACleanup();if(status==SOCKET_ERROR){coutERROR:WSACleanupunsuccessfulendl;return2;}return3;}serverSockAddr.sin_family=AF_INET;serverSockAddr.sin_port=htons(PORT);serverSockAddr.s