2024年10月recvfrom函数原型(使用recvfrom接收UDP包在Windows和Linux平台的不同表现)

 更新时间:2024-10-12

  ⑴recvfrom函数原型(使用recvfrom接收UDP包在Windows和Linux平台的不同表现

  ⑵使用recvfrom接收UDP包在Windows和Linux平台的不同表现

  ⑶操作系统的UDP接收流程如下:收到一个UDP包后,验证没有错误后,放入一个包队列中,队列中的每一个元素就是一个完整的UDP包。当应用程序通过recvfrom()读取时,OS把相应的一个完整UDP包取出,然后拷贝到用户提供的内存中,物理用户提供的内存大小是多少,OS都会完整取出一个UDP包。如果用户提供的内存小于这个UDP包的大小,那么在填充慢内存后,UDP包剩余的部分就会被丢弃,以后再也无法取回。这与TCP接收完全不同,TCP没有完整包的概念,也没有边界,OS只会取出用户要求的大小,剩余的仍然保留在OS中,下次还可以继续取出。socket编程虽然是事实上的标准,而且不同平台提供的接口函数也非常类似,但毕竟它不存在严格的标准。所以各个平台的实现也不完全兼容。下面就从recvfrom()这个函数看看Window平台和Linux平台的不同。Windows平台的表现intWSAAPIrecvfrom(_In_SOCKETs,_Out_writes_bytes_to_(len,return)__out_data_source(WORK)charFAR*buf,_In_intlen,_In_intflags,_Out_writes_bytes_to_opt_(*fromlen,*fromlen)structsockaddrFAR*from,_Inout_opt_intFAR*fromlen);再看MSDN说明:Ifthedatagramormessageislargerthanthebufferspecified,thebufferisfilledwiththefirstpartofthedatagram,andrecvfromgeneratestheerrorWSAEMSGSIZE.Forunreliableprotocols(forexample,UDP)theexcessdataislost.可以看出,buf大小小于UDP包大小的时候,recvfrom()会返回-,并设置错误WSAEMSGSIZE。实际编程测试验证确实是这样的表现。Linux平台的表现__extern_always_inlinessize_trecvfrom(int__fd,void*__restrict__buf,size_t__n,int__flags,__SOCKADDR_ARG__addr,socklen_t*__restrict__addr_len)可以看出与Windows平台的函数原型相同。但是在其man手册里,没有看到UDP包大于接收缓冲区情况的特殊说明。写代码测试表明,buf小于UDP包大小的时候,recvfrom()仍然返回复制到缓冲区的字节数,调用者无法得知UDP包被截断的情况。

  ⑷socket的常用函数

  ⑸函数原型:intsocket(intdomain,inttype,intprotocol);参数说明:domain:协议域,又称协议族(family。常用的协议族有AF_I、AF_I、AF_LOCAL(或称AF_UNIX,Unix域Socket、AF_ROUTE等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_I决定了要用ipv地址(位的与端口号(位的的组合、AF_UNIX决定了要用一个绝对路径名作为地址。type:指定Socket类型。常用的socket类型有SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等。流式Socket(SOCK_STREAM是一种面向连接的Socket,针对于面向连接的TCP服务应用。数据报式Socket(SOCK_DGRAM是一种无连接的Socket,对应于无连接的UDP服务应用。protocol:指定协议。常用协议有IPPROTO_TCP、IPPROTO_UDP、IPPROTO_STCP、IPPROTO_TIPC等,分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。注意:.type和protocol不可以随意组合,如SOCK_STREAM不可以跟IPPROTO_UDP组合。当第三个参数为时,会自动选择第二个参数类型对应的默认协议。.WindowsSocket下protocol参数中不存在IPPROTO_STCP返回值:如果调用成功就返回新创建的套接字的描述符,如果失败就返回INVALID_SOCKET(Linux下失败返回-。套接字描述符是一个整数类型的值。每个进程的进程空间里都有一个套接字描述符表,该表中存放着套接字描述符和套接字数据结构的对应关系。该表中有一个字段存放新创建的套接字的描述符,另一个字段存放套接字数据结构的地址,因此根据套接字描述符就可以找到其对应的套接字数据结构。每个进程在自己的进程空间里都有一个套接字描述符表但是套接字数据结构都是在操作系统的内核缓冲里。函数原型:intbind(SOCKETsocket,conststructsockaddr*address,socklen_taddress_len);参数说明:socket:是一个套接字描述符。address:是一个sockaddr结构指针,该结构中包含了要结合的地址和端口号。address_len:确定address缓冲区的长度。返回值:如果函数执行成功,返回值为,否则为SOCKET_ERROR。函数原型:intrecv(SOCKETsocket,charFAR*buf,intlen,intflags);参数说明:socket:一个标识已连接套接口的描述字。buf:用于接收数据的缓冲区。len:缓冲区长度。flags:指定调用方式。取值:MSG_PEEK查看当前数据,数据将被复制到缓冲区中,但并不从输入队列中删除;MSG_OOB处理带外数据。返回值:若无错误发生,recv()返回读入的字节数。如果连接已中止,返回。否则的话,返回SOCKET_ERROR错误,应用程序可通过WSAGetLastError()获取相应错误代码。函数原型:ssize_trecvfrom(intsockfd,voidbuf,intlen,unsignedintflags,structsocketaddr*from,socket_t*fromlen);参数说明:sockfd:标识一个已连接套接口的描述字。buf:接收数据缓冲区。len:缓冲区长度。flags:调用操作方式。是以下一个或者多个标志的组合体,可通过or操作连在一起:(MSG_DONTWAIT:操作不会被阻塞;(MSG_ERRQUEUE:指示应该从套接字的错误队列上接收错误值,依据不同的协议,错误值以某种辅佐性消息的方式传递进来,使用者应该提供足够大的缓冲区。导致错误的原封包通过msg_iovec作为一般的数据来传递。导致错误的数据报原目标地址作为msg_name被提供。错误以sock_extended_err结构形态被使用。(MSG_PEEK:指示数据接收后,在接收队列中保留原数据,不将其删除,随后的读操作还可以接收相同的数据。(MSG_TRUNC:返回封包的实际长度,即使它比所提供的缓冲区更长,只对packet套接字有效。(MSG_WAITALL:要求阻塞操作,直到请求得到完整的满足。然而,如果捕捉到信号,错误或者连接断开发生,或者下次被接收的数据类型不同,仍会返回少于请求量的数据。(MSG_EOR:指示记录的结束,返回的数据完成一个记录。(MSG_TRUNC:指明数据报尾部数据已被丢弃,因为它比所提供的缓冲区需要更多的空间。/*(MSG_TRUNC使用错误,才是MSG_TRUNC的正确解释)*/(MSG_CTRUNC:指明由于缓冲区空间不足,一些控制数据已被丢弃。(MSG_OOB:指示接收到out-of-band数据(即需要优先处理的数据)。(MSG_ERRQUEUE:指示除了来自套接字错误队列的错误外,没有接收到其它数据。from:(可选指针,指向装有源地址的缓冲区。fromlen:(可选指针,指向from缓冲区长度值。函数原型:intsendto(SOCKETs,constcharFAR*buf,intsize,intflags,conststructsockaddrFAR*to,inttolen);参数说明:s:套接字buf:待发送数据的缓冲区size:缓冲区长度flags:调用方式标志位,一般为,改变Flags,将会改变Sendto发送的形式addr:(可选指针,指向目的套接字的地址tolen:addr所指地址的长度返回值:如果成功,则返回发送的字节数,失败则返回SOCKET_ERROR。函数原型:intaept(intfd,structsocketaddr*addr,socklen_t*len);参数说明:fd:套接字描述符。addr:返回连接着的地址len:接收返回地址的缓冲区长度返回值:成功返回客户端的文件描述符,失败返回-。

  ⑹怎样让send函数,recv函数发送多于字节的数据

  ⑺一般情况下:send(),recv()用于TCP,sen一般情况下:send(),recv()用于TCP,sendto()及recvfrom(用于UDP但是send(),recv()也可以用于UDP,sendto()及recvfrom()也可以用于TCPsend函数intsend(SOCKETs,constcharFAR*buf,intlen,intflags);不论是客户还是服务器应用程序都用send函数来向TCP连接的另一端发送数据。客户程序一般用send函数向服务器发送请求,而服务器则通常用send函数来向客户程序发送应答。该函数的第一个参数指定发送端套接字描述符;第二个参数指明一个存放应用程序要发送数据的缓冲区;第三个参数指明实际要发送的数据的字节数;第四个参数一般置。这里只描述同步Socket的send函数的执行流程。当调用该函数时,send先比较待发送数据的长度len和套接字s的发送缓冲的长度,如果len大于s的发送缓冲区的长度,该函数返回SOCKET_ERROR;如果len小于或者等于s的发送缓冲区的长度,那么send先检查协议是否正在发送s的发送缓冲中的数据,如果是就等待协议把数据发送完,如果协议还没有开始发送s的发送缓冲中的数据或者s的发送缓冲中没有数据,那么send就比较s的发送缓冲区的剩余空间和len,如果len大于剩余空间大小send就一直等待协议把s的发送缓冲中的数据发送完,如果len小于剩余空间大小send就仅仅把buf中的数据copy到剩余空间里(注意并不是send把s的发送缓冲中的数据传到连接的另一端的,而是协议传的,send仅仅是把buf中的数据copy到s的发送缓冲区的剩余空间里。如果send函数copy数据成功,就返回实际copy的字节数,如果send在copy数据时出现错误,那么send就返回SOCKET_ERROR;如果send在等待协议传送数据时网络断开的话,那么send函数也返回SOCKET_ERROR。要注意send函数把buf中的数据成功copy到s的发送缓冲的剩余空间里后它就返回了,但是此时这些数据并不一定马上被传到连接的另一端。如果协议在后续的传送过程中出现网络错误的话,那么下一个Socket函数就会返回SOCKET_ERROR。(每一个除send外的Socket函数在执行的最开始总要先等待套接字的发送缓冲中的数据被协议传送完毕才能继续,如果在等待时出现网络错误,那么该Socket函数就返回SOCKET_ERROR注意:在Unix系统下,如果send在等待协议传送数据时网络断开的话,调用send的进程会接收到一个SIGPIPE信号,进程对该信号的默认处理是进程终止。recv函数intrecv(SOCKETs,charFAR*buf,intlen,intflags);不论是客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据。该函数的第一个参数指定接收端套接字描述符;第二个参数指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据;第三个参数指明buf的长度;第四个参数一般置。这里只描述同步Socket的recv函数的执行流程。当应用程序调用recv函数时,recv先等待s的发送缓冲中的数据被协议传送完毕,如果协议在传送s的发送缓冲中的数据时出现网络错误,那么recv函数返回SOCKET_ERROR,如果s的发送缓冲中没有数据或者数据被协议成功发送完毕后,recv先检查套接字s的接收缓冲区,如果s接收缓冲区中没有数据或者协议正在接收数据,那么recv就一直等待,只到协议把数据接收完毕。当协议把数据接收完毕,recv函数就把s的接收缓冲中的数据copy到buf中(注意协议接收到的数据可能大于buf的长度,所以在这种情况下要调用几次recv函数才能把s的接收缓冲中的数据copy完。recv函数仅仅是copy数据,真正的接收数据是协议来完成的,recv函数返回其实际copy的字节数。如果recv在copy时出错,那么它返回SOCKET_ERROR;如果recv函数在等待协议接收数据时网络中断了,那么它返回。注意:在Unix系统下,如果recv函数在等待协议接收数据时网络断开了,那么调用recv的进程会接收到一个SIGPIPE信号,进程对该信号的默认处理是进程终止。sendto和recvfrom一般用于UDP协议中,但是如果在TCP中connect函数调用后也可以用.sendto(和recvfrom(——利用数据报方式进行数据传输在无连接的数据报socket方式下,由于本地socket并没有与远端机器建立连接,所以在发送数据时应指明目的地址,sendto(函数原型为:intsendto(intsockfd,constvoid*msg,intlenunsignedintflags,conststructsockaddr*to,inttolen;该函数比send(函数多了两个参数,to表示目地机的IP地址和端口号信息,而tolen常常被赋值为sizeof(structsockaddr。Sendto函数也返回实际发送的数据字节长度或在出现发送错误时返回-。recvfrom(函数原型为:intrecvfrom(intsockfd,void*buf,intlen,unsignedintlags,structsockaddr*from,int*fromlen;from是一个structsockaddr类型的变量,该变量保存源机的IP地址及端口号。fromlen常置为sizeof(structsockaddr。当recvfrom(返回时,fromlen包含实际存入from中的数据字节数。Recvfrom(函数返回接收到的字节数或当出现错误时返回-,并置相应的errno。应注意的一点是,当你对于数据报socket调用了connect(函数时,你也可以利用send(和recv(进行数据传输,但该socket仍然是数据报socket,并且利用传输层的UDP服务。但在发送或接收数据报时,内核会自动为之加上目地和源地址信息。dto()及recvfrom(用于UDP但是send(),recv()也可以用于UDP,sendto()及recvfrom()也可以用于TCPsend函数intsend(SOCKETs,constcharFAR*buf,intlen,intflags);不论是客户还是服务器应用程序都用send函数来向TCP连接的另一端发送数据。客户程序一般用send函数向服务器发送请求,而服务器则通常用send函数来向客户程序发送应答。该函数的第一个参数指定发送端套接字描述符;第二个参数指明一个存放应用程序要发送数据的缓冲区;第三个参数指明实际要发送的数据的字节数;第四个参数一般置。这里只描述同步Socket的send函数的执行流程。当调用该函数时,send先比较待发送数据的长度len和套接字s的发送缓冲的长度,如果len大于s的发送缓冲区的长度,该函数返回SOCKET_ERROR;如果len小于或者等于s的发送缓冲区的长度,那么send先检查协议是否正在发送s的发送缓冲中的数据,如果是就等待协议把数据发送完,如果协议还没有开始发送s的发送缓冲中的数据或者s的发送缓冲中没有数据,那么send就比较s的发送缓冲区的剩余空间和len,如果len大于剩余空间大小send就一直等待协议把s的发送缓冲中的数据发送完,如果len小于剩余空间大小send就仅仅把buf中的数据copy到剩余空间里(注意并不是send把s的发送缓冲中的数据传到连接的另一端的,而是协议传的,send仅仅是把buf中的数据copy到s的发送缓冲区的剩余空间里。如果send函数copy数据成功,就返回实际copy的字节数,如果send在copy数据时出现错误,那么send就返回SOCKET_ERROR;如果send在等待协议传送数据时网络断开的话,那么send函数也返回SOCKET_ERROR。要注意send函数把buf中的数据成功copy到s的发送缓冲的剩余空间里后它就返回了,但是此时这些数据并不一定马上被传到连接的另一端。如果协议在后续的传送过程中出现网络错误的话,那么下一个Socket函数就会返回SOCKET_ERROR。(每一个除send外的Socket函数在执行的最开始总要先等待套接字的发送缓冲中的数据被协议传送完毕才能继续,如果在等待时出现网络错误,那么该Socket函数就返回SOCKET_ERROR注意:在Unix系统下,如果send在等待协议传送数据时网络断开的话,调用send的进程会接收到一个SIGPIPE信号,进程对该信号的默认处理是进程终止。recv函数intrecv(SOCKETs,charFAR*buf,intlen,intflags);不论是客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据。该函数的第一个参数指定接收端套接字描述符;第二个参数指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据;第三个参数指明buf的长度;第四个参数一般置。这里只描述同步Socket的recv函数的执行流程。当应用程序调用recv函数时,recv先等待s的发送缓冲中的数据被协议传送完毕,如果协议在传送s的发送缓冲中的数据时出现网络错误,那么recv函数返回SOCKET_ERROR,如果s的发送缓冲中没有数据或者数据被协议成功发送完毕后,recv先检查套接字s的接收缓冲区,如果s接收缓冲区中没有数据或者协议正在接收数据,那么recv就一直等待,只到协议把数据接收完毕。当协议把数据接收完毕,recv函数就把s的接收缓冲中的数据copy到buf中(注意协议接收到的数据可能大于buf的长度,所以在这种情况下要调用几次recv函数才能把s的接收缓冲中的数据copy完。recv函数仅仅是copy数据,真正的接收数据是协议来完成的,recv函数返回其实际copy的字节数。如果recv在copy时出错,那么它返回SOCKET_ERROR;如果recv函数在等待协议接收数据时网络中断了,那么它返回。注意:在Unix系统下,如果recv函数在等待协议接收数据时网络断开了,那么调用recv的进程会接收到一个SIGPIPE信号,进程对该信号的默认处理是进程终止。sendto和recvfrom一般用于UDP协议中,但是如果在TCP中connect函数调用后也可以用.sendto(和recvfrom(——利用数据报方式进行数据传输在无连接的数据报socket方式下,由于本地socket并没有与远端机器建立连接,所以在发送数据时应指明目的地址,sendto(函数原型为:intsendto(intsockfd,constvoid*msg,intlenunsignedintflags,conststructsockaddr*to,inttolen;该函数比send(函数多了两个参数,to表示目地机的IP地址和端口号信息,而tolen常常被赋值为sizeof(structsockaddr。Sendto函数也返回实际发送的数据字节长度或在出现发送错误时返回-。recvfrom(函数原型为:intrecvfrom(intsockfd,void*buf,intlen,unsignedintlags,structsockaddr*from,int*fromlen;from是一个structsockaddr类型的变量,该变量保存源机的IP地址及端口号。fromlen常置为sizeof(structsockaddr。当recvfrom(返回时,fromlen包含实际存入from中的数据字节数。Recvfrom(函数返回接收到的字节数或当出现错误时返回-,并置相应的errno。应注意的一点是,当你对于数据报socket调用了connect(函数时,你也可以利用send(和recv(进行数据传输,但该socket仍然是数据报socket,并且利用传输层的UDP服务。但在发送或接收数据报时,内核会自动为之加上目地和源地址信息。

  ⑻UnixSocket-核心函数

  ⑼本章描述了编写完整的TCP客户端和服务器所需的核心套接字函数。下图显示了完整的客户端和服务器交互要执行网络I/O,进程必须做的第一件事是,调用socket函数,指定所需的通信协议类型和协议族,等等。这个调用返回一个套接字描述符,您可以在以后的系统调用中使用该描述符,或者在出错时返回-。Parametersfamily??它指定协议族,是如下所示的常量之一AF_I:IPvprotocolsAF_I:?IPvprotocolsAF_LOCAL:?UnixdomainprotocolsAF_ROUTE:?RoutingSocketsAF_KEY:?Ketsocket本章不涉及除IPv以外的其他协议。type-?它指定您想要的套接字类型。它可以取以下值之一SOCK_STREAM:?StreamsocketSOCK_DGRAM:?DatagramsocketSOCK_SEQPACKET:?SequencedpacketsocketSOCK_RAW:?Rawsocketprotocol-?参数应该设置为下面给出的特定协议类型,或者来为给定的family和type组合选择系统的默认值IPPROTO_TCP:?TCPtransportprotocolIPPROTO_UDP:?UDPtransportprotocolIPPROTO_SCTP:?SCTPtransportprotocol连接功能用于TCP客户端与TCP服务器建立连接如果成功连接到服务器,则返回,否则返回-。Parameterssockfd??它是套接字函数返回的套接字描述符。serv_addr??它是一个指向structsockaddr的指针,其中包含了目的IP地址和端口。addrlen??设置为sizeof(structsockaddr)。The?bind?Functionbind函数为套接字分配一个本地协议地址。在互联网协议中,协议地址是位IPv地址或位IPv地址,以及位TCP或UDP端口号的组合。此函数仅由TCP服务器调用。如果成功绑定到地址,则返回,否则返回-。Parameters???sockfd??它是套接字函数返回的套接字描述符。???my_addr??它是一个指向structsockaddr的指针,其中包含本地IP地址和端口。???addrlen??设置大小为sizeof(structsockaddr).您可以自动输入您的IP地址和端口端口号的值为表示系统将随机选择一个端口,IP地址的值为INADDR_ANY表示服务器的IP地址将自动分配。注意:所有以下的端口都保留。您可以将端口设置为以上,以下,除非它们被其他程序使用。The?listen?Functionlisten函数只由TCP服务器调用,它执行两个操作???-listen函数将一个未连接的套接字转换为被动套接字,表明内核应该接受指向该套接字的传入连接请求。??-这个函数的第二个参数指定内核应该为这个套接字队列的最大连接数。如果调用成功,则返回,否则返回-。Parameters???sockfd??它是套接字函数返回的套接字描述符。???backlog??它是允许的连接数。TCP服务器调用aept函数,从已完成的连接队列的前端返回下一个已完成的连接。呼叫的签名如下?如果调用成功,则返回一个非负描述符,否则返回-。返回的描述符被假定为客户端套接字描述符,所有的读写操作都将在这个描述符上完成,以与客户端通信。Parameters???sockfd??它是套接字函数返回的套接字描述符。???cliaddr??它是一个指向sockaddr结构体的指针,其中包含客户端IP地址和端口。???addrlen??设置大小为sizeof(structsockaddr)。send函数用于通过流套接字或连接的数据报套接字发送数据。如果要在未连接的数据报套接字上发送数据,必须使用sendto()函数。您可以使用write()系统调用来发送数据。如下intsend(intsockfd,constvoid*msg,intlen,intflags);这个调用返回发送的字节数,否则它将在出错时返回-。Parameters???sockfd??它是套接字函数返回的套接字描述符。???msg??它是一个指针,指向您想要发送的数据。???len??它是您想要发送的数据长度(以字节为单位)。???flags??它被设置为。recv函数用于通过流套接字或连接的数据报套接字接收数据。如果想通过未连接的数据报套接字接收数据,必须使用recvfrom()。可以使用read()系统调用读取数据。这个调用在帮助函数一章中有解释。intrecv(intsockfd,void*buf,intlen,unsignedintflags);这个调用返回读入缓冲区的字节数,否则它将在出错时返回-。Parameters???sockfd??它是套接字函数返回的套接字描述符。???buf??它是读取信息的缓冲区。???len??它是缓冲区的最大长度。???flags??它被设置为。sendto函数用于在未连接的数据报套接字上发送数据。签名如下intsendto(intsockfd,constvoid*msg,intlen,unsignedintflags,conststructsockaddr*to,inttolen);这个调用返回发送的字节数,否则它返回-错误。Parameters???sockfd??它是套接字函数返回的套接字描述符。???msg??它是一个指针,指向您想要发送的数据。???len??它是您想要发送的数据长度(以字节为单位)。???flags??它被设置为。???to??它是一个指向structsockaddr的指针,用于发送数据的主机。???tolen??它设置为sizeof(structsockaddr)。recvfrom函数用于从未连接的数据报套接字接收数据。intrecvfrom(intsockfd,void*buf,intlen,unsignedintflagsstructsockaddr*from,int*fromlen);这个调用返回读入缓冲区的字节数,否则返回-。Parameters???sockfd??它是套接字函数返回的套接字描述符。???buf???它是读取信息的缓冲区。???len??它是缓冲区的最大长度。???flags??它被设置为。???from??它是一个指向structsockaddr的指针,用于读取数据的主机。???fromlen??它设置为sizeof(structsockaddr)。关闭功能用于关闭客户端和服务器之间的通信。其语法为intclose(intsockfd);如果调用成功,则返回,否则返回-。Parameters???sockfd??它是套接字函数返回的套接字描述符。shutdown功能用于优雅地关闭客户端和服务器之间的通信。与close函数相比,这个函数提供了更多的控制。下面给出了shutdown的语法intshutdown(intsockfd,inthow);如果调用成功,则返回,否则返回-。Parameters???sockfd??它是套接字函数返回的套接字描述符。???how??下面其中一个?????????表示不允许接收?????????表示不允许发送?????????表示发送和接收都不允许。当how设置为时,它和close()是一样的。select函数指示指定的文件描述符中哪些可以读,哪些可以写,或者有一个等待的错误条件。当应用程序调用recv或recvfrom时,它将被阻塞,直到该套接字的数据到达。当传入的数据流为空时,应用程序可以进行其他有用的处理。另一种情况是应用程序从多个套接字接收数据。在输入队列中没有数据的套接字上调用recv或recvfrom会阻止从其他套接字上立即接收数据。select函数调用通过允许程序轮询所有套接字句柄来解决这个问题,以查看它们是否可用于非阻塞的读写操作。下面给出select的语法?intselect(int?nfds,fd_set?*readfds,fd_set?*writefds,fd_set*errorfds,structtimeval*timeout);如果调用成功,则返回,否则返回-。Parameters???nfds??它指定要测试的文件描述符的范围。select()函数测试范围为到nfds-的文件描述符???readfds??它指向一个fd_set类型的对象,该对象在输入时指定要检查的文件描述符是否准备读取,在输出时指定哪些文件描述符准备读取。它可以为NULL,表示为空集。???writefds??它指向一个fd_set类型的对象,该对象在输入时指定要检查的文件描述符是否准备写入,在输出时指定哪些文件描述符准备写入。它可以为NULL,表示为空集。???exceptfds??它指向一个fd_set类型的对象,该对象在输入时指定要检查的文件描述符是否有错误条件等待处理,在输出时指定哪些文件描述符有错误条件等待处理。它可以为NULL,表示为空集。???timeout??它指向一个timeval结构体,该结构体指定select调用应该为一个可用的I/O操作轮询描述符多长时间。如果超时值为,则select将立即返回。如果timeout参数为NULL,则select将阻塞,直到至少有一个文件/套接字句柄为可用的I/O操作准备好为止。否则,select将在超时时间已经过去或至少有一个文件/套接字描述符准备好进行I/O操作之后返回。select的返回值是文件描述符集中指定的准备好进行I/O的句柄数。如果达到timeout字段指定的时间限制,则选择返回。以下宏用于操作文件描述符集????FD_CLR(fd,&fdset)??清除文件描述符集fdset中文件描述符fd的位。???FD_ISSET(fd,&fdset)??如果文件描述符fd的位设置在fdset所指向的文件描述符集合中,则返回一个非零值,否则返回。???FD_SET(fd,&fdset)??在文件描述符集合fdset中设置文件描述符fd的位。???FD_ZERO(&fdset)??初始化文件描述符集fdset,使所有文件描述符的位都为零。如果fd参数小于或大于等于FD_SETSIZE,这些宏的行为是未定义的。Example

  ⑽udp的recvfrom函数,能接收指定ip和端口发送来的数据吗

  ⑾不能,他的参数是用来存储发送数据的socket的。可以在接收到数据以后进行判断,如果是需要的IP则采用数据,否则丢弃数据。

  ⑿recvfrom()的与recv()函数的比较

  ⒀UDP使用recvfrom()函数接收数据,他类似于标准的read(),但是在recvfrom()函数中要指明目的地址。从套接字上接收一个消息。对于recvfrom,可同时应用于面向连接的和无连接的套接字。recv一般只用在面向连接的套接字,几乎等同于recvfrom,只要将recvfrom的第五个参数设置NULL。不管是recv还是recvfrom,都有两种模式,阻塞和非阻塞,可以通过ioctl函数来设置。阻塞模式是一直等待直到有数据到达,非阻塞模式是立即返回,需要通过消息,异步事件等来查询完成状态。

  ⒁网络字节顺序和机器顺序什么区别

  ⒂存在两种字节顺序:NBO与HBO网络字节顺序NBO(workByteOrder:按从高到低的顺序存储,在网络上使用统一的网络字节顺序,可以避免兼容性问题。主机字节顺序(HBO,HostByteOrder:不同的机器HBO不相同,与CPU设计有关计算机数据存储有两种字节优先顺序:高位字节优先和低位字节优先。Inter上数据以高位字节优先顺序在网络上传输,所以对于在内部是以低位字节优先方式存储数据的机器,在Inter上传输数据时就需要进行转换。我们要讨论的第一个结构类型是:structsockaddr,该类型是用来保存socket信息的:structsockaddr{unsignedshortsa_family;/*地址族,AF_xxx*/charsa_data;/*字节的协议地址*/};sa_family一般为AF_I;sa_data则包含该socket的IP地址和端口号。另外还有一种结构类型:structsockaddr_in{shortintsin_family;/*地址族*/unsignedshortintsin_port;/*端口号*/structin_addrsin_addr;/*IP地址*/unsignedcharsin_zero;/*填充以保持与structsockaddr同样大小*/};这个结构使用更为方便。sin_zero(它用来将sockaddr_in结构填充到与structsockaddr同样的长度)应该用bzero()或memset()函数将其置为零。指向sockaddr_in的指针和指向sockaddr的指针可以相互转换,这意味着如果一个函数所需参数类型是sockaddr时,你可以在函数调用的时候将一个指向sockaddr_in的指针转换为指向sockaddr的指针;或者相反。sin_family通常被赋AF_I;sin_port和sin_addr应该转换成为网络字节优先顺序;而sin_addr则不需要转换。我们下面讨论几个字节顺序转换函数:htons()--“HosttoworkShort“;htonl()--“HosttoworkLong“ntohs()--“worktoHostShort“;ntohl()--“worktoHostLong“在这里,h表示“host“,n表示“work“,s表示“short“,l表示“long“。打开socket描述符、建立绑定并建立连接socket函数原型为:intsocket(intdomain,inttype,intprotocol);domain参数指定socket的类型:SOCK_STREAM或SOCK_DGRAM;protocol通常赋值“”。Socket()调用返回一个整型socket描述符,你可以在后面的调用使用它。一旦通过socket调用返回一个socket描述符,你应该将该socket与你本机上的一个端口相关联(往往当你在设计服务器端程序时需要调用该函数。随后你就可以在该端口监听服务请求;而客户端一般无须调用该函数。Bind函数原型为:intbind(intsockfd,structsockaddr*my_addr,intaddrlen);Sockfd是一个socket描述符,my_addr是一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针;addrlen常被设置为sizeof(structsockaddr)。最后,对于bind函数要说明的一点是,你可以用下面的赋值实现自动获得本机IP地址和随机获取一个没有被占用的端口号:my_addr.sin_port=;/*系统随机选择一个未被使用的端口号*/my_addr.sin_addr.s_addr=INADDR_ANY;/*填入本机IP地址*/通过将my_addr.sin_port置为,函数会自动为你选择一个未占用的端口来使用。同样,通过将my_addr.sin_addr.s_addr置为INADDR_ANY,系统会自动填入本机IP地址。Bind()函数在成功被调用时返回;遇到错误时返回“-”并将errno置为相应的错误号。另外要注意的是,当调用函数时,一般不要将端口号置为小于的值,因为~是保留端口号,你可以使用大于中任何一个没有被占用的端口号。Connect()函数用来与远端服务器建立一个TCP连接,其函数原型为:intconnect(intsockfd,structsockaddr*serv_addr,intaddrlen);Sockfd是目的服务器的sockt描述符;serv_addr是包含目的机IP地址和端口号的指针。遇到错误时返回-,并且errno中包含相应的错误码。进行客户端程序设计无须调用bind(),因为这种情况下只需知道目的机器的IP地址,而客户通过哪个端口与服务器建立连接并不需要关心,内核会自动选择一个未被占用的端口供客户端来使用。Listen()——监听是否有服务请求在服务器端程序中,当socket与某一端口捆绑以后,就需要监听该端口,以便对到达的服务请求加以处理。intlisten(intsockfd,intbacklog);Sockfd是Socket系统调用返回的socket描述符;backlog指定在请求队列中允许的最大请求数,进入的连接请求将在队列中等待aept()它们(参考下文。Backlog对队列中等待服务的请求的数目进行了限制,大多数系统缺省值为。当listen遇到错误时返回-,errno被置为相应的错误码。故服务器端程序通常按下列顺序进行函数调用:socket();bind();listen();/*aept()goeshere*/aept()——连接端口的服务请求。当某个客户端试图与服务器监听的端口连接时,该连接请求将排队等待服务器aept()它。通过调用aept()函数为其建立一个连接,aept()函数将返回一个新的socket描述符,来供这个新连接来使用。而服务器可以继续在以前的那个socket上监听,同时可以在新的socket描述符上进行数据send()(发送和recv()(接收操作:intaept(intsockfd,void*addr,int*addrlen);sockfd是被监听的socket描述符,addr通常是一个指向sockaddr_in变量的指针,该变量用来存放提出连接请求服务的主机的信息(某台主机从某个端口发出该请求;addrten通常为一个指向值为sizeof(structsockaddr_in)的整型指针变量。错误发生时返回一个-并且设置相应的errno值。Send()和recv()——数据传输这两个函数是用于面向连接的socket上进行数据传输。Send()函数原型为:intsend(intsockfd,constvoid*msg,intlen,intflags);Sockfd是你想用来传输数据的socket描述符,msg是一个指向要发送数据的指针。Len是以字节为单位的数据的长度。flags一般情况下置为(关于该参数的用法可参照man手册。char*msg=“Beejwashere!“;intlen,bytes_sent;......len=strlen(msg);bytes_sent=send(sockfd,msg,len,);......Send()函数返回实际上发送出的字节数,可能会少于你希望发送的数据。所以需要对send()的返回值进行测量。当send()返回值与len不匹配时,应该对这种情况进行处理。recv()函数原型为:intrecv(intsockfd,void*buf,intlen,unsignedintflags);Sockfd是接受数据的socket描述符;buf是存放接收数据的缓冲区;len是缓冲的长度。Flags也被置为。Recv()返回实际上接收的字节数,或当出现错误时,返回-并置相应的errno值。Sendto()和recvfrom()——利用数据报方式进行数据传输在无连接的数据报socket方式下,由于本地socket并没有与远端机器建立连接,所以在发送数据时应指明目的地址,sendto()函数原型为:intsendto(intsockfd,constvoid*msg,intlen,unsignedintflags,conststructsockaddr*to,inttolen);该函数比send()函数多了两个参数,to表示目地机的IP地址和端口号信息,而tolen常常被赋值为sizeof(structsockaddr)。Sendto函数也返回实际发送的数据字节长度或在出现发送错误时返回-。Recvfrom()函数原型为:intrecvfrom(intsockfd,void*buf,intlen,unsignedintflags,structsockaddr*from,int*fromlen);from是一个structsockaddr类型的变量,该变量保存源机的IP地址及端口号。fromlen常置为sizeof(structsockaddr)。当recvfrom()返回时,fromlen包含实际存入from中的数据字节数。Recvfrom()函数返回接收到的字节数或当出现错误时返回-,并置相应的errno。应注意的一点是,当你对于数据报socket调用了connect()函数时,你也可以利用send()和recv()进行数据传输,但该socket仍然是数据报socket,并且利用传输层的UDP服务。但在发送或接收数据报时,内核会自动为之加上目地和源地址信息。Close()和shutdown()——结束数据传输当所有的数据操作结束以后,你可以调用close()函数来释放该socket,从而停止在该socket上的任何数据操作:close(sockfd);你也可以调用shutdown()函数来关闭该socket。该函数允许你只停止在某个方向上的数据传输,而一个方向上的数据传输继续进行。如你可以关闭某socket的写操作而允许继续在该socket上接受数据,直至读入所有数据。intshutdown(intsockfd,inthow);Sockfd的含义是显而易见的,而参数how可以设为下列值:·-------不允许继续接收数据·-------不允许继续发送数据·-------不允许继续发送和接收数据,均为允许则调用close()shutdown在操作成功时返回,在出现错误时返回-(并置相应errno。DNS——域名服务相关函数由于IP地址难以记忆和读写,所以为了读写记忆方便,人们常常用域名来表示主机,这就需要进行域名和IP地址的转换。函数gethostbyname()就是完成这种转换的,函数原型为:structhostent*gethostbyname(constchar*name);函数返回一种名为hosten的结构类型,它的定义如下:structhostent{char*h_name;/*主机的官方域名*/char**h_aliases;/*一个以NULL结尾的主机别名数组*/inth_addrtype;/*返回的地址类型,在Inter环境下为AF-I*/inth_length;/*地址的字节长度*/char**h_addr_list;/*一个以结尾的数组,包含该主机的所有地址*/};#defineh_addrh_addr_list/*在h-addr-list中的第一个地址*/、将主机的unsignedlong值转换为网络字节顺序(位):为什么要这样做呢?因为不同的计算机使用不同的字节顺序存储数据。因此任何从Winsock函数对IP地址和端口号的引用和传给Winsock函数的IP地址和端口号均时按照网络顺序组织的。&《;&《;&《;&《;&《;u_long&《;htonl(u_longhostlong);&《;&《;&《;&《;&《;举例:htonl()=&《;&《;&《;&《;&《;htonl()=、将unsignedlong数从网络字节顺序转换位主机字节顺序,是上面函数的逆函数。&《;&《;&《;&《;&《;&《;u_long&《;ntohl(u_longlong);&《;&《;&《;&《;&《;举例:ntohl()=&《;&《;&《;&《;&《;ntohl()==***、将主机的unsignedshort值转换为网络字节顺序(位):原因同:&《;&《;&《;&《;&《;&《;u_short&《;htons(u_shorthostshort);&《;&《;&《;&《;&《;举例:htonl()=&《;&《;&《;&《;&《;htonl()=、将unsignedshort数从网络字节顺序转换位主机字节顺序,是上面函数的逆函数。&《;&《;&《;&《;&《;&《;u_short&《;ntohs(u_shortshort);&《;&《;&《;&《;&《;举例:ntohs()=&《;&《;&《;&《;&《;ntohsl()==-*(大小端地址转换****不同的CPU有不同的字节序类型这些字节序是指整数在内存中保存的顺序这个叫做主机序最常见的有两种.Littleendian:将低序字节存储在起始地址.Bigendian:将高序字节存储在起始地址LElittle-endian最符合人的思维的字节序地址低位存储值的低位地址高位存储值的高位怎么讲是最符合人的思维的字节序,是因为从人的第一观感来说低位值小,就应该放在内存地址小的地方,也即内存地址低位反之,高位值就应该放在内存地址大的地方,也即内存地址高位BEbig-endian最直观的字节序地址低位存储值的高位地址高位存储值的低位为什么说直观,不要考虑对应关系只需要把内存地址从左到右按照由低到高的顺序写出把值按照通常的高位到低位的顺序写出两者对照,一个字节一个字节的填充进去

  ⒃vc++网络编程recvfrom函数问题

  ⒄INADDR_ANY是表示地址吧,表示绑定本地所有的ip地址如果没有指定端口号的话(端口号设置为),系统会自动分配一个sendto必须要指定端口号的,因为ip:port才是网络服务的惟一标识一般客户端的话可以让系统自动分配端口,服务端得话就必须指定端口UDP协议两边都要用指定的端口号,不然消息不知道发送到哪里去到网上百度一下。值得信赖.//::

  ⒅recvfrom函数

  ⒆recvfrom函数用于从(已连接套接口上接收数据,并捕获数据发送源的地址。本函数用于从(已连接套接口上接收数据,并捕获数据发送源的地址。对于SOCK_STREAM类型的套接口,最多可接收缓冲区大小个数据。如果套接口被设置为线内接收带外数据(选项为SO_OOBINLINE,且有带外数据未读入,则返回带外数据。应用程序可通过调用ioctlsocket()的SOCATMARK命令来确定是否有带外数据待读入。对于SOCK_STREAM类型套接口,忽略from和fromlen参数。对于数据报类套接口,队列中第一个数据报中的数据被解包,但最多不超过缓冲区的大小。如果数据报大于缓冲区,那么缓冲区中只有数据报的前面部分,其他的数据都丢失了,并且recvfrom()函数返回WSAEMSGSIZE错误。若from非零,且套接口为SOCK_DGRAM类型,则发送数据源的地址被复制到相应的sockaddr结构中。fromlen所指向的值初始化时为这个结构的大小,当调用返回时按实际地址所占的空间进行修改。如果没有数据待读,那么除非是非阻塞模式,不然的话套接口将一直等待数据的到来,此时将返回SOCKET_ERROR错误,错误代码是WSAEWOULDBLOCK。用select()或WSAAsynSelect()可以获知何时数据到达。如果套接口为SOCK_STREAM类型,并且远端“优雅”地中止了连接,那么recvfrom()一个数据也不读取,立即返回。如果立即被强制中止,那么recv()将以WSAECONNRESET错误失败返回。

  ⒇vc++网络编程recvfrom函数问题

  ⒈既然把分给了我就应该帮你解决的,这是一个简单的聊天室,测试后可以。你看下源代码好了。服务器端程序:,创建套接字(socket)。,将套接字绑定到本地地址和端口上(bind)。,等待接受数据(recvfrom。,关闭套接字。#include《iostream.h》#include《stdio.h》#include《Winsock.h》//必须加载套接字的头文件,还必须在工程的链接处添加Ws_.libintmain(){WORDwVersionRequested;WSADATAwsaData;interr;//请求套接字版本wVersionRequested=MAKEWORD(,);//用MAKEWORD宏请求.版本的Winsock库err=WSAStartup(wVersionRequested,&wsaData);//加载套字节,确定使用版本if(err!=){return;}if(LOBYTE(wsaData.wVersion)!=||HIBYTE(wsaData.wVersion)!=)//低字节和高字节是不是{WSACleanup();//终止对Winsock库的使用return;}//创建套接字SOCKETsock=socket(AF_I,SOCK_DGRAM,);//定义一个sock用来接受返回的套接字//定义一个地址结构体SOCKADDR_INip;ip.sin_addr.S_un.S_addr=htonl(INADDR_ANY);//IP,或者用ip.sin_addr.S_un.S_addr=i_addr(“...“);ip.sin_family=AF_I;//指定地址族ip.sin_port=htons();//端口//绑定套接字bind(sock,(SOCKADDR*)&ip,sizeof(SOCKADDR));charsendbuf;//发送数据charrecvbuf;//接受数据chartemp;//其他用处SOCKADDR_INclient;//用于接受客户端的地址信息intlen=sizeof(SOCKADDR);//长度while(true){//接受数据recvfrom(sock,recvbuf,,,(SOCKADDR*)&client,&len);if(strcmp(“out“,recvbuf)==){sendto(sock,“out“,sizeof(“out“)+,,(SOCKADDR*)&client,len);//地址在我们调用recvfrom已经得到了cout《《“客户端程序已经退出,聊天终止

  ⒉“;break;}sprintf(temp,“IP是%s的人说:%s“,i_ntoa(client.sin_addr),recvbuf);cout《《temp《《endl;cin.getline(sendbuf,);sendto(sock,sendbuf,sizeof(sendbuf)+,,(SOCKADDR*)&client,len);}closesocket(sock);WSACleanup();return;}----------------客户端程序:,创建套接字(socket)。,向服务器发送数据(sendto。,关闭套接字。#include《Winsock.h》//必须加载套接字的头文件,还必须在工程的链接处添加Ws_.lib#include《iostream.h》#include《stdio.h》intmain(){WORDwVersionRequested;WSADATAwsaData;interr;//请求套接字版本wVersionRequested=MAKEWORD(,);//用MAKEWORD宏请求.版本的Winsock库err=WSAStartup(wVersionRequested,&wsaData);//加载套字节,确定使用版本if(err!=){return;}if(LOBYTE(wsaData.wVersion)!=||HIBYTE(wsaData.wVersion)!=)//低字节和高字节是不是{WSACleanup();//终止对Winsock库的使用return;}//创建套接字SOCKETsock=socket(AF_I,SOCK_DGRAM,);//发送数据SOCKADDR_INfuwuqi;fuwuqi.sin_addr.S_un.S_addr=i_addr(“...“);fuwuqi.sin_family=AF_I;fuwuqi.sin_port=htons();charsendbuf;charrecvbuf;chartemp;intlen=sizeof(SOCKADDR);while(true){cout《《“请输入你要说的话

  ⒊“;cin.getline(sendbuf,);sendto(sock,sendbuf,sizeof(sendbuf)+,,(SOCKADDR*)&fuwuqi,len);recvfrom(sock,recvbuf,,,(SOCKADDR*)&fuwuqi,&len);if(strcmp(recvbuf,“out“)==){cout《《“程序退出

  ⒋“;break;}sprintf(temp,“服务器%s说:%s“,i_ntoa(fuwuqi.sin_addr),recvbuf);cout《《temp《《endl;}closesocket(sock);WSACleanup();}

您可能感兴趣的文章:

相关文章